I’ve recently been doing a lot of reading about password hashing, which is a deterministic operation that will take a piece of cleartext of arbitrary length and produce a hashed result of a fixed size. The cleartext is known as the message and the hashed value the message digest, or just digest. They are often performed by a cryptographic hash function, but one should use a function that is optimized to be a password hashing function. The latter is the subject of this article.
I’m not going to spend any time on why one should hash passwords and not ever store the cleartext version in the database. We’re way past the point where this should be common practice, although it still happens too frequently.
I’ve usually reached for bcrypt when hashing passwords, as this automatically salts the password and allows for a customizable work factor, and for these reasons crypto experts say to use it (or something similar) over cryptographic hash functions.
Why? Well, the latter, while it works perfectly well as a one-way function, falls down in two very important areas: parallelism and speed (perhaps counter-intuitively, speed is not desirable when hashing passwords). Unfortunately, cryptographic hash functions don’t use a salt and are designed to be fast.
Cryptographic hash functions are too fast, which allows an adversary to try billions of passwords per second with an off-the-shelf GPU.
Parallelism is defeated by using a unique salt for every stored password, and the time to compute a hashed password can be slowed down immensely by increasing the amount of rounds the algorithm uses to hash the password (aka, the work factor).
Think of it this way: if an adversary gets a read-only view of your database (which does happen, i.e., in the case of a SQL injection attack), they can try to crack your passwords at their leisure. Our defense, as informed developers, is to use a good salt and a work factor as high as can be tolerated. This can literally increase the time to crack a password by several orders of magnitude, essentially making it too costly (re: time-consuming) for the adversary.
Password Hashing Functions
I highly recommend reading all of the links that I’ve referenced. Too many developers, myself included at one point, may not know the difference between cryptographic hash functions and tools such as
PBKDF2. The differences may seem subtle, but not to an adversary attempting to crack your passwords, and it could be the difference between a successful break-in and a retreat to look for an easier, softer victim.