【转载】OTP原理及实现
原文链接:https://blog.csdn.net/LVXIANGAN/article/details/73775969
网银动态口令工作原理是什么?
原理
动态密码的密码其实不是随机的,而是由规律的。当下动态密码分为两类,时间性和事件性。何为时间性动态密码?该类令牌产出动态密码是以时间为参数的,而事件性一般以使用次数为参数的。我们以时间性动态为主要说明对象。整个验证的过程如下:
1.动态密码令牌产生动态密码 以时间和种子为参数,进行迭代,得出动态密码,这里的时间一般是秒数。每个时间性动态密码令牌中会内置一个时钟芯片。
2.服务器校验动态密码。 服务器读取系统时间加上种子,以相同的迭代方法得出动态密码,然后双方进行比对。
讲到这边,可能有所怀疑难道令牌的时间和服务器的时间一定会一致吗?我的答案肯定是不一致的。那怎么能检验的过去呢?原来很简单,服务器校验是是在一个时间区间里校验的,比如现在是12:00,服务器会生成11:55-12:05中所有的动态密码,然后和令牌产生的动态密码比对,这样不就解决了时间不一致的问题了。另外服务器会把令牌和服务器相差的时间记录下来,下次检验的会先把这个偏移值记录下来,以减少动态密码迭代次数,这样就完成了另外一个比较重要的功能,偏移值自动调整。
动态口令,又叫动态令牌、动态密码。它的主要原理是: 用户登录前,依据用户私人身份信息,并引入随机数产生随机变化的口令,使每次登录过程中传送的口令信息都不同,以提高登录过程中用户身份认证的安全性。
银行通常提供给用户两种动态口令: 一种是固定数量的动态口令,最常见的就是刮刮卡。用户每次根据银行提示,刮开卡上相应区域的涂层,即可获得一个口令。刮刮卡成本低廉,使用方法简单,因此很多银行采用这种方法,如工商银行; 另一种是硬件形式的动态口令,即电子令牌,它采用专用硬件,每次可以用自带的密码生成芯片得到一个当前可用的一次性动态密码,交通银行等就采用这种方式。一般来讲,每个客户端的电子令牌都有一个唯一的密钥,该密钥同时存放在服务器端,每次认证时令牌与服务器分别根据同样的密钥,同样的随机数和同样的算法计算出认证时的动态口令,从而确保口令的一致性和认证的成功。因每次认证时,随机数的参数不同,所以每次产生的动态口令也不同。每次计算时参数的随机性保证了每次口令不可预测,以保证系统安全。
这些随机数是怎样产生的呢?动态口令随机数分为以下几类。
1. 口令为一个单向的前后相关的序列,系统只记录第N个口令。用户用第N—1个口令登录时,系统用单向算法算出第N个口令与自己保存的第N个口令匹配,以判断用户的合法性。由于N是有限的,用户登录N次后必须重新初始化口令序列。
2. 时间同步: 以用户登录时间作为随机因素。这种方式对双方的时间准确度要求较高,一般采取以分钟为时间单位的折中办法。在这种动态口令中,对时间误差的容忍可达±1分钟。
3. 事件同步: 通过某一特定的事件次序及相同的种子值作为输入,使用相同的算法运算出一致的密码,其运算机理决定了其整个工作流程同时钟无关,不受时钟的影响。它节省了用户每次输入挑战信息的麻烦,但当用户的挑战序列与服务器产生偏差后,需要重新同步。
4. 挑战/应答: 也叫异步认证方式。它比时间/事件同步方式操作相对烦琐,实现相对复杂,一般用于对安全性要求更高的场合,比如登录网上银行等,需要附加认证的情形。当用户需要访问系统时,远程认证服务器根据用户的电子令牌资料产生一个随机的数字串,即“挑战码”,用户将该数字串输入到电子令牌中。电子令牌利用内置的种子密钥和算法计算出相应的应答数(通常也是一个数字串)。
5. 用户将该应答数输入系统。 系统根据所保存的该用户相应电子令牌信息(种子密钥和算法)计算出应答数,并与用户输入的应答数进行比较。如果两者相同,则认证通过。由于每个电子令牌的种子密钥不同,因此不同用户的电子令牌对同样的挑战数计算出应答数也并不相同。只有用户持有指定的电子令牌才能计算出正确的应答数以通过系统认证。从而可以保证该用户是持有指定电子令牌的合法用户。
由于口令每次都变化,即使得到密码也没用,而且这种动态口令由专用算法生成,随机性高,不太容易被破解。传统的木马程序即使窃取到用户个人信息,拿去登录银行网页,也已经过期。因此,动态口令极大地提高了用户身份认证的安全性。
动态口令(OTP,One-Time Password)又称一次性密码,是使用密码技术实现的在客户端和服务器之间通过共享秘密的一种认证技术,是一种强认证技术,是增强目前静态口令认证的一种非常方便技术手段,是一种重要的双因素认证技术,动态口令认证技术包括客户端用于生成口令产生器的,动态令牌,是一个硬件设备,和用于管理令牌及口令认证的后台动态口令认证系统组成。
一、OTP历史溯源
动态口令(OTP)有一个同名确不同翻译的前辈,一次性密码(OTP, One-Time Pad),也叫密电本,是一种应用于军事领域的谍报技术,即对通信信息使用预先约定的一次性密电本进行加密和解密,使用后的密电本部分丢弃不再使用,能够做到一次一密。如果看过一些国内的谍战电视剧可能会对在二战时期,日本轰炸重庆中的一个号称“独臂大盗”的日本间谍有印象的话,他同日军通电使用的就是一次性密码技术,使用诺贝尔获奖的小说《The Good Earth》进行谍报编码,最后是被称为美国密码之父的赫伯特·亚德利破获。而目前在安全强认证领域使用的OTP动态密码技术,源于最早由RSA公司于1986年开发的RSA SecureID产品,动态密码并不是一次性密码技术,而是动态一次性口令技术。目前,国际上动态口令OTP有2大主流算法,一个是RSA SecurID ,一个是OATH组织的OTP算法。如果在国内来说的话,另一个是国密的OTP密码算法。RSA SecurID使用AES对称算法,OATH使用HMAC算法,国密算法使用的国密SM1(对称)和SM3(HASH)算法。
二、OTP认证原理与同步方法
动态口令的基本认证原理是在认证双方共享密钥,也称种子密钥,并使用的同一个种子密钥对某一个事件计数、或时间值、或者是异步挑战数进行密码算法计算,使用的算法有对称算法、HASH、HMAC,之后比较计算值是否一致进行认证。可以做到一次一个动态口令,使用后作废,口令长度通常为6-8个数字,使用方便,与通常的静态口令认证方式类似,使用方便与系统集成好,因此OTP动态口令技术的应用非常普遍,可以应用于多种系统渠道使用,如:Web应用、手机应用、电话应用、ATM自助终端等。
动态口令的同步机制有3种,即时间型、事件型和挑战与应答型,目前应用最多的是时间型动态口令,挑战与应答型动态口令的应用也逐渐增多,并且动态口令逐渐变为多种同步类型复合的机制发展,如时间+挑战与应答型。
三、OTP与常用认证技术比较
目前在信息系统中使用的增强型认证技术包括:
1 USBKey: 申请PKI证书。
2 动态口令卡:打印好的密码刮刮卡。
3 动态短信:使用电信通道下发口令。
4 IC卡/SIM卡:内置与用户身份相关的信息。
5 生物特征:采用独一无二的生物特征来验证身份,如指纹。
6 动态令牌:动态口令生成器和认证系统。
不同方案比较如下:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
由上面的比较可以非常直观的看出,动态口令认证技术有着一定优势。
四、动态口令认证技术不足
动态口令认证技术没有第3方权威机构认证,如果业务应用系统安全策略不完善的情况下,可能会受到中间人攻击。如某某银行使用时间型动态令牌受到网络钓鱼攻击。建议在应用中完善安全使用策略,划清口令使用权限,加强交易系统流程控制,用以提高系统安全性。
附:OATH算法Java源代码:http://download.csdn.net/detail/goldboar/3932212
银行的动态口令令牌是什么原理?
有网银的少年们一般都收到过银行给的这样一个令牌,俗称动态口令,在支付的时候输入自己的密码和动态口令上的动态密码,就能完成验证,银行就相信你不是坏人了,今天我们来简述一下这个动态口令令牌是个什么原理。
PS:本篇阅读可能需要读者有一些密码学基础,预警一下。
RSA SecurID SID700
如图的RSA SecurID SID700是当前市面上流行使用的动态口令令牌,在笔者准备资料的过程中发现国内描写动态口令的野生博客有不少谬误,其中大多是对银行这一套认证机制结构的不了解,所以首先要强调的是:
在大众用户手中的动态口令令牌,并不使用任何对称或者非对称加密的算法,在整个银行的认证体系中,动态口令令牌只是一个一次性口令的产生器,在其中运行的主要计算仅包括时间因子的计算和散列值的计算。
动态口令算法又叫一次性口令算法,英文写作OTP(One-Time Password Algorithm),动态口令令牌使用的算法是OTP中的一类,TOTP(Time-Based One-Time Password Algorithm) — 时间同步型动态口令。
时间同步型动态口令产生口令的时候和时间有关系,我们可以通过其工作的原理图来看一下:
图示给出了动态口令的工作原理,突出了整个认证机制中的动态口令部分,我们可以清楚看到在最左边和最右边有完全相同的两个流程,这里分别代表了用户的令牌卡和银行服务器的验证机器做的工作。本文的重点就在这两个完全相同的流程上。
在用户从银行手中拿到动态口令令牌卡的时候,在令牌卡的内部已经存储了一份种子文件(即图中钥匙所代表的seed),这份种子文件在银行的服务器里保存的完全一样的一份,所以对于动态口令令牌来说,这种方式是share secret的。另外在令牌硬件上的设置中,假使有人打开了这个令牌卡,种子文件将会从令牌卡的内存上擦除(待考证)。
令牌卡中有了种子文件,并实现了TOTP算法,在预先设置的间隔时间里它就能不断产生不同的动态口令,并显示到屏幕上,而银行服务器上跟随时间做同样的计算,也会得到和令牌卡同样的口令,用作认证。
那么TOTP算法具体做了什么操作呢?在RFC6238中有详细的算法描述,这里也会做简单的叙述。
TOTP是来自 HOTP [RFC4226] 的变形,从统筹上看,他们都是将数据文件进行散列计算,只是HOTP的因子是事件因子,TOTP将因子换成了时间因子,具体的TOTP计算公式(其中的HMAC-SHA-256也可能是 HMAC-SHA-512):
TOTP = Truncate(HMAC-SHA-256(K,T))
其中: K 为这里的种子文件内容; T 为计算出来的时间因子
公式中的 HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。而公式中给出的哈希算法是 SHA-256,这种哈希算法目前并没有好的破解办法。
令牌卡中预先设置了要显示的口令长度,TOTP 中的 Truncate 操作剪切获得口令。
以上就是动态口令令牌卡的内部原理。
几点补充:
1、时间同步型动态口令对令牌卡和服务器的时间同步要求很高,时间误差会造成整个令牌的失灵,所以每一次用户成功使用令牌认证,服务器都会做相应的时间误差矫正。
2、种子文件的产生使用了一种AES-128 变形而来的算法, AES-128 也是目前顶尖级的对称加密技术。
3、目前从加密技术上以及数学理论上整个银行机制的认证系统基本无解。
4、欢迎勘误。
公司项目需求:为局域网以外的网站后台用户开发动态密保的功能。
在当前的现有设备下,最方便实现的就两种:1、通过短信获取动态密码登录;2、通过手机令牌来实现。
相关的博文:http://blog.csdn.net/goldboar/article/details/7065948
百度百科: http://baike.baidu.com/view/1505735.htm
otp从技术来分有三种形式, 时间同步、事件同步、挑战/应答。
项目采用:
https://code.google.com/p/androidtoken/ 实现TOTP动态口令登录
android token 该项目支持HOTP (事件令牌)和TOTP (时间令牌)规范
配置令牌支持:KeyUriFormat和QR码,以及手动创建;
项目实现:
我这里采用添加方便的qr码,也就是常见的二维码来实现用户通过手机来绑定一个token;
首先,需要有的就是服务器端和客户端都共有的一个seed。
private final static String NUM_CHAR = "0123456789";
private static int charLen = NUM_CHAR.length();
/**
* 根据系统时间获得指定位数的随机数
* @param randomNumberDigit 随机数的位数
* @return 获得的随机数
*/
public static String getRandomNumber(int randomNumberDigit) {
long seed = System.currentTimeMillis();// 获得系统时间,作为生成随机数的种子
StringBuffer sb = new StringBuffer();// 装载生成的随机数
Random random = new Random(seed);// 调用种子生成随机数
for (int i = 0; i < randomNumberDigit; i++) {
sb.append(NUM_CHAR.charAt(random.nextInt(charLen)));
}
return sb.toString();
}
通过http://www.oschina.net/p/jquery-qrcode-js可以很方便的生成二维码。
二维码的内容
otpauth://totp/oa?secret=63985989418859891633&period=60&digits=8(android 支持这个协议,能直接扫描读取,添加一个token)
secret:密钥,也就是上面生成的seed;period:每60秒生成一次;digits:生成的随机码长度。
通过动态口令验证以后,服务器端也保存上seed;需要登陆的时候,服务器端生成动态口令和手机的来次对比就行了。
服务器端生成动态密码的方法:
/**
* 每60秒生成1个8位动态密码
*
* @param seed
* @return
*/
public static String getTOTP(String seed) {
long T0 = 0;
long X = 60;
Calendar cal = Calendar.getInstance();
long time = cal.getTimeInMillis() / 1000;
String steps = "0";
try {
long T = (time - T0) / X;
steps = Long.toHexString(T).toUpperCase();
while (steps.length() < 16)
steps = "0" + steps;
return generateTOTP(seed, steps, "8", "HmacSHA1");
} catch (final Exception e) {
System.out.println("Error : " + e);
return "生成动态口令失败";
}
}
/**
* This method generates a TOTP value for the given set of parameters.
*
* @param key
* : the shared secret, HEX encoded
* @param time
* : a value that reflects a time
* @param returnDigits
* : number of digits to return
* @param crypto
* : the crypto function to use
*
* @return: a numeric String in base 10 that includes
* {@link truncationDigits} digits
*/
public static String generateTOTP(String key, String time,
String returnDigits, String crypto) {
int codeDigits = Integer.decode(returnDigits).intValue();
String result = null;
// Using the counter
// First 8 bytes are for the movingFactor
// Compliant with base RFC 4226 (HOTP)
while (time.length() < 16)
time = "0" + time;
// Get the HEX in a Byte[]
byte[] msg = hexStr2Bytes(time);
byte[] k = hexStr2Bytes(key);
byte[] hash = hmac_sha(crypto, k, msg);
// put selected bytes into result int
int offset = hash[hash.length - 1] & 0xf;
int binary = ((hash[offset] & 0x7f) << 24)
| ((hash[offset + 1] & 0xff) << 16)
| ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
int otp = binary % DIGITS_POWER[codeDigits];
result = Integer.toString(otp);
while (result.length() < codeDigits) {
result = "0" + result;
}
return result;
}