We've incorporated two factor authentication into one of our applications using Google Authenticator. In QA, something really weird turned up. While I managed to fix it, I'm not really sure why the fix works.
For our shared secret, we assigned a GUID to the user when they begin the TFA setup. The GUID gets base-32 encoded, and put into the URL that is converted to a QR code and scanned by the user with their phone:
otpauth://totp/myapp_user?secret=g5swmnddhbtggllbgi3dsljumi3tallbmuytgljtg5sdgnbxmy2dgyjwmy======
And all works well for all non-ios machines we have tried. On ios alone, it throws a really peculiar error when trying to scan the barcode most of the time:
Invalid barcode
The barcode '[same as above]' is not a valid authentication token barcode.
It meets Google/RFC 4226's minimum secret requirement (128 bits), is properly Base32 encoded, etc... Why does it fail? The typical reason for this message is whitespace in the url -- but there is none.
If I add a small seed to the beginning of the guid everything works just fine:
otpauth://totp/myapp_user?secret=nfygq33omvzxky3lom3ggmzyha2tgnjnmu4gezbngqzdgyrnhbtdqzrnmeywimrwmjsgknzymi3a
Essentially it's the difference between:
secret = enc.Encode32(Encoding.ASCII.GetBytes("iphonesucks" + Guid.NewGuid().ToString())); // Works
secret = enc.Encode(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString())); // Fails
newAuthUrl = string.Format("otpauth://totp/myapp_user?secret={0}", secret);
I've got two crazy theories on why this could possibly have worked:
The ios port requires more than 128 bits. My commentary/seed is enough to bump it over that limit, whatever that happens to be... except that I actually gave it more than 128 bits since it was a guid-as-string.
After Base32 decoding, the ios app recognizes the secret string as a guid and does something else with it.
I hate fixing a bug and not knowing why the fix worked. Can anyone explain this? Additional conspiracy theories on this topic are also welcome.
All you have to do is make sure your Google Authenticator app's time is synced correctly. Launch the app, tap the Menu button (three dots), and go to Settings > Time Correction for Codes > Sync now. You should find that your Authenticator codes work properly after this.
The Google Authenticator app can be used on an Android, iPhone, or Blackberry device.
When you set up an authenticator app with a website, that site generates a secret key - a random collection of numbers and symbols - which you then save to the app. The site usually shows you that key in the form of a QR code. When you scan that with the app, the key is then saved to your phone.
I was having the same issue as above. It turns out that Google Authenticator doesn't like = signs in the IPhone App, but doesn't complain in Android.
In my case I increased the length of the string before encoding to base32 from 8 chars to 10 chars. This removed the three === at the end of the string. I found this online as to why = signs appear in base32 encoded strings:
The pad character (=) does not have a binary representation in BASE32; it is inserted into the BASE32 text as a placeholder to maintain 40-bit alignment
In your case above the same happened when you added the salt. The second secret you pasted doesn't have ='s at the end.
Hope this help.
5 years later... We can only get Google Authenticator to accept secret keys that are 16 digits long. Shorter and longer keys just fail with "Invalid barcode. The barcode ... is not a valid authentication token barcode." Lost a lot of time troubleshooting this, hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With