当前位置: 首页 > 面试题库 >

Google Authenticator在Python中的实现

任繁
2023-03-14
问题内容

我正在尝试使用可以通过Google
Authenticator应用程序
生成的一次性密码。

Google身份验证器的功能

基本上,Google身份验证器实现两种类型的密码:

  • HOTP- 基于HMAC的一次性密码,这意味着密码会随RFC4226的每次调用而更改,并且
  • TOTP- 基于时间的一次性密码,每30秒更改一次(据我所知)。

Google身份验证器也可以在此处作为开源使用:code.google.com/p/google-
authenticator

当前代码

我一直在寻找用于生成HOTP和TOTP密码的现有解决方案,但没有找到太多。我拥有的代码是负责生成HOTP的以下代码段:

import hmac, base64, struct, hashlib, time

def get_token(secret, digest_mode=hashlib.sha1, intervals_no=None):
    if intervals_no == None:
        intervals_no = int(time.time()) // 30
    key = base64.b32decode(secret)
    msg = struct.pack(">Q", intervals_no)
    h = hmac.new(key, msg, digest_mode).digest()
    o = ord(h[19]) & 15
    h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
    return h

我面临的问题是,使用上述代码生成的密码与使用Android的Google
Authenticator应用生成的密码不同。即使我尝试了多个intervals_no值(以开头,刚好是10000 intervals_no = 0),但secret都等于GA应用程序中提供的键。

我有问题

我的问题是:

  1. 我究竟做错了什么?
  2. 如何在Python中生成HOTP和/或TOTP?
  3. 有没有现成的Python库?

总结一下:请给我提供任何线索,这些线索将有助于我在Python代码中实现Google Authenticator身份验证。


问题答案:

我想悬赏我的问题,但是我成功地找到了解决方案。我的问题似乎与错误的secret键值有关(它必须是base64.b32decode()功能的正确参数)。

下面,我发布完整的工作解决方案,并说明如何使用它。

以下代码就足够了。我也将它作为名为 onetimepass的 单独模块上传到了GitHub
(可在此处找到:https :
//github.com/tadeck/onetimepass)。

import hmac, base64, struct, hashlib, time

def get_hotp_token(secret, intervals_no):
    key = base64.b32decode(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 h

def 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 是每代令牌生成后增加的数字(可能应该在服务器上通过检查过去一次成功的整数之后检查一些有限数量的整数来解决)

如何使用它

  1. 生成secret(必须是的正确参数base64.b32decode())-最好为16个字符(无=符号),因为它肯定适用于脚本和Google身份验证器。
  2. 使用get_hotp_token(),如果你想在每次使用后无效一次性密码。在Google Authenticator中,我提到了这种基于计数器的密码。为了在服务器上检查它,您将需要检查多个值intervals_no(因为您没有隔离该用户由于某种原因未在请求之间生成传递的密码),但不能小于最后一个工作intervals_no值(因此您可能应该存储它)某处)。
  3. get_totp_token()如果您希望令牌以30秒的间隔工作,请使用。您必须确保两个系统都设置了正确的时间(这意味着它们在任何给定的时间点都生成相同的Unix时间戳)。
  4. 确保保护自己免受暴力攻击。如果使用了基于时间的密码,则在不到30秒的时间内尝试输入1000000个值将有100%的机会猜测密码。在基于HMAC的密码(HOTP)的情况下,情况甚至更糟。

将以下代码用于基于HMAC的一次性密码时:

secret = 'MZXW633PN5XW6MZX'
for i in xrange(1, 10):
    print i, get_hotp_token(secret, intervals_no=i)

您将得到以下结果:

1 448400
2 656122
3 457125
4 35022
5 401553
6 581333
7 16329
8 529359
9 171710

对应于Google Authenticator应用生成的令牌(除非少于6个符号,应用会在开头添加零,以达到6个字符的长度)。



 类似资料:
  • 问题内容: 我找到了它并以它为基础,但它开箱即用时却无法正常工作。我的目标也是将其视为程序包而不是命令行实用程序,因此我的代码更改将反映出来。 当我向设备发送基本命令时,它将返回以下内容。 我的代码读取第一行,但是随后出现错误消息,表明连接暂时不可用,并且没有获得第二行。如果我将其更改为阻塞,它只会阻塞并且永远不会返回。有什么想法吗? 问题答案: 如果您只使用它是否有效? 我认为您应该尝试一些更简

  • 上面是我在Python中的Gauss-Seidel方法。由于某种原因,即使在矩阵A是严格对角占优的情况下,即使在50000次迭代后,它也不收敛。下面是在MATLAB中工作的相同实现: 我犯了什么错误?我认为它是在TriSolve方法中,因为如果我用常规的LU求解器(如np.linalg.solve)替换它,它就能工作。为什么三角解的行为不像这里想要的那样?

  • 本文向大家介绍在python shell中运行python文件的实现,包括了在python shell中运行python文件的实现的使用技巧和注意事项,需要的朋友参考一下 最近在学习flask开发,写好程序后需要在python shell中运行测试功能。专门抽时间研究了下,总结以防止以后遗忘。 这是测试文件的结构,python_example主文件夹,下面有example.py和一个subexam

  • 问题内容: 我正在尝试使用网站的OAuth,该网站要求签名方法仅是“ HMAC-SHA1”。 我想知道如何在Python中实现此功能? 问题答案: 假单胞菌: 签名错误通常驻留在基本字符串中,请确保您理解这一点(如OAuth1.0规范在此处所述:http://tools.ietf.org/html/draft-hammer- oauth-10#section-3.4 。 1)。 以下输入用于生成签

  • 本文向大家介绍在Python中实现导入(importlib),包括了在Python中实现导入(importlib)的使用技巧和注意事项,需要的朋友参考一下 importlib软件包提供了可移植到任何Python解释器的Python源代码中import语句的实现。这也提供了比用Python以外的其他编程语言实现的实现更容易理解的实现。 该软件包还公开了实现导入的组件,使用户可以更轻松地创建自己的自定

  • 问题内容: 我以前的编程中,代码段仅用于调试目的(记录命令等)。通过使用预处理程序指令,可以完全禁用这些语句以进行生产,如下所示: 做类似的事情的最好方法是什么? 问题答案: 如果只想禁用日志记录方法,请使用该模块。如果日志级别设置为排除调试语句,那么它将非常接近无操作(它仅检查日志级别并返回而不插入日志字符串)。 如果要在特定条件下以字节码编译时实际删除代码块,则唯一的选择是相当神秘的全局变量。