我想悬赏我的问题,但是我成功地找到了解决方案。我的问题似乎与错误的
secret键值有关(它必须是
base64.b32depre()功能的正确参数)。
下面,我发布完整的工作解决方案,并说明如何使用它。
码
以下代码就足够了。我也将它作为名为 onetimepass的 单独模块上传到了GitHub
(可在此处找到:https :
//github.com/tadeck/onetimepass)。
import hmac, base64, struct, hashlib, timedef get_hotp_token(secret, intervals_no): key = base64.b32depre(secret, True) msg = struct.pack(">Q", intervals_no) h = hmac.new(key, msg, hashlib.sha1).digest() o = ord(h[19]) & 15 h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000 return hdef get_totp_token(secret): return get_hotp_token(secret, intervals_no=int(time.time())//30)它具有两个功能:
get_hotp_token()
生成一次性令牌(单次使用后应失效),get_totp_token()
根据时间生成令牌(每30秒更改一次),
参量
关于参数:
secret
是服务器(上述脚本)和客户端(Google身份验证器,通过在应用程序中将其作为密码提供)已知的秘密值,intervals_no
是每代令牌生成后增加的数字(可能应该在服务器上通过检查过去一次成功的整数之后检查一些有限数量的整数来解决)
如何使用它
- 生成
secret
(必须是的正确参数base64.b32depre()
)-最好为16个字符(无=
符号),因为它肯定适用于脚本和Google身份验证器。 - 使用
get_hotp_token()
,如果你想在每次使用后无效一次性密码。在Google Authenticator中,我提到了这种基于计数器的密码。为了在服务器上检查它,您将需要检查多个值intervals_no
(因为您没有隔离该用户由于某种原因未在请求之间生成传递的密码),但不能小于最后一个工作intervals_no
值(因此您可能应该存储它)某处)。 get_totp_token()
如果您希望令牌以30秒的间隔工作,请使用。您必须确保两个系统都设置了正确的时间(这意味着它们在任何给定的时间点都生成相同的Unix时间戳)。- 确保保护自己免受暴力攻击。如果使用了基于时间的密码,则在不到30秒的时间内尝试输入1000000个值将有100%的机会猜测密码。在基于HMAC的密码(HOTP)的情况下,情况甚至更糟。
例
将以下代码用于基于HMAC的一次性密码时:
secret = 'MZXW633PN5XW6MZX'for i in xrange(1, 10): print i, get_hotp_token(secret, intervals_no=i)
您将得到以下结果:
1 4484002 6561223 4571254 350225 4015536 5813337 163298 5293599 171710
对应于Google Authenticator应用生成的令牌(除非少于6个符号,应用会在开头添加零,以达到6个字符的长度)。



