/otp_export

Google Authenticator export format

Primary LanguagePython

Google Authenticator export format

A recent update of the Google Authenticator app on Android brought an export/import feature. This enables users to copy their 2FA codes to a new device.

The format of the export seems to not be publicly documented (yet?). I believe that this export function is quite interesting and would like to see innovative solutions for back-up or interopability between devices. It would also be in the general public's interest if there would be a single import/export format for 2FA codes and this one looks promising to me.

This repo contains my interpretation of the export data. I hope this enables other developers to come up with new cool solutions that use the exported secrets.

** NOTE THAT THE 2FA CODES ARE SECRETS THAT YOU SHOULD TREAT AS SUCH! **

An interesting blog about the update was published at Ctrl blog.

Encapsulation

The layers of data in the export are:

Protocol Buffers

A reconstructed definition of the protobuf file is included in the repo.

Bash example

With some regular bash tools and protoc you can extract the data like this:

$ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
$ urldecode '<DATA VALUE>' | base64 -d | protoc --decode_raw

1 {
  1: "\r\037)\335\260l\377\216=\0352O+\352\221.o\177\014e\030\217\352NM~V\322\322 \320\351@\314C"
  2: "Demo Issuer:Demo Account"
  4: 1
  5: 1
  6: 2
}
2: 1
3: 1
4: 0
5: 1045125660

Note however that this is just raw decoding the protoc buffer and will show field IDs without assigning names. You'll have to lookup the meaning of each field in the Format description.

Alternatively use the provided OtpMigration.proto and instruct protoc to decode a MigrationPayload:

$ urldecode '<DATA VALUE>' | base64 -d | protoc --decode=MigrationPayload OtpMigration.proto

otp_parameters {
  secret: "\r\037)\335\260l\377\216=\0352O+\352\221.o\177\014e\030\217\352NM~V\322\322 \320\351@\314C"
  name: "Demo Issuer:Demo Account"
  algorithm: SHA1
  digits: SIX
  type: TOTP
}
version: 1
batch_size: 1
batch_index: 0
batch_id: 1045125660

Python example

parse.py contains a sample python script that parses an otpauth-migration URL. The OtpMigration_pb2.py is generated with protoc --python_out=. OtpMigration.proto.

$ pip install -r requirements.txt
$ ./parse.py '<OTP URL>'

version: 1
batch_size: 1
batch_index: 0
batch_id: 1045125660
otp_parameters:
  secret: b'BUPSTXNQNT7Y4PI5GJHSX2URFZXX6DDFDCH6UTSNPZLNFURA2DUUBTCD'
  name: Demo Issuer:Demo Account
  issuer: 
  algorithm: SHA1
  digits: SIX
  type: TOTP
  counter: 0

Python sample 2 - export to yubikey

Another sample I've included is export2yubikey.py. This script generates ykman commands to import the secrets into a yubikey.

$ ./export2yubikey.py '<OTP URL>'
ykman oath add -o TOTP -d 6 -s SHA1 -p 30 "example1" INWGK5TFOIQFS33VEFBHK5BAJZXSAU3FMNZGK5A=
ykman oath add -o TOTP -d 6 -s SHA1 -p 30 -i "some issuer" "example2" KN2G64BANF2CCTTPORUGS3THEBUGK4TF
...

Format description

See OtpMigration.proto.

MigrationPayload

message

ID Name Type
1 otp_parameters OtpParameters
2 version int32
3 batch_size int32
4 batch_index int32
5 batch_id int32

OtpParameters

message

ID Name Type
1 secret bytes
2 name string
3 issuer string
4 algorithm Algorithm
5 digits DigitCount
6 type OtpType
7 counter int64

Algorithm

enum

Value Name
0 ALGORITHM_TYPE_UNSPECIFIED
1 SHA1
2 SHA256
3 SHA512
4 MD5

DigitCount

enum

Value Name
0 DIGIT_COUNT_UNSPECIFIED
1 SIX
2 EIGHT

OtpType

enum

Value Name
0 OTP_TYPE_UNSPECIFIED
1 HOTP
2 TOTP