Unless you have been living under a rock, you would be very used to authenticating yourself using an authenticator app on your mobile phone. But have you ever wondered how an online service is able to check if the code generated by an app on your mobile phone is correct or not? No, the app and the online service don’t talk to one another over the internet.
If so, how is this possible? Well, this is made possible by TOTP authentication which stands for Time-based One-time Password authentication. This is merely an extension of HOTP which stands for HMAC-based One-Time Password. Therefore, to understand TOTP, an understanding of HOTP is necessary.
TOTP is an extension of HOTP
To explain HOTP briefly, HOTP uses the HMAC algorithm to generate a hash which is then truncated to produce a number containing a certain number of digits, which is usually six. The HMAC algorithm takes in a secret key and data and hashes them twice to produce a hash. You can learn more about the HMAC algorithm here.
The HOTP algorithm uses HMAC to hash together a secret key and a counter. This counter is incremented over time by the algorithm in such a way that both the authenticating system and the code generator, which is often a hardware token, have their counters in sync with one another. You can learn about it here.
TOTP extends HOTP by replacing the counter that is incremented with the current time. This not only ensures that the OTP generated is valid only for a certain amount of time but it also greatly reduces the problem of synchronization in HOTP.
How does TOTP work?
Here, the authenticator and the authenticated share a secret key between each other. The authenticated, whenever asked to present the OTP code, uses the shared secret key and the current time as inputs to the HMAC algorithm to produce a hash which is then truncated to produce the code. Since it is a hash, the system needs to provide the exact same input to produce the same code. If the system can produce the same code, it then successfully authenticates the user.
However, there will be an obvious latency between the user’s authenticator app generating the code and the system receiving the code. Which means the time input into the HMAC algorithm by the app will differ from the time the system enters. Therefore, it is important that there exists a window of time.
This window is usually 30 seconds. So, a code is supposed to be entered into the system within 30 seconds of its generation. But how can this window be implemented? This is done by deducting the Unix epoch from the current Unix time and dividing it by the window duration.
Let’s see how this works by considering an example. Let’s say the current time is 2020-04-20T07:09:48Z. Here, the last Z shows that it is the GMT time. The Unix epoch is 1970-01-01T00:00:00Z. So, we need to first find out how much time has elapsed since the Unix epoch by subtracting the Unix epoch from the current time. Doing so gives us 50 years, 3 months, 19 days, 7 hours, 9 minutes, 48 seconds. Now, we need to divide it by 30 seconds to find out how many 30 seconds have elapsed since the Unix epoch.
getTime() method of the Date object can give you the number of milliseconds that have elapsed since the Unix epoch. This is
1587366588000 for our example. Now, we can divide this by 30000 (since
getTime() returns milliseconds) to get the number of 30 seconds that have elapsed since the Unix epoch.
Flooring the division
After doing the division, it is important that we floor the obtained value to the largest integer less than or equal to the output of the division. If we assume 58 seconds have elapsed since the Unix epoch, dividing 58 by 30 is going to give us 1.933. To know the number of 30 seconds that have elapsed, we need to floor this value. Flooring 1.93 gives us 1. This shows 1 30-second duration has elapsed since the epoch, which is correct.
Thus, if we divide the value we obtained in our example by 30 seconds and floor it, we get 52912219. This shows 52,912,219 30-seconds have elapsed since the epoch. Since both the system and the app will produce the exact same number during the 30-second window, they would be producing the same TOTP code and thus, the user can be authenticated.
Now that we have understood how TOTP works, let’s try to implement it. It will be fun!
Let “Hello World!” be the secret key. First, we need to base32 encode it to produce a QR code URI. I used this site to encode the secret key. The encoded base32 string is this:
Now, let’s construct the QR code URI.
Here, the secret query parameter takes in the encoded secret key whereas the issuer parameter takes in the name of the issuer. The issuer’s name can be anything you want. The portion between ‘
totp/’ and ‘
?’ can carry information regarding the user. Once the URI is ready, we can use a service such as this to generate a QR code.
The TOTP code from my app is:
The timestamp when the above code was generated is:
Let’s try to reproduce the TOTP code using the algorithm
Our goal, now, is to use the timestamp to produce the TOTP code using the TOTP algorithm. First, we need to convert the timestamp to the hexadecimal format. I used this site for converting. The converted hexadecimal number is as follows:
A hexadecimal digit represents 4 bits. Here, we have 7 digits giving us a total of 28 bits. Popular implementations of the TOTP algorithm expect an eight-byte (64-bit) input. Hence, we have to add zeroes to the left of the number to make it an eight-byte number. Since we need
64-28=36 bits in addition, we have to add nine zeroes to the left of the number. So, the final number would be:
Next, let’s produce an HMAC code using the secret key and the timestamp. I used this site to create the HMAC code. Set the input type to “HEX” and enter the timestamp. Set the key type to “TEXT” and enter the secret key. The HMAC code produced would be as follows:
Now, let’s truncate this hash to produce the TOTP code. You can learn about how the algorithm does this in detail here. The last hexadecimal digit is 1, the decimal value of which is also 1. So, we need to extract from the 1st byte to the 3rd byte, which is:
Now, let’s mask the first bit. This gives us:
Next, we need to find the decimal value of this number. This site allows you to convert hexadecimal numbers to decimals. The converted decimal number is:
Now, let’s find the modulus of this number by dividing it by 106 since we need a six-digit code. Doing so gives us
649751, which is exactly the TOTP code we got from the app!