Python 中的 Google 身份验证器实现 [英] Google Authenticator implementation in Python

查看:96
本文介绍了Python 中的 Google 身份验证器实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用可以使用 Google 身份验证器应用程序.

I am trying to use one-time passwords that can be generated using Google Authenticator application.

基本上,Google Authenticator 实现两种类型的密码:

Basically, Google Authenticator implements two types of passwords:

  • HOTP - 基于 HMAC 的一次性密码,这意味着每次调用都会更改密码,符合 RFC4226
  • TOTP - 基于时间的一次性密码,每 30 秒更改一次(据我所知).
  • HOTP - HMAC-based One-Time Password, which means the password is changed with each call, in compliance to RFC4226, and
  • TOTP - Time-based One-Time Password, which changes for every 30-seconds period (as far as I know).

Google Authenticator 也可在此处作为开源获得:code.google.com/p/谷歌身份验证器

Google Authenticator is also available as Open Source here: code.google.com/p/google-authenticator

我正在寻找现有的解决方案来生成 HOTP 和 TOTP 密码,但没有找到太多.我拥有的代码是以下负责生成 HOTP 的代码片段:

I was looking for existing solutions to generate HOTP and TOTP passwords, but did not find much. The code I have is the following snippet responsible for generating 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 中提供的密钥应用程序.

The problem I am facing is that the password I generate using the above code is not the same as generated using Google Authenticator app for Android. Even though I tried multiple intervals_no values (exactly first 10000, beginning with intervals_no = 0), with secret being equal to key provided within the GA app.

我的问题是:

  1. 我做错了什么?
  2. 如何在 Python 中生成 HOTP 和/或 TOTP?
  3. 是否有任何用于此的现有 Python 库?

总结:请给我任何有助于我在 Python 代码中实现 Google Authenticator 身份验证的线索.

To sum up: please give me any clues that will help me implement Google Authenticator authentication within my Python code.

推荐答案

我想悬赏我的问题,但我已经成功地创建了解决方案.我的问题似乎与 secret 密钥的错误值有关(它必须是 base64.b32decode() 函数的正确参数).

I wanted to set a bounty on my question, but I have succeeded in creating solution. My problem seemed to be connected with incorrect value of secret key (it must be correct parameter for base64.b32decode() function).

下面我发布了完整的工作解决方案,并解释了如何使用它.

Below I post full working solution with explanation on how to use it.

下面的代码就够了.我还将它作为名为 onetimepass 的单独模块上传到 GitHub(可在此处获得:https://github.com/tadeck/onetimepass).

The following code is enough. I have also uploaded it to GitHub as separate module called onetimepass (available here: 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 秒更改一次),
  • get_hotp_token() generates one-time token (that should invalidate after single use),
  • get_totp_token() generates token based on time (changed in 30-second intervals),

说到参数:

  • secret 是服务器(上述脚本)和客户端(Google Authenticator,通过在应用程序中将其作为密码提供)已知的秘密值,
  • intervals_no 是每次生成令牌后增加的数字(这可能应该在服务器上通过在过去最后一次成功检查后检查一些有限数量的整数来解决)
  • secret is a secret value known to server (the above script) and client (Google Authenticator, by providing it as password within application),
  • intervals_no is the number incremeneted after each generation of the token (this should be probably resolved on the server by checking some finite number of integers after last successful one checked in the past)
  1. Generate 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),情况似乎更糟.
  1. Generate secret (it must be correct parameter for base64.b32decode()) - preferably 16-char (no = signs), as it surely worked for both script and Google Authenticator.
  2. Use get_hotp_token() if you want one-time passwords invalidated after each use. In Google Authenticator this type of passwords i mentioned as based on the counter. For checking it on the server you will need to check several values of intervals_no (as you have no quarantee that user did not generate the pass between the requests for some reason), but not less than the last working intervals_no value (thus you should probably store it somewhere).
  3. Use get_totp_token(), if you want a token working in 30-second intervals. You have to make sure both systems have correct time set (meaning that they both generate the same Unix timestamp in any given moment in time).
  4. Make sure to protect yourself from brute-force attack. If time-based password is used, then trying 1000000 values in less than 30 seconds gives 100% chance of guessing the password. In case of HMAC-based passowrds (HOTPs) it seems to be even worse.

示例

当使用以下代码作为一次性基于 HMAC 的密码时:

Example

When using the following code for one-time HMAC-based password:

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 个字符的长度).

which is corresponding to the tokens generated by the Google Authenticator app (except if shorter than 6 signs, app adds zeros to the beginning to reach a length of 6 chars).

这篇关于Python 中的 Google 身份验证器实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆