OTP 全称叫One-timePassword,也称动态口令,是根据专门的算法每隔60秒生成一个与时间相关的、不可预测的随机数字组合,每个口令只能使用一次,每天可以产生43200个密码。
OTP有3中形式,分别为时间同步(TOTP),事件同步,挑战/应答。
下面就来简单介绍下TOTP。
TOTP -Time-based One-time Password Algorithm is an extension of the HMAC-based OneTime Password algorithm HOTP to support a time based moving factor(TOTP基于时间的一次性密码算法是支持时间作为动态因素基于HMAC一次性密码算法的扩展)。
HMAC -Hash-based Message Authentication Code。
相关文档:
RFC 4226 - HOTP: An HMAC-BasedOne-Time Password Algorithm
(http://tools.ietf.org/html/rfc4226)
RFC 6238 - TOTP: Time-Based One-TimePassword Algorithm
(http://tools.ietf.org/html/rfc6238)
原理图如下:
要求:
1) 令牌与服务器之间必须时钟同步;
2) 令牌与服务器之间必须共享密钥;
3) 令牌与服务器之间必须使用相同的时间步长
算法:
TOTP =Truncate(HMAC-SHA-1(K, (T - T0) / X))
1) K 共享密钥(令牌种子)
2) T 是一个整数,代表当前时间(以UTC时间为标准)
3) T0 是一个整数,代表一个时间点,一般为0
4) X 口令变化周期,单位为秒,30秒或者60秒
5) Truncate HAMC算法得出的位值数比较多,不方面输入,因此需要截断成一组不太长十进制数(例如6位数)
RFC 6238文档中有一个java语言示例程序,我这里写了一个python版本的,代码如下:
__author__ ='juxuan'
import hmac
import hashlib
import time
import datetime
class TOTP(object):
def __init__(self):
self.DIGITS_POWER = [1,10,100,1000,10000,100000,1000000,10000000,100000000 ];
def hmac_sha(self, key, msg,crypto):
myhmac = hmac.new(key,msg,crypto)
return myhmac.hexdigest()
def generateTOTP(self, key, msg,length, crypto):
hash = self.hmac_sha(key,msg, crypto)
bytes_hash = [ hash[i:i+2]foriinrange(0,len(hash),2) ]
offset = int(bytes_hash[len(bytes_hash)-1],16) & 0xf
binary = ((int(bytes_hash[offset],16) &0x7f) << 24) \
| ((int(bytes_hash[offset+1],16) &0xff) << 16) \
| ((int(bytes_hash[offset+2],16) &0xff) << 8) \
| (int(bytes_hash[offset+3],16) &0xff)
otp = binary % self.DIGITS_POWER[length]
result = str(otp)
while len(result) <length:
result = "0" + result
return result
if __name__ =="__main__":
#seed for HMAC_SHA1
seed_sha1 = "3132333435363738393031323334353637383930"
#seed forHMAC_SHA256
seed_sha256 = "3132333435363738393031323334353637383930"\
"313233343536373839303132"
#seed forHAMC_SHA512
seed_sha512 = "3132333435363738393031323334353637383930"\
"3132333435363738393031323334353637383930"\
"3132333435363738393031323334353637383930"\
"31323334"
totp = TOTP();
T0 = 0
X = 60
testTimes = [59L,1111111109L,1111111111L, 1234567890L,2000000000L,20000000000L]
for iinrange(len(testTimes)):
T = (testTimes[i] - T0) / X
steps = str(T).upper()
while len(steps) <16:
steps = "0" + steps
print "utcTime:"+datetime.datetime.strftime(datetime.datetime.utcfromtimestamp(testTimes[i]),"%Y-%m-%d%H:%M:%S")
print "steps :"+ steps
print "SHA :"+totp.generateTOTP(seed_sha1, steps, 6, hashlib.sha1)
print "SHA256:"+ totp.generateTOTP(seed_sha256, steps,6, hashlib.sha256)
print "SHA512:"+ totp.generateTOTP(seed_sha512, steps,6, hashlib.sha512)+"\n"
结果如下:
utcTime:1970-01-01 00:00:59
steps :0000000000000001
SHA :807215
SHA256 :496488
SHA512 :397631
utcTime:2005-03-18 01:58:29
steps :0000000037037036
SHA :650743
SHA256 :694729
SHA512 :774782
utcTime:2005-03-18 01:58:31
steps :0000000037037037
SHA :839043
SHA256 :239243
SHA512 :264185
utcTime:2009-02-13 23:31:30
steps :0000000041152263
SHA :403899
SHA256 :384578
SHA512 :383107
utcTime:2033-05-18 03:33:20
steps :0000000066666666
SHA :453673
SHA256 :246989
SHA512 :381445
utcTime:2603-10-11 11:33:20
steps :0000000666666666
SHA :452866
SHA256 :271026
SHA512 :442876