dim13 / otpauth

Google Authenticator migration decoder

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Migration Payload.batch_id should be int32

tc287 opened this issue · comments

commented

a2c0a3f changes a bunch of protobuf fields from int32 to uint32; I assume this was in due to the discussion around google/google-authenticator-android#118 (comment) (batch_id sometimes being negative).

I believe this is incorrect! After figuring out how to generate batched migration codes (an Android-only feature), the first batch_id I see is 18446744073509271282 (0xfffffffff40ff6f2), which indicates that the type is a negative int32 ("if you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes long"). This shows up as "%2F%2F%2F%2F" in the otpauth-migration URL, making it easy to spot.

(I agree that uint32 would have been a more sensible type, but it is not the type they used.)

If you want to dig deeper, you can look at the generated code's dynamicMethod(): For BUILD_MESSAGE_INFO, it returns a RawMessageInfo which encodes a bunch more information from the source proto (including the "FieldType"). But given that batch_id is int32, it seems reasonable to assume that integer fields are int32 by default.

You may be right, but I could not deduce it with certainly now.

Here are encoded message info definitions. I see some patterns here, but I'm not quite sure, how to decode 'em:

Main Payload message:

01 05 00 01 01 05 05 00 01 00
01 1b          # otpParameters_
02 e1 80 84 00 # version_ (u?int32) → 4: int32
03 e1 80 84 01 # batchSize_ (u?int32) → 4: int32
04 e1 80 84 02 # batchIndex_ (u?int32) → 4: int32
05 e1 80 84 03 # batchId_ (u?int32) → 4: int32

And embedded OtpParams message:

01 07 00 01 01 07 07 00 00 00
01 e1 80 8a 00 # secret_ (bytes)
02 e1 80 88 01 # name_ (string)
03 e1 80 88 02 # issuer_ (string)
04 e1 80 8c 03 # algorithm_ (enum)
05 e1 80 8c 04 # digits_ (enum)
06 e1 80 8c 05 # type_ (enum)
07 e1 80 83 06 # counter_ (u?int64) → 3: uint64

Would love to hear, if you know more.

commented

The encoding is described in RawMessageInfo.java and encodes integers using 1-3 UTF-16 "chars". Fortunately, most numbers are small enough to be encoded in a single char, so the only thing you need to worry about is U+0000 encoding as c0 80 due to "modified UTF-8" (depending on the tool you use to view the strings).

In the above, e1 80 84 represents 0x1004, e1 80 83 represents 0x1003, etc. This is the "field type with extra bits"; the lower 8 bits are the field type from FieldType.java: 4 is int32, 3 is uint64, 8 is string, 0xA (10) is bytes, 0xC (12) is enum.

Thanks! That helped.