Parsing Google Authenticator export QR codes

We recently added support for scanning the new Google Authenticator export QR codes to Aegis Authenticator. The single token URI format is well-documented, but the format of the QR codes displayed in the new export feature of Google Authenticator is not. It’s not immediately obvious how the format works without doing some reverse engineering, so I figured I’d briefly explain it in a blog post.

The QR codes contain a URI with the following format: otpauth-migration://offline?data=... The scheme is otpauth-migration, the host is offline and there is a data query parameter. The data parameter is a base64 encoded Protobuf message with the following format:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
syntax = "proto3";

message MigrationPayload {
  enum Algorithm {
    ALGO_INVALID = 0;
    ALGO_SHA1 = 1;
  }

  enum OtpType {
    OTP_INVALID = 0;
    OTP_HOTP = 1;
    OTP_TOTP = 2;
  }

  message OtpParameters {
    bytes secret = 1;
    string name = 2;
    string issuer = 3;
    Algorithm algorithm = 4;
    int32 digits = 5;
    OtpType type = 6;
    int64 counter = 7;
  }

  repeated OtpParameters otp_parameters = 1;
  int32 version = 2;
  int32 batch_size = 3;
  int32 batch_index = 4;
  int32 batch_id = 5;
}

The Protobuf message contains a list of OtpParameters. If you’ve worked with HOTP/TOTP before, the fields in OtpParameters should be obvious, so I won’t explain them here. If there are more than a few entries to export from Google Authenticator, they will be split up into multiple QR codes. The batch_size and batch_index fields indicate the number of QR codes and the index of this QR code, respectively. The batch_id is a unique identifier for the export attempt.

I’m not 100% sure if the types of the fields are exactly correct, as I don’t have access to the Protobuf message definition file of Google Authenticator, but they seem to match up well enough.