首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Google Authenticator

Google Authenticator

作者头像
py3study
发布2020-01-08 11:31:14
1.7K0
发布2020-01-08 11:31:14
举报
文章被收录于专栏:python3python3

一、 原理详解(点击图片然后放大查看)

Google Authenticator TOTP原理详解(以Python为例)
Google Authenticator TOTP原理详解(以Python为例)

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

Google Authenticator TOTP原理详解(以Python为例)
Google Authenticator TOTP原理详解(以Python为例)

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')
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-09-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
多因子身份认证
多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档