Skip to main content

Google TOTP decode and self-generate

Pre-requirements

  • An ubuntu system
    • with python3 supports
    • with python3-pip
    • with package installer, likes apt

Step1. Export TOTP

Export your TOTP from Google Authenticator by using "Transfer Codes". Take a screenshot of the generated QR-Code.

Step 2. Decode the exportsexport

Step 2-1. Decode QR-code

  • Install dependencies

    sudo apt install -y libzbar0 protobuf-compiler
    
    pip install pyzbar pillow
    

Write the protobuf created by Google

cat > migration.proto <<'EOF'
syntax = "proto3";

message MigrationPayload {
  repeated OTPParameters otp_parameters = 1;
}

message OTPParameters {
  bytes secret = 1;
  string name = 2;
  string issuer = 3;
  Algorithm algorithm = 4;
  DigitCount digits = 5;
  OTPType type = 6;
  int64 counter = 7;
}

enum Algorithm {
  ALGORITHM_UNSPECIFIED = 0;
  SHA1 = 1;
  SHA256 = 2;
  SHA512 = 3;
}
EOF
protoc --python_out=. migration.proto
# File migration_pb2.py is generated

Run the script

import base64
import migration_pb2
import pickle
from pyzbar.pyzbar import decode
from PIL import Image
from urllib.parse import unquote


img = Image.open('google_auth.jpg')

decoded_objects = decode(img)

if len(decoded_objects) == 0:
    print('No decoded object from given QRCode')
    exit()

migrations = [datum
                for obj in decoded_objects:decoded_objects
                print('Type:',if obj.type)type print(== 'Data:',QRCODE' and 
                    (datum := unquote(obj.data.decode('utf-8'))) and
                    datum.startswith('otpauth-migration://')]

if len(migrations) == 0:
    print('No valid migration extracted from given QRCode')
    exit()

prots = [base64.b64decode(migration.replace('otpauth-migration://offline?data=', '\n'', 1))
            for migration in migrations]

if len(prots) == 0:
    print('No correctly-formed migration extracted from given QRCode')
    exit()

totps = []

payload = migration_pb2.MigrationPayload()
payload.ParseFromString(prots[0])

for otp in payload.otp_parameters:
    totps.append({
        "issuer": otp.issuer,
        "name": otp.name,
        "secret": otp.secret,
    })

with open('google_auth.bin', 'wb') as fout:
    pickle.dump(totps, fout)

The script outputoutput, the decoded data, should be saved in file google_auth.bin

Step 3. Generate the TOTP codes

    You only need google_auth.bin and following python script to re-generate TOTP codes
    Type:import QRCODEhmac
    Data:import otpauth-migration:hashlib
    import pickle
    import struct
    import time
    
    
    def gen_totp_code(secret, digits=6, period=30, algo=hashlib.sha1):
        counter = int(time.time() //offline?data= period)
        msg = struct.pack(">Q", counter)
        h = hmac.new(secret, msg, algo).digest()
        offset = h[-1] & 0x0F
        code = struct.unpack(">I", h[offset:offset+4])[0] & 0x7fffffff
        return str(code % (10 ** digits))..zfill(digits)
    
    def load_totp_raws():
        with open('google_auth.bin', 'rb') as fin:
            return pickle.load(fin)
    
    for otp in load_totp_raws():
        print(otp['issuer'])
        print(otp['name'])
        print(gen_totp_code(otp['secret']))
        print()
    

    Just save the string after data paramater

    Step 2-2. Decode URL