A simple .NET password hashing implementation using BCrypt

By now, you've heard many many stories about compromised sites and how millions of emails and clear-text passwords have made it to the hands of "not so good" people.

If you are a developer and you need to create some kind of authentication for your clients/software/site/pet-project, please make sure you approach this with the gravity that it demands.

Troy Hunt, a security expert has written about the subject multiple times and I would urge you seriously to have a look at his blog or his pluralsight courses. Troy is one of the many security experts out there, so please ensure you educate yourself on the subject.

The bottom line is: you should never, ever, ever in any case expose user details, especially emails and passwords. To ensure that this never happens, even if the site, database, server etc get compromised, you need to employ the power of cryptography. There are lots of established cryptographic algorithms out there to choose from, so I leave this with you. However, you should never feel the urge to re-invent the wheel or roll out your own as this is a big security NO-NO.

How do you got about implementing this then, you ask? Easy:

  • Passwords => should be one-way hashed
  • Sensitive data => should be encrypted

Passwords should be one-way hashed to enhance security. If there is any way for your software or your users to retrieve their password through the application, then any hacker with access to your data can do the same. Simple(s)!

Implementing a hashing library

Below I have a very basic implementation of a basic hashing library.

First you need to use Nuget to add the BCrypt library to your project. If you wish to find more details on BCrypt and why "slow hashing algorithms can save your skin", feel free to look here and here

Then create a class that looks like this:

using BCrypt.Net;

public class Hashing  
    private static string GetRandomSalt()
        return BCrypt.GenerateSalt(12);

    public static string HashPassword(string password)
        return BCrypt.HashPassword(password, GetRandomSalt());

    public static bool ValidatePassword(string password, string correctHash)
        return BCrypt.Verify(password, correctHash);

That's it! That's all you need. Crazy simple, right? Now, I wonder why so many reputable sites out there don't implement this... Anyway, back to the task at hand. The class consists of 3 basic methods, but the important ones are the public methods.

When your users create their password, you call the HashPassword(plaintextPassword) with the user's plaintext password. This returns a nice hash for you. You store this against the user data in the database or any other persisted data implementation you use.

If you want to really strengthen your hash, you can change the GenerateSalt() method to use a value bigger than 12. However, this will seriously impact speed and CPU so be aware of this method. You should find the right balance for your implementation

When the user returns to your application to authenticate, you use the ValidatePassword(plainTextPassword, storedHash) method. Notice that at no stage do you try to retrieve the password from the stored hash. Instead, what you do is compare the plain text password supplied by the user against the stored hash. BCrypt takes care of the validation under the covers so you don't have to worry about it. If the plaintext password matches the one that was originally supplied by the user, the method returns "true" and you can then authenticate your user.

That's all folks!

Bonus points: Another little trick I like to implement to further improve security is to add an artificial delay to the login process to protect against brute force attacks.

The delay is exponentially incremented with every attempt taking a few seconds so, say after 5 failed login attempts, the page takes about 15-20secs to load. Most users will take between 1-3 attempts before they either look up the password in some password management tool (Password Defence) or request a reset. In any case, the site and user data are fully protected from random, brute force attacks without degrading the user experience.
Let me know if you would like an implementation example of this and I'll be happy to write up a quick post about it.

Happy coding...

  • Share this post on
comments powered by Disqus