TOTP

本文主要介绍基于时间的一次性密码生成算法 TOTP,它由 RFC 6238 定义。和基于事件的一次性密码生成算法不同 HOTP,TOTP 是基于时间的,它和 HOTP 具有如下关系:

TOTP = HOTP(K, T)

HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

其中:

  • T:T = (Current Unix time - T0) / X, T0 = 0,X = 30
  • K:客户端和服务端的共享密钥,不同的客户端的密钥各不相同。
  • HOTP:该算法请参考 RFC,也可参考博文 理解 HMAC-Based One-Time Password Algorithm

例如:

>>> import datatime
>>> import time
>>>
>>> current_time = datetime.datetime.now()
>>> print current_time
2016-04-16 22:11:38.508616
>>> time.mktime(current_time.timetuple())
1460815898.0  # Current Unix Time

当前时间为 2016-04-16 22:11:38.508616 的 Unix Time 为 1460815898.0,所以 T 为:

T = (1460815898.0 - 0) / 30 = 48693863

对于 HOTP,客户端和服务端需要同步移动因子 C;而对于 TOTP,只需客户端和服务器端采用相同的时区,不存在同步的问题,提高了便利性和通用性。


Python Demo

import hashlib
import hmac


def get_hotp_passcode(secret, count):
    data = bytearray([int(hex(count >> i & 0xff), 16) for i in (56, 48, 40, 32 ,24, 16, 8, 0)])
    hs = hmac.new(secret, data, hashlib.sha1).hexdigest()
    offset = int(hs[-1], 16)
    sbits = int(hs[offset * 2: offset * 2 + 8], 16) & 0x7fffffff
    return sbits % 1000000


def get_totp_passcode(secret, unix_time):
    return get_totp_passcode(secret, int(unix_time) / 30)