One Time Passwords in C#

Illustration

Recently I was working on a project where time-based one-time password algorithm might come in handy. You know the one - you have token that displays 6-digit number and you enter it after your user name and password. It used to be restricted to hardware (e.g. RSA) but these days Google Authenticator is probably the best known.

While rolling something on your own is always possibility, following the standard is always better because all tough questions have been answered by people smarter than you. In this case all things needed were covered in RFC 6238 (Time-Based One-Time Password Algorithm) and RFC 4226 (An HMAC-Based One-Time Password Algorithm).

While specifications do grant you some freedom in algorithm choice and number of digits you wish to generate, looking at other services implementing the same algorithm, 6-digit SHA-1 based code seems to be unwritten rule. Also universal seems the rule to use (unpadded) Base32 encoding of a secret key. Any implementation of one-time password algorithm has obey these rules if it wants to use existing infrastructure - both server side services and end-user applications (e.g. Google Authenticator or Pebble one).

With my OneTimePassword implementation, basic code generation would looks something like this:

var otp = new OneTimePassword("jbsw y3dp ehpk 3pxp");
txtCode.Text = otp.GetCode().ToString("000000"); //to generate new code

If you are on server side, verification would look just slightly different:

var otp = new OneTimePassword("jbsw y3dp ehpk 3pxp");
var isValid = otp.IsCodeValid(code); //to verify one that user entered

If you want to generate a new secret key for end-user:

var otp = new OneTimePassword();
var secret = otp.GetBase32Secret();

Pretty much all basic scenarios are covered and then some. Sample with full code is available for download.

PS: OneTimePassword class supports many more things than ones mentioned here. You can use it in HOTP (counter) mode with TimeStep=0; you can generate your own keys; validate codes; use SHA-256 and SHA-512; other digit lengths… Play with it and see.