Hashing is using a one-way function to take a variable length input and generate a fixed length output. The same input produces the same output, while slightly different inputs produce very different outputs. Hashing is used in various situations such as encryption, checksums, and digital signatures. An important feature of hashing algorithms is that the input must be impossible to derive from the output. This is why hashing is a one-way function. This article is about using the OpenBSD Blowfish password hashing code (BCrypt) for securing passwords against cracking.
Brief Background on Password Security
Passwords are extremely sensitive pieces of data. Since users often use the same password on many applications, a single breach on that password can cascade to many other exploitations. Because passwords are so sensitive, they should never be stored as “plaintext”. If a store of passwords is stolen, plaintext passwords are compromised with no effort at all. Instead, passwords should be hashed so that the input is unknown to everyone except the user of the password. When the user enters a password, the hash is then calculated and compared to the stored hash. Only the user should know the password.
Different Ways to Hash
MD5 and SHA are examples of hashing algorithms. MD5 is a common hashing algorithm that produces a 128 bit hash but is not suitable for use in security implementations because of design flaws and successful exploits. SHA-1 creates a 160 bit hash but is also exploitable. SHA-256 and SHA-512 are in the family of SHA-2 hashes and, as indicated by their names, produce 256 and 512 bit hashes respectively. Because the SHA-2 algorithm is similar to SHA-1, it is theoretically exploitable (although as of this post, not successfully broken) so SHA-2 is also not safe. SHA-3, chosen in 2012, is a completely different algorithm than its predecessors and is trusted to be secure.
Blowfish is fairly unique because it is actually a block cipher with a very slow key generator algorithm. This slow key generator, the foundation of BCrypt, was found to be very useful to protect against dictionary attacks because it limits the number of guesses a cracker can attempt per second. On MD5 hashes, a cracker can run programs to try millions or billions of permutations every second because MD5 hashes are so easy to calculate. BCrypt hashes take much longer to calculate, which dramatically reduces the effectiveness of dictionary or brute force cracking. BCrypt also requires a randomly generated salt when it hashes passwords. The optimal setup is to generate a unique salt for each password so that hashes can not be pre-computed en masse.
Bcrypt in Action
I saw this first hand when I used Hashcat to crack a list of 14,000,000 MD5 hashed passwords. In less than two minutes, I cracked about 20% of the passwords (over 2 million). I then took the first 1000 cracked passwords, re-hashed them with the py-BCrypt (the python wrapper for BCrypt), and ran Hashcat over the passwords again. After twenty minutes, not a single hash had been cracked. In retrospect, it would have been interesting to let Hashcat run until it cracked one just to see how long it would take but I got bored. Whatever! The point is, that is an incredible security enhancement.
If you run an application (especially a web app) where you are in charge of password security, you should strongly consider using BCrypt to hash and salt your passwords. It is slower, but security is a good thing to take your time about.