What is Two Factor Authentication?

Two Factor Authentication is a way to authenticate users using two of the three valid authentication factors: something the user knows (password, PIN, etc), something the user has (smart card, phone, ATM card, etc.), and something the user is (biometric data, including figerprints). In the case of this article, we will be using something the user knows, a password, and something the user has, a smartphone.

What is Google Authenticator?

Google Authenticator is a software based two-factor authentication token. It is available on iOS, Android, and BlackBerry operating systems. It provides a 6 digit, time or counter based number that acts as the 2nd factor for our two factor authentication.

How does it work?

Google Authenticator implements the algorithms defined in RFC 4226 and RFC 6238. The first is a counter based implementation of two-factor authentication. The second is a time-based implementation. First, the server and the user agree on a secret key to use as the seed value for the hashing function. The user can type in this key to Google Authenticator or use a QR code to automatically set up your application. Then Google Authenticator uses one of the above algorithms to generate a code to be entered during authentication. Your server will then use the same algorithm and secret key to check the code. Once the secret key has been agreed on, the only data passing between the client and your server will be the 6-digit key generated by the Google Authenticator application. At no time does any of this data pass through Google's servers.

Counter Based One Time Password Generation

To generate a one-time password, we need three pieces of information, the secret key, the counter number, and the number of digits the output should be. Since we are using Google Authenticator, we are limited to 6 digits.

Let's go through what we are doing. First, we convert the iteration number to a byte[], which can be hashed using the HMAC-SHA-1 hash method. The iteration number should be incremented on the client and server every time authentication succeeds. We use the managed HMAC-SHA-1 hashing method available from the <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha1.aspx">System.Security.Cryptography.HMACSHA1</a> class. Next we compute the hash for the current value of the counter. The next part of the code extracts the binary value of a 4 byte integer, then shrinks it to the number of digits required. That's it. The entire algorithm in 25 lines. RFC 4226 Section 5.4 has a good example and description of what is happening, which I will copy and paste here:

Time Based One Time Password Generation

RFC 6238 defines the time based implementation of the one time password generation. Time based one time password generation builds on the counter based approach above. It is exactly the same, except it automatically defines the counter based on intervals of time since the Unix epoch (Jan 1, 1970, 00:00 UTC). Technically, the RFC allows for any start date and time interval, but Google Authenticator requires the Unix epoch and a 30 second time interval. What this means is that we can get the current one-time-password using only the secret key. Here is how:

As you can see, we are just getting the number of 30 second intervals since the Unix epoch and using that as our counter value. This means that the clock on both the client and the server need to be kept in sync with each other. This is commonly done with the Network Time Protocol.

How do I put it to use?

Well, now we have covered how the code works, the next question is how do you use it? I have created some extra overloads for the GetPassword method for time-based generation, and added an IsValid method.

IsValid helps a little with clock skew by checking adjacent intervals for the password as well. This can help improve user experience a lot, because it doesn't require the clocks to be perfectly aligned.

Create the MVC Web Application

Create a new MVC 3 Web Application using the "New Project" wizard in Visual Studio 2010. Be sure to select "Internet" application in the wizard. This will create the default Account controller and views needed for forms authentication.

Create the TwoFactorProfile Class

Next we create a Profile class that inherits from ProfileBase. This will store the 2 factor secret for a given user.

Modify the web.config

Modify the <system.web><profile> element to inherit from the TwoFactorProfile class we just created:

<profileinherits="TwoFactorWeb.TwoFactorProfile">

Modify AccountController

We need to modify AccountController in a few places. First, the Register action needs to be modified to send the user to the ShowTwoFactorSecret page, so they can set up their Google Authenticator. In the Register action, modify the RedirectToAction from:

This just generates a new random 10 character secret, then shows it to the user in Base32 encoded format, which is how Google Authenticator expects the user to enter it. Feel free to create your secret any way you want, but it needs to be at least 10 characters or Google Authenticator will complain.

Finally, we change the LogOn action to check the code provided by the user to ensure it is valid. Our new LogOn action is below:

As you can see, we show an image of a QR code the user can scan and we also show the secret as a string the user can manually enter. The format of the QR code is defined here.

See the result

After registering as a new user in the web application, you should see a screen like the following:

At this point, you should scan the QR code with the Google Authenticator app, or enter the code below the QR code manually:

Now, when you log in, you should see a new field to enter your "Google Authenticator Code":

Just enter the current 6-digit code on the Google Authenticator screen for your application:

If you entered your username, password and code correctly, you should be able to log in.

History

13 June 2012 - First release.

14 June 2012 - Added screenshots of the web app and Google Authenticator. Thanks to Priyank Bolia for suggesting this.

13 August 2012 - Updated to use a more secure method of generating the random secret for the user. Thanks to rhoffman for pointing this out.

11 September 2012 - Updated to add a time delay between login attempts for a given user. This helps mitigate the chance of a brute force attack when the attacker knows the password. Updated to generate the QR code directly, instead of relying on an external service.

23 October 2012 - Updated the code attached to provided caching of previously used one-time passwords, to prevent them from being used more than once. Thanks to MatrixQN for pointing out this issue.

I have found an addition regarding iPhones, for some mysterious reason a QR code containing "=" characters at the end function perfectly on Android phones, but on iPhones the Google authenticator app refuses the code stating it is invalid. As the "=" character is only padding strip them before sending it to the QR generator.

Dear Rick Bassham： As title, when I read and run the project code, I find there have some classes in the directory"C:\Users\$UserName\AppData\Local\Temp", such like "FormsAuthentication" and "MemberShip".Could you tell me why or give me a guide?Another question is does the user data save in function "FormsAuthentication.SetAuthCookie"?

Dear Rick I've read your article,and it's great! But when I read the part about "How does it work？", I'm a little confused. For example,I've got a smartphone that have the Google Authenticator in it,when I login ,I input my username\password\6-digit number.How the server part recognises the 6-digit number?

When you created your account, you had to setup Google Authenticator with a "seed" value (the secret key). When you scan the QR code or enter the key, both the server and the client (Google Authenticator) now know how to generate the code. The 6 digit code is entirely based on the secret key and the current time, so no information needs to be exchanged after the initial key has been shared. Take some time to really study and understand the "GeneratePassword" and "GetPassword" methods in the article. If you have any other questions, please ask.

Google Authenticator by itself does not provide two factor authentication. However, using Google Authenticator along with requiring a separate password for your site does satisfy the requirement for two separate authentication factors. To log in you must still provide proof of something you have (your smartphone running Google Authenticator) and something you know (your password for your site). This is the first time I have seen mOTP, and (I may be wrong here, I just glanced at the project) it looks to solve both parts in one application, where my approach is to use the built in authentication methods in ASP.Net along side Google Authenticator.

It doesn't create the database. It gives this error: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

Since the counter used in generating the password only changes every 30 seconds, then yes, you can use it multiple times in a given 30 second interval. If this is an issue for your application, then you should store which interval was last used to log in, and require the user to wait until a later interval. This is actually mentioned specifically in section 5.2 of the RFC[^], and to qualify as a real one time password algorithm, it is required to do this.

This was very good, well-written, and I'm sure I'll use this technique again. However, I had to hunt around quite a bit for the stuff missing from the article -- although if I'd just installed the .csproj file instead of relying on the article, it all would have been obvious from the first hour.

Nice work. I implemented this process a few months ago. Your code would have been helpful at that time.

I actually used Google's chart service to generate the QR code. One advantage is their support of https for retrieval. Of course, who knows how long either of these services will stay operational. Anyway, here's the google URL method:

Thanks for the comment. I updated the code to use a QR code generating library instead of relying on an external service. I also added a link to the github site where I keep the code. The newest code also has checks in place to limit a brute force attack of the code when the attacker knows the username and password.

Actually, it was when I saw that LastPass allowed you to use the Google Authenticator app that I realized you could use it for more than just Google services. That is what made me research the project and decide to write the article!

It seems to work for me on Android. Did you add the account by scanning the QR code or typing in the code below it? Also, are you trying to log in with the username you created or the email address? It should be the username. I only ask because I made the same mistake while trying to test your issue. You also need to make sure your clocks are synchronized.

Thanks Rick !! I've found out that the clocks are not synchronized, but this is a little tricky because a user has to make sure that his clock on his device is synchronized with the clock on the server!

That is true. Most servers should have their clocks synchronized for other reasons. Windows calls this feature "Internet Time" and is available in the "Date & Time" settings. Also, most mobile phones sync their time to their carrier. For everyone else, they just have to make sure they keep their clock correct... You can help them a little by increasing the "checkAdjacentIntervals" parameter in call to the "IsValid" method. This would allow you to increase the width of the "correct" time slice, but at decreased security. The larger you make the window, the less security you have.

Interesting. The My APP LABEL was just a placeholder and is meant to be replaced with an identifier meaningful to your user, either your application name, their login, etc. I don't have an IPhone so I wasn't able to test it. Thanks for letting me know.

This article looked like a fun project to try, so I created an ASP.NET MVC app that implemented two factor authentication. I am voting 4 stars because I feel the technique for generating the random seed value (the two factor secret) is vulnerable in this implementation. The code:

Overall, I really appreciated the author writing about this topic. It seems nearly every day we hear how a huge company's database has been compromised and two factor authentication is clearly an interesting approach to increase security.

I agree that the Guid technique is not a secure way to generate the random value, and that the random number generator in the Cryptography namespace is the better way to go. I really just thought of this as a proof-of-concept, but I'll look at updating the example so people don't think this is a proper way to do it in a production environment.