Skip to content

Instantly share code, notes, and snippets.

Created December 22, 2020 06:21
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
Parse seeds out of Google Authenticator migration QR codes
# Scan the Google Authenticator export QR code to get a otpauth-migration:// URI
# Then, provide that URL here and get your precious seeds back.
# The last components on each line of output are the 80-bit TOTP conforming seeds Authenticator uses, e.g.
# Output looks like this
# Some Service 1 (Andres) - JBUSYICBNZSHEZLT
# Some Service 2 (Kevin) - JZXXIICTN4QEEYLE
from urllib.parse import unquote
def consume(b: bytes):
l = b[0]
return b[1:l+1], b[l+2:]
uri = 'otpauth-migration://offline?data=CioKCkhpLCBBbmRyZXMSBkFuZHJlcxoOU29tZSBTZXJ2aWNlIDEgASgBMAIKKQoKTm90IFNvIEJhZBIFS2V2aW4aDlNvbWUgU2VydmljZSAyIAEoATACEAE%3D'
data = base64.b64decode(unquote(uri.split('=')[1]))
while len(data) > 3:
data = data[3:] # Nothing to see here
seed, data = consume(data)
account, data = consume(data)
service, data = consume(data)
print('{} ({}) - {}'.format(service.decode(), account.decode(), base64.b32encode(seed).decode()))
data = data[5:] # Nothing to see here
Copy link

For anyone else who came across this first like I did, please allow me to point you in this direction:

Learning a lot about protobuf helped a lot with this.

Copy link

klustic commented Mar 26, 2023

This is much cleaner, thanks for the link!

Copy link

arzcbnh commented Sep 13, 2023

Thank you, it worked perfectly! I just had to add import base64 after line 8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment