Use BCrypt to Save Password (Hashes)

With nearly every application and website demanding an account, most developers will sooner or later have to store passwords. It is incredible how bad that can be implemented and how dire the consequences can be for the users. Take a quick look at the long list of sites taking part in “Have I been pwned?” and you can see how big the problem is.

Security is a complex topic with many stumbling blocks. Overlook just one and you create a big security hole that dissolves your other work into thin air. Therefore, take the tips in this post with caution and check if the here recommended libraries are still in favour of the programming community.

This post is part of the Protecting Passwords series. You can find the other parts here:

 

What exactly is the requirement?

Let us start with the most important question: Do you really need to store passwords? Most applications only need a username and a password to identify a user. That can and should be done using password hashes instead of the password itself and this post is going to show you a secure way to do it.

Only a few applications need to store the password itself, like a password manager. In this case you have to do a lot of research on what the programming language and framework you use can offer or go extra lengths to come up with your own solution. If you build such an application, you need to look somewhere else for help.

 

Use BCrypt

Hashing passwords seems to be easy: Take a hash function, run the user password through it and compare it with the one you stored. While this is the general approach, you cannot take just any hash function. MD5 was widely used in the past, but since 2012 you can calculate collisions (different values resulting in the same hash) without much effort. MD5 should therefore no longer be used, even when you find many examples online.

A much better hash function is BCrypt. It not only is easy to use, it has some built-in features that makes password cracking especially hard. You get a randomly generated salt for free, what gives every user his own unique hash – even when they all use the same password. You can try it for yourself as I did it with the string “demo“:

$2a$12$HE3WNFbpOOEe0.E35fFHZ.HvPBwGknio0J/0NmCVI0VCpZV6iDN6G
$2a$12$lithgf7LGjOYPG8Nr/cmoOxudT99GsTIOhPBqlzkjuR45sBpd1.di
$2a$12$D7NwzW/jZdhqw8WrzMzLZeXfjOhX/zsX27wVkWQuojhG0Lrf0ZrSO
$2a$12$9Tfxc7KW4W79HaTowt7GEOxJWAUnDAaOK.emXaUTG/f4P7cIQRhxK
$2a$12$wamHSU9negAgNu7FO7WRd.MlRcU7DYHS3x7xUqtfMWThdajUPxkpe

This behaviour requires you to use a different method to verify a password than you used to create the hash. Since this will be done in two different places in your code, the additional work is neglectable. Just compare it to the code you would need to write to get a random salt for each password and store it in your user table.

There are implementations for nearly every programming language, including

 

Code examples

When you use C#, you can install BCrypt.Net in the package manager console:

Use the HashPassword() method to create a new hash:

Check the password with the Verify() method:

That is all you need to create a hash with BCrypt and verify that a password is a match.

 

Slow is better

When it comes to hash functions for passwords you want a slow one. That is at odds with all we usually want, but here it is a feature and not a bug. Slow means your attacker will have a long time to crack the passwords.

With the work factor of BCrypt you can increase the computational work one needs to do to create and verify a hash. Increasing the work factor by one doubles the amount of work it needs. With that you can adjust for the improvements in hardware and keep using the same hashing function for years to come.

On a modern gaming computer, you can calculate millions of MD5 hashes per second. If you use BCrypt with a work factor of 12 you may only be able to calculate 2 hashes per second. Even when you add much more graphic cards, you will always be miles away from the speed to calculate MD5 hashes.

You should choose the work factor at a level where it is taking its time but is still fast enough to not get noticed by your users. I picked 12 for that reason and the machines I used. You can pick what you like, but you should not get below 10.

Should you forget what the work factor was at the time of hashing a password, you can look at the hash itself. As in the examples above all hashes started with a prefix of $2a$12$. This means they where created using version 2a of the algorithm and a work factor of 12.

 

Limitations of BCrypt

BCrypt limits the length of the password to 72 bytes and truncates longer ones. The number of characters that fit into 72 bytes depend on their encoding in UTF8 and can therefore be much less than 72 characters. You find the details in an answer by Ian Boyd on Stack Exchange.

That is a downside when your users use a password manager. However, some implementations like bcrypt.net I used above, already have a built-in enhancer who can be turned on. If you set the flag enhancedEntropy to true in the HashPassword() and Verify() method you can use much longer passwords.

 

Conclusion

Do not write your own hash function or worse, store passwords in plain text or use MD5. Instead use an established hash function that is made for handling passwords like BCrypt. Its no extra work and you reduce the risk of compromising your users’ passwords.

 

Next

We now have done our part to protect the passwords of our users. However, that does not help much if they reuse their password in multiple sites. Next week I show you a way to check if the password used to login on your site is part of a data breach.

1 thought on “Use BCrypt to Save Password (Hashes)”

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.