One Time Passwords
Two factor authentication has become commonplace amongst the multitude of web services I use on a daily basis. The goal of two factor authentication is to increase security by requiring two pieces of information to authorize yourself. First you use the traditional username/password combination to establish identity. Then you use a second, time sensitive code. This code is delivered by text message or generated by using an authenticator application.
To amuse myself, and reduce my dependence on my phone, I decided to implement my own one time password generator. Of course it will be a command line application implemented in go. Let's look at the most common application - Google Authenticator - for inspiration. This screenshot taken on my iPhone shows three accounts and their respective codes.1 Each account has a code and a countdown timer (shown as a circular progress meter). The goal: reproduce the same code and same timing for each account.
The first step is to research the algorithm used. Wikipedia provides a brief overview and a link to the RFC (#6238). The algorithm used is called Time OTP, or TOTP. TOTP takes one input, a secret string.2 The secret string is then hashed3 with the current unix time4. The output is then truncated, modded, and padded to return a 6 digit code. That covers the criteria for generating a single code. What about one for every site?
Run the algorithm multiple times - once for each site. Done. Well, not quite. We want to display the time remaining for each code in place to avoid scrolling. The terminal provides a mechanism for this exact scenario - escape codes.
Terminal escape codes are a string of characters, from stdout, that are interpreted by the terminal as behavior rather than displayed to the user.
For example, coloring text can be done with terminal escape codes.
echo "this is \x1b[0;32mgreen\x1b[0m text"
5
Aside from color, and more relevant to this project, are the collection of escape codes for moving the cursor and clearing text.
Two are of particular interest - move cursor up (\0x1b[A
) and clear current line(\0x1b[2k
).6
Every half second I clear the output and redraw7.
After a draw the cursor sits at the beginning of the next line.
To clear the output move the cursor up and clear the current line.
Repeat len(sites)
times.
Since TOTP is time sensitive a token generator can be frustrating to debug. Essentially, the clocks have to be in sync on both the server side and the authenticator application side. Otherwise, the tokens would not match and login would fail. A handy tool for this (at least on linux) is NTP8. In my case the clocks were out of sync by 40 seconds. This was the most frustrating part. Since the time difference was only slightly longer than the token lifetime I would occasionally see correct tokens further back in the output9. Long story short, time is hard.
When I started this project I only expected to learn about a hash function. NTP, base32 encoding, and terminal escape codes are three tools that were previously mysterious but crucial to implementing onetime. Overall, I would call it a success. There are still many areas to explore in the future (profiling memory usage, cross platform testing, output to file instead of terminal, ...).
-
Don't worry, they are generated from old secrets. No security issue here. ↩
-
The secret is encoded in base32. Some sites (looking at you Hover) decide to provide a key with an odd number of characters. be sure to pad it with '='. ↩
-
Well, the time is computed as number of 30 second periods since the Unix Epoch for UI. It would be hard to copy and paste if the code was valid for only one second. ↩
-
Run it in a VT/100 compatible terminal. ↩
-
\0x1b
is the hex literal forESC
(keycode 27). ↩ -
Half second redraw time instead of second to reduce timing inaccuracies. ↩
-
This protocol is on the implementation list. ↩
-
This was ultimately the clue to fixing it. ↩