One-Time Passwords (OTP)

By December 27, 2016.NET, node.js

Years ago, I worked for a customer who provided me with a RSA SecurID device to access their VPN. This was a plastic fob that would display a six digit number on a LCD screen. Every 30 seconds, the numbers changed to a different random six digits. To log into their VPN, I had to provide my username and password, plus the current six digit number displayed on the device. So, even if my password was compromised, an attacker still could not get into their VPN without also having that SecurID device.

Today, we simply call this Two-Factor Authentication, or 2FA. While plastic fobs are still in use, it is more common for people to have apps on their phone to show the same information (such as Google Authenticator, Microsoft AuthenticatorToofer, and Authy). Generating and verifying One-Time Passwords (OTPs) has been standardized (e.g., RFC 2289, RFC 4226, and RFC 6238), so you can easily implement 2FA on your own site for login. Or, as I recently discovered, you can also use a OTP as a temporary self-expiring token to authenticate between two disconnected systems under your control without the need for a separate login.

There are two types of OTPs that are commonly used:

  • HMAC-based One-Time Passwords (HOTP) utilize a shared secret and an increasing counter as the randomness seed. Each time that a user successfully uses a HOTP, the counter is incremented to make that password no longer valid (i.e., your application must increment the counter, and the counter must be kept in sync among various components of your system). Because they change only upon consumption, this approach creates long-lived OTPs.
  • Time-based One-Time Passwords (TOTP) utilize a shared secret and the current date/time as the randomness seed. This is refreshed periodically (i.e., every 30 seconds, like the RSA SecurID device), creating short-lived OTPs. This approach requires the clocks in various components of your system to be synchronized.

From a security point of view, OTP algorithms are nothing more than a cryptographic hasher (such as SHA256), a secret key, and a nonce (i.e., the counter or the current timestamp). One weak link to be aware of is the fact that the secret key must be shared among the system’s participants. This makes the key subject to being discovered if any part of the system is compromised. A best practice is to use a unique secret per identity principal (so that an attack is confined to a single user), and handle keys within your application’s code like you would a password.

It is notoriously hard for programmers to implement cryptography correctly on the first attempt. Fortunately, OTP algorithms are available as packages for inclusion in your application, such as Speakeasy for Node.js and OTPSharp for .NET. (Note: There are MANY others, but I fell into the pit of success by using these two).

Implement an OTP in Node.js with Speakeasy

Using Speakeasy in Node.js is very simple, and yet very configurable to meet your exact needs:

Speakeasy supports many different encoding formats for the secret. In the example above, the secret is provided as an ASCII string (the default encoding, but is explicitly set in the example code). This will be hashed first, resulting in an array of bytes. You can also provide a binary secret as a string of hexadecimal characters (‘hex’ encoding), Base32 characters (‘base32’ encoding), or Base64 characters (‘base64’ encoding). The important requirement is that the secret must be the same in all parts of your system (i.e., the token generation component and the token verification component).

Time synchronization is a feature commonly enabled by default on computers and phones, but there is no guarantee that all machines using your system will have the same exact time. To accommodate for a small delta, Speakeasy allows you to provide a ‘window’ option. In the above TOTP example, a default step of 30 seconds is being used in the token generation. When verifying a token, the ‘window: 1’ option means that it will accept the current 30-second window’s token, as well as a valid token that is from the previous 30 second window and the next 30 second window. I would caution against making the window too large, though, since that allows a token to be valid longer (and for TOTP, shorter timeframes are more secure).

Implement an OTP in .NET with OTPSharp

On the .NET side, use NuGet to include OTPSharp into your project. Because it implements the same RFC standards, it will offer similar functionality to Speakeasy. However, syntax is definitely different:

The secret can be provided as a string to be hashed, or a byte array that you manually create beforehand. There are no convenience methods to create the byte array for you from hex, Base32, or Base64 strings (due to separation of concerns).

The verification step returns the nonce value as an output variable when a password is valid. This is a significant difference from the Speakeasy functionality. The purpose of a One-Time Password is to be used only once, so your system must track when a password is used and not accept it a second time. Speakeasy just assumes that you will save the token itself for tracking when a password has been used, but OTPSharp also provides you with the 30-second window number itself to which the token belongs (in case working with an integer is easier for your persistence layer).

Use a Third-Party Authenticator App

If you wish to use a third-party app, like Microsoft Authenticator or Google Authenticator, then be aware that your TOTP must use SHA1 as the hashing algorithm, 30 second steps, and 6-digit tokens. The binary secret must be shared as a Base32 string compliant with RFC 4648. You can provide the Base32 string directly to the user, or generate a QR code containing a Key URI (so that the user simply needs to take a picture of the QR instead of entering a complex string of letters and numbers by hand).

screenshot_20161227-101811

Once the account has been set up, the Authenticator app will show a new token every 30 seconds:

screenshot_20161227-102657

 

The following two tabs change content below.
Jason Follas is a Sr. Architect for Falafel Software and lives near Toledo, OH. He has been a Microsoft MVP for SQL, Visual C#, and most recently Windows Platform. When not working or speaking, you can find him writing a number of casual games currently in the Windows Store or fishing in the local river.

Latest posts by Jason Follas (see all)