Lesson from a Reference

I learned a valuable lesson recently. When implemented TOTP on the OTP Android application, I used the Java reference implementation from the draft RFC document. The outputs matched and I assumed everything was fine. Last week, I was given a heads up through email that  TOTP output values were not matching output values of other TOTP implementations. I assumed the other applications were wrong as I followed the true reference implementation.

I realized, however, that I was wrong. I was incorrectly using the source code by not verifying how the input was specified. The source attached to the document assumed that the ASCII seed had already been transformed into a hexadecimal string. For example, the seed in the reference implementation was "3132333435363738393031323334353637383930" which is the hexadecimal representation of the ASCII string "01234567890123456789". I thought that the long string was supposed to be entered by the user. If I would have though shortly about the ridiculous nature of that number, I may have realized my mistake.

I have released an update to the market correcting this error and a few other bugs. I fixed the activity stack to behave more in line with other Android applications (I didn't know much at the time of writing the older releases). I also cleaned up some interfaces to behave properly on different screen sizes.

12 comments:

manonstreet said...

I believe your 'correction' actually broke HOTP. From what I have seen, HOTP seeds are distributed as 16 byte hexadecimal values (32 byte string).

Jeff said...

Great app!

I have a suggestion - when setting up a HOTP/TOTP profile, could you add the digits setting to the profile and remove it from the Generate Key screen? That way, if you don't use the default key length (Google's TOPT app defaults to 6 digits, BTW), you wouldn't have to enter it every time you generate a key.

Chris Miceli said...

@manonstreet
I now realize that HOTP seeds are distributed as hex instead of ASCII strings, but if I change this in the application, all users will have to reenter their key, or I could automatically update them. This may cause future confusion if a user goes to enter a new key. There is always a 1-to-1 conversion between the two, so users will just have to convert if they have a hex seed. I know this is suboptimal, but perhaps I can fix this one day by allowing both types to be entered and automatically detecting which one was entered.

Chris Miceli said...

@Jeff
I have made this adjustment in the newest version of the application. That is a great suggestion. I would like to move the hash type also, but have limited time at the moment. Thank you for the suggestion.

Jeff said...

Thanks for the updating, it looks good. A couple more questions:

1. You say that the seeds are distributed in hex. Is there a standard that suggests this or is it just common practice. I'm writing a TOPT based authenticator for an application and I'm not really sure how best disseminate the seeds. Google uses Base32 (both in the QR code and plain text), so I have been providing that along with the 20 digit key for use with your application.

2. In the new version, you added the Time Zone combobox to the profile setting screen. As far as I can tell from the specification, the time zone should always be UTC since the time is always described as Unix time.

Matt said...

@chris
It is impossible to enter an ASCII representation of a hex value. Remember, ASCII is a limited character set. For example, try figuring out and typing the ASCII character for the hex value "dc" on your phone keyboard. ASCII generally only uses 7 out of 8 bits, and even within those 7 bits there are plenty of untypable characters such as NULL or BACKSPACE. Tough to enter that into an input box...

I can't imagine that anyone has successfully typed an HOTP seed in your current implementation. The odds of having a long hex seed consisting of only values that have keyboard representations are extremely small.

Chris Miceli said...

@matt
You make a good point! I was thinking that you meant all keys were ASCII and distributed in Hex for some reason. That wouldn't make much sense at all. I will update the application to accept both kinds and convert old keys in ASCII to Hex. This may take some time. I thank you for your input.

Chris Miceli said...

@Jeff
I have allowed both ASCII and Hexadecimal key entry in the newest version. I store the keys internally though as hexadecmial. This is not specified in the specification of either TOTP of HOTP so it must just be common practice.

Also, I reread the TOTP specification, and you are correct about the Unix Time. I removed time zone support from TOTP as Unix Time is always relative to UTC. Thank you very much for the input.

Chris Miceli said...

@Matt
I have updated the application now to support either ASCII or hexadecimal key/seed entry. Thank you for pointing this out. I appreciate the input. Tell me what you think.

Jan Zawadzki (Hapara) said...

Hi Chris -

Same problem with mOTP. Your code automatically performs an MD5 transform on the seed, but does not allow the hash to be shown or set the secret explicitly...

Unfortunately this means that other mobile implementations (the midlet, iPhone ones, JS, etc.) cannot work alongside yours, as they all set the secret directly (no md5), thereby making your otherwise great tool not very useful.

In brief: the secret needs to be directly settable to make it possible to enroll your Android users along with Nokia, BB and iPhone users through the same server interface...

Of the Android motp generators yours is the cleanest, so clients like it - but can't use it as is and I'm not keen to fork your code?

Can you add one more text field to the motp enroll form to allow the users to set the secret directly, and if present, use that?

Chris Miceli said...

@Jan Zawadzki (Hapara)
I just want to make sure that I understand you correctly before I implement your fix. Your clients have the secret that they wish to create a profile with. The secret has already been generated and thus had MD5 applied to it already. You want them to be able to enter the MD5ed secret into my program and use it instead of taking what they give me, MD5ing it, and then computing the OTP.

If this is the case, I can simply put a check box on the create screen for mOTP and if checked, don't compute the MD5 when computing the OTP. Does this sound good to you?

Jan Zawadzki (Hapara) said...

Hi Chris - wish I knew what to suggest! The problem is usability across the different devices and the enrollment process.

OTP enrollment is difficult for most users as-is, hence the appeal of your app - compare your app to others and you will see that yours gives the users the fewest choices, and therefore the fewest opportunities for error.

Unfortunately, with mOTP clients diverging (some require a seed, some ask for the secret directly) there just isn't a simple way to express this to the user. Things like "seed", or "secret" mean absolutely nothing to most people, and getting the user to make the right decision during enrollment here is a crapshoot. Not your doing, just the problem with diverging client implementations.

We've ended up migrating to HOTP and the Google Authenticator, but again, FWIW, you were very much on the right track with your UI.