Detailed explanation of the principle of Google Authenticator TOTP (take Python as an example)

Keywords: Web Development Google QRCode SHA1 Python

Xiaosheng blog: http://xsboke.blog.51cto.com

If in doubt, please Click here The author will reply in time (or comment directly in the current article).

                        -------Thank you for your reference. If you have any questions, welcome to exchange

I. detailed explanation of the principle (click and zoom in the picture)

II. Verification
1. Download Google authentication.
2. The QR code is generated by the qrcode and pyotp modules of Python.

3. Then scan the generated QR code with the downloaded Google authenticator

If there is no Google service, select to enter the Secret key, fill in the name parameter in the account window, and fill in the Secret in the Secret key.

4. Compare the 6-digit dynamic code displayed by Google verifier on the mobile phone, and you will find that it is consistent with the 6-digit dynamic code in the code calculation in [principle details]

Source code

1. Calculate Google Authenticator 6-bit dynamic code

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# How Google Authenticator works TOTP (time based one time password)

import hmac
import hashlib
import base64
import struct
import time
import pyotp

# setup 1 : base32 secret
Secret = 'userxiaosheng'
Secret += '=' * (8-len(Secret)%8) # The base64 module in py3 requires that the string must be a multiple of 8, and the insufficient part uses = complement
K = base64.b32decode(Secret,True)

# setup 2 : get current timestamp
# Int (time. Time()) / / how many 30 seconds have passed since 30
C = struct.pack(">Q", int(time.time()) // 30) bytes with big endian interval and long integer

# setup 3 : start hmac-sha1
# hmac = SHA1(secret + SHA1(secret + input))
H = hmac.new(K,C,hashlib.sha1).digest() # Use hmac sha1 encryption, and fetch = b'\x0f\x1a\xaeL\x0c\x8e\x19g\x8dv}\xde7\xbc\x95\xeal\xa3\xc1\xee' in bytes
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] -- a number (integer) converted to big endian and not negative, because the conversion is an array, similar to "(2828101188,)", so it needs to be taken out by [0]
# h[o:o+4] - if four bytes are taken, o=10, then the index is 10, 11, 12, 13 bytes respectively
# &0x7fffffff = 11111111 -- do and operate with the number of byte conversion
# %1000000 -- divide the resulting number by 1000000 and then take the remainder

TOTP = str(0) + str(DynamicPasswd) if len(DynamicPasswd) < 6 else DynamicPasswd
# passwd = passwd if len(passwd) < 6 else str(0) + str(passwd)
# If the final 6 digits, the first 0, may only output 5 digits, so here we make a judgment, if it is 5 digits, then add the first 0
print(TOTP)

2. Generate QR code

from qrcode import QRCode
from qrcode import constants

Content = pyotp.totp.TOTP(Secret).provisioning_uri(name='xiaosheng', issuer_name="Verfiy Code")
# In the real environment, the name parameter should be associated with Secret, so that we can calculate the dynamic verification code for each different user

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')

Posted by aurigus on Sat, 30 Nov 2019 10:23:35 -0800