Google Authenticator TOTP原理和代码示例

Google Authenticator TOTP原理和代码示例

这篇文章主要介绍了Google Authenticator TOTP的原理以及使用代码示例,具有一定借鉴价值,需要的朋友可以参考下。

话不多说,一起往下看吧。

一、 原理详解(点击图片然后放大查看)
Google Authenticator TOTP原理和代码示例

二、  验证
1、下载Google谷歌身份验证器。
2、通过Python 的qrcode和pyotp模块生成二维码。
Google Authenticator TOTP原理和代码示例

3、然后使用下载的谷歌身份验证器扫描生成的二维码

如果没有谷歌服务,则选择输入秘钥,在账户明处填入name参数,在秘钥处填入Secret即可。

4、对比手机上谷歌验证器显示的6位动态码,你会发现,代码计算处的6位动态码是一致的

三、 源码

1、计算Google Authenticator 6位动态码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Google Authenticator工作原理 TOTP(Time-Based One-Time Password)

import hmac
import hashlib
import base64
import struct
import time

# setup 1 : base32 secret
# 提示:Secret的长度最好不要超过32
Secret = 'userxiaosheng'

# Secret += '=' * (8-len(Secret)%8) # py3中base64模块要求字符串必须为8的倍数,不足部分使用 = 补全
# 在查阅相关资料时,发现解决【可以将Key进行b3decode】的代码都是这样写的(或者类似).
# 但是在生产环境中,为了给每个用户生成不一样的Key,我们必须通过各种算法,生成一个和用户有关的字符串作为Key使用,
# 如果你使用的是 Secret += '=' * (8-len(Secret)%8) 这种方式解决b32decode问题,那么当Key中有数字时,
# b32decode将会报错:binascii.Error: Non-base32 digit found,
# 通过测试,我找到了一段代替Secret += '=' * (8-len(Secret)%8)的代码,所以在我这篇文章中,
# 将会使用Secret = base64.b32encode(s=Secret.encode('utf-8'))来代替类似Secret += '=' * (8-len(Secret)%8) 的代码.

Secret = base64.b32encode(s=Secret.encode('utf-8'))
K = base64.b32decode(Secret,True)

# setup 2 : get current timestamp
# int(time.time()) // 30  到当前经历了多少个30秒
C = struct.pack(">Q", int(time.time()) // 30)   # 将间隔时间转为big-endian(大端序)并且为长整型的字节

# setup 3 : start hmac-sha1
# hmac = SHA1(secret + SHA1(secret + input))
H = hmac.new(K,C,hashlib.sha1).digest() # 使用hmac sha1加密,并且以字节的方式取出 = b'\x0f\x1a\xaeL\x0c\x8e\x19g\x8dv}\xde7\xbc\x95\xeal\xa3\xc1\xee'
O = H[19] & 15  # bin(15)=00001111=0b1111

DynamicPasswd = str((struct.unpack(">I", H[O:O+4])[0] & 0x7fffffff) % 1000000)
# struct.unpack('>I',h[o:o+4])[0]   -- 转为big-endian(大端序)并且不为负数的数字(整数),因为转换完是一个数组,类似"(2828101188,)",所以需要[0]取出
# h[o:o+4]  --  取其中4个字节  o=10  则取索引分别为 10,11,12,13的字节
# & 0x7fffffff = 11111111  --  与字节转换的数字做与运算
# % 1000000  --  得出的数字与1000000相除然后取余

TOTP = str(0) + str(DynamicPasswd) if len(DynamicPasswd) < 6 else DynamicPasswd
# passwd = passwd if len(passwd) < 6 else str(0) + str(passwd)
# 如果最后得出的6位数字,首位0,可能会只输出5位数字,所以这里进行一个判断,如果是5位则加上首位的0
print(TOTP)

2、生成二维码

import pyotp
from qrcode import QRCode
from qrcode import constants

Secret = 'userxiaosheng'
Secret = base64.b32encode(s=Secret.encode('utf-8'))
Content = pyotp.totp.TOTP(Secret).provisioning_uri(name='xiaosheng', issuer_name="Verfiy Code")
# 在真实环境中,name的参数应该是和Secret有关联的,这样我们才能为每个不同的用户分别计算动态验证码.

qr = QRCode(version=1,
            error_correction=constants.ERROR_CORRECT_L,
            box_size=6,
            border=4,)

qr.add_data(Content)
qr.make(fit=True)
img = qr.make_image()
img.save('./GoogleQR.png')

关于Google Authenticator TOTP的原理以及使用代码示例就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果喜欢这篇文章,不如把它分享出去让更多的人看到。