Why You Should Use Bcrypt to Hash Stored Passwords

79% of participants in a recent ZoneAlarm survey were found to be using risky passwords. The data was used to present a very stylish infographic showing just how widespread the use of bad passwords really is. But no matter how hard it is to guess good passwords, they may be no more difficult to crack than bad ones depending on how the password is stored.

Back in 2006, Reddit confirmed that a copy of their database had been stolen. More troubling was the fact that all of the user passwords had been stored in Reddit’s database without being masked in any way! Many users were panicked because they used the same password for Reddit on many other sites too. This was a huge security breach that resulted in a major problem for many unfortunate members of Reddit. It’s shocking to think some web developers still believe storing passwords as plain text with no encryption or hashing is a good way to store a password.

It’s now 2011, and even though most developers agree that obfuscating stored passwords is a mandatory security feature for any user driven website, the practices used are falling behind. Some believe MD5 is a safe way to encode passwords; this is a lie (a very bad one, too)! MD5 is a good method to obscure non-sensitive data but it can be very easily “decoded” using rainbow tables. I once heard the story of a web developer who could not access a client’s database after the client deleted an email that had his password details. The developer, after scouring through the client’s files on their server, found a nicely formatted text file containing the MD5 password hash. It was just a quick copy and paste procedure into an online rainbow table lookup utility before they were logged into the client’s database. This story has a happy ending as the client’s password were recovered and development could continue, but the shocking truth is this process could have easily been carried out by the hands of a malicious hacker.

BCrypt

So what exactly is a good option for secure password hashing? One stand-out option in PHP is Bcrypt. Bcrypt is an adaptive hash function based on the Blowfish symmetric block cipher cryptographic algorithm. It uses a Key Factor (or Work Factor) which adjusts the cost of hashing, which is probably Bcrypt’s most notable feature. The ability to increase the cost (time and processing power) of hashing in the future as computers become more powerful is what really sets Bcrypt apart from other functions.

Bcrypt can expand what is called its Key Factor to compensate for increasingly more-powerful computers and effectively “slow down” its hashing speed. Changing the Key Factor also influences the hash output, so this makes Bcrypt extremely resistant to rainbow table-based attacks. Newer computers can attempt to guess the original input of the hash, but it would still take the same amount of time (or longer) to verify whether its guess is a match or not. All this makes Bcrypt almost future proof!

Bcrypt is incredibly slow to hash input compared to other functions, but this results in a much better output hash. When it comes to hashing and encryption, faster is never better. The longer it takes to encode something, the longer it takes a computer to try and identify the input. As Thomas Ptacek writes in his article Enough with the Rainbow Tables, “The better you can optimize your password hash function, the faster your password hash function gets, the weaker your scheme is.” In Bcrypt’s case, it’s very slow. Consider this quote from Coda Hale’s article How to Safely Store a Password:

How much slower is bcrypt than, say, MD5? Depends on the work factor. Using a work factor of 12, bcrypt hashes the password yaaa in about 0.3 seconds on my laptop. MD5, on the other hand, takes less than a microsecond.

Don’t think Bcrypt sounds like it would be too slow, though. As I mentioned earlier, you can set how large you want the cost of your your hashing to be. This means you can go for all-out-security but sacrifice time by using a huge Key Factor, or you can use a minimum Key Factor and reduce the time it takes to hash the input value. In either case, its this very feature that makes Bcrypt encryption so safe so you can’t lose with either option. It’s all up to you.

To put the ability of Bcrypt into perspective, let’s compare it to a suitable hashing algorithm, such as SHA-2. SHA-2 doesn’t use any cryptographic algorithms, but instead uses a hashing algorithm to generate its output (though both SHA-2′s and Blowfish’s algorithms can stand up to a very similar level of scrutiny). Bcrypt is much slower than SHA-2, and thus theoretically better. SHA-2 also isn’t adaptive like Bcrypt and its Key Factor, so it will be more susceptible to table-based attacks as computer processing power increases. SHA-2 is a completely capable hashing function for now, but Bcrypt wins out because it’s speed (with hashing, slower is always better) and adaptability.

Using Bcrypt in PHP

You might be thinking, “jeez these all seem to be very complex functions… is it really worth taking the time to change my password hashing strategy to use Bcrypt?” The answer is YES! Bcrypt is easy to use and will be worth using in the long run.

Bcrypt is available to you already if you are running PHP version 5.3, simply by using the crypt() function with a Blowfish required salt. It may be available in earlier versions if your system supports them, but I recommend 5.3 because PHP contains its own implementation of algorithm thus eliminating any additional dependencies).

You can check if Bcrypt will work on your server by checking whether or not the CRYPT_BLOWFISH constant is defined and represents 1:

<?php
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
    echo "CRYPT_BLOWFISH is enabled!";
}
else {
    echo "CRYPT_BLOWFISH is not available";
}

After that, you only have to use code similar the following to hash you passwords before storing them:

<?php
$salt = '$2a$07$R.gJb2U2N.FmZ4hPp1y2CN$';
crypt("secretpassword", $salt);

The salt must start with $2a$ followed by a two-digit Key Factor and another dollar-sign, and then contain 22 alphanumeric characters (a period and slash are also allowed). The PHP Manual explains the restrictions on the salt:

[...] salt as follows: “$2a$”, a two digit cost parameter, “$”, and 22 digits from the alphabet “./0-9A-Za-z”. Using characters outside of this range in the salt will cause crypt() to return a zero-length string. The two digit cost parameter is the base-2 logarithm of the iteration count for the underlying Blowfish-based hashing algorithmeter and must be in range 04-31, values outside this range will cause crypt() to fail.

Summary

PHP allows developers to use Bcrypt with the greatest of ease, which begs the question why are you not using it? If you are running a version lower than 5.3, I implore you to upgrade your PHP installation. The importance of using a secure hashing function such as Bcrypt should be vital to anyone creating a web application that will store users’ passwords and other sensitive data.

Besides its ease, I encourage you to use Bcrypt because of the fact it will keep up with Moore’s Law. I know I’ve already covered this earlier, but I feel the need to stress how important this fact is. If you start using Bcrypt now, you can rest assured all your users’ passwords are hashed with a function that is not going to be made obsolete over night. The key to this is the ability to customize the work rate, or Key Factor as I referred to it earlier.

So there you have it, my personal recommendation why you should be using Bcrypt to hash passwords and other sensitive data. Here is a list of sites and articles you can read if you’d like to learn more about Bcrypt or Blowfish:

Image via Valerie Potapova / Shutterstock

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://msmprojects.com MSM

    Better still, use a well-tested component that uses bcrypt, such as Openwall’s PHPass: http://www.openwall.com/phpass/

    • http://www.ryanchouinard.com/ Ryan Chouinard

      Speaking of Openwall’s PHPass, I have adapted an updated version for use in PHP 5.3+: https://github.com/rchouinard/phpass

      Sorry for the self-promotion, but the original PHPass is an excellent library, and more developers should be aware of it. My hope is that the reimplementation will pull in developers who might pass on the original for various reasons.

    • Chris

      “phpass” might be powerful, but it’s extremely hard to use/read/understand. Instead of making it useable with some single lines, you have to work through a giant mess of nerd code.

  • http://keryx.se Lars Gunther

    Also take a look at the built in HMAC functions.
    http://se2.php.net/manual/en/ref.hash.php
    These are not doing the encryption, but they enable easier and consistent coding.

  • http://keryx.se/ Lars Gunther

    Oh, yes, the hmac functions do add an extra layer of security as well. (Forgot to say that…)

  • http://www.get2know.me Anthony Wlodarski

    The best part about crypt is that lets say you use SHA5 and want to switch over to Blowfish this is an easy feat to accomplish. Since all passwords should be checked with “crypt($input, $password) == $password” you can change the salt at any time in your password generation method without fear. No matter what current hashing algorithm you use it will use the correct one denoted every time. Excellent article.

  • http://apyc.com cookies

    very nice article about crypt, thanks ;)

  • http://www.tripvera.com Rob

    Why do you have the extra dollar sign on the end of the salt, it doesn’t do anything?

    • CommentKing

      Because it’s all about the money!

  • http://www.xoogu.com/ Dave

    Thanks for this article, I will look at using crypt for future projects.

    I think you are maybe slightly over-exaggerating the weakness of md5 hashing though. I imagine most developers will be hashing passwords with a different salt for each user, and so rainbow tables would be pretty useless. As you say though, with computing power increasing all the time, it would probably will be vulnerable to brute force attacks in the future.

  • http://zenshadow.com Trevor Geene

    This article is very insightful. My only concern is I am not always told what the server specs are before I start a project, so I worry I might waste my time. I do agree that this seems like a great thing for high security sites and will be looking to use this when the opportunity arises.

  • http://blog.mmn-o.se/ Mikael “MMN-o” Nordfeldth

    Also, there’s no reason to limit oneself to Blowfish if one wants to configure the number of rounds. It works just as well with SHA-512 using a salt like ‘$6$rounds=1234$alengthysalt$’.

    Also, is that really how you supply the number of rounds for Blowfish?

  • http://www.techresx.com/ TechResX

    Always use a random salt when hashing using bcrypt.
    $salt = ‘$2a$12$’ . substr(md5(uniqid(rand(), true)), 0, 22);
    crypt($password, $salt);