Password Hashing

One of the primary uses for one-way hash algorithms is to store user passwords securely.

Never Plain Text

Passwords should NEVER be stored in plain text. This is one of the worst security sins possible. A website compromises its own user accounts by storing passwords in plain text. Staff can easily read and use the passwords. They can be retained insecurely in old data backups or on discarded hardware. Attackers can steal them through techniques like SQL Injection. But plain text passwords also compromise the security of other websites because passwords are often re-used. It is common for stolen or leaked passwords from one site to be used to log in to other sites in the days and weeks that follow.

The Plain Text Offenders website attempts to shame this bad behavior but publishing the names of sites which are discovered to either store or email plain text passwords.

Use One-way Encryption

One-way encryption algorithms are better for passwords than two-way encryption algorithms. They cannot be decrypted—not by an attacker, not by staff, not even by administrators. If stolen, they provide the most security.

It might seem that a password needs to be decrypted so that it can be compared against a password submitted during login. It is not necessary because one-way encryption algorithms operate on the principle that the same input into the same hash algorithm returns the same output. A website can hash a user's original password and store the result. When a user logins in, the website can hash the new password with the same algorithm. If the two results match, then the password is correct.

A good choice for a password hashing algorithm will be cryptographically secure (i.e. unbreakable) and use one-way encryption, allowing no decryption. Calculation speed is not an important consideration, in fact, there are some reasons to favor a slow calculation.

Slower is Better

A slower algorithm provides a defense against rapid-fire password attempts in a Brute Force Attack. A user will not notice if they have to wait an extra 0.1 seconds during the login process. However, a Brute Force Attack needs to try billions of random strings to guess the correct password. An extra 0.1 seconds will significantly slow down their attempts. For every one billion attempts, an extra 0.1 second adds three additional years to the time it takes to crack one password!

Password Hashing Algorithms

Historically, the MD5 and SHA-1 algorithms have been popular choices for storing passwords. MD5 was popular from 1991-2004 until a number of collision vulnerabilities where discovered. SHA-1 was popular from 1996-2010, largely as a replacement for MD5. It is more secure than MD5 in part because it generates a larger hash (160-bit vs. 128-bit) which makes collisions much less likely. While not as vulnerable as MD5, some collision vulnerabilities have been discovered for SHA-1. Because there are better alternatives, these algorithms are not recommended for hashing passwords.

bcrypt is a popular and secure choice for hashing passwords. It is based on Blowfish, but because it performs one-way encryption, it is more secure. One of the distinguishing characteristics of bcrypt (and Blowfish) is that it is a relatively slow algorithm. This is a good trait for password hashing because it provides a defense against a Brute Force Attack. bcrypt is recommended for hashing passwords.

Encryption using bcrypt

Example in PHP:

  function password_encrypt($password) {
    // Use bcrypt with a "cost" of 10
    $hash_format = "$2y$10$";
    return crypt($password, $hash_format);

Decryption using bcrypt

Example in PHP:

  $password_hash = password_encrypt('secret');
  $new_hash = crypt($attempted_password, $password_hash);
  $is_match = ($new_hash === $password_hash);

bcrypt Cost Parameter

This example sets bcrypt's cost parameter to 10. Cost specifies the key expansion iteration count. In plain language, that means it sets how many times to scramble the values being used for encryption. The cost parameter is a great feature of bcrypt because it makes it more secure in a few ways. Primarily, the ability to set a higher cost makes the algorithm slower. It also provides a defense against the use of Rainbow Tables.

bcrypt Salts

bcrypt also uses [salts|Salts] when hashing. Using a salt when hashing passwords is the best defense against the use of Rainbow Tables. The salt value can be provided by the user, or bcrypt will use a default salt. A bcrypt salt should be 22 characters or longer and should contain only the characters: a-zA-Z0-9./. In PHP, the salt is appended to the end of the hash format string and included as the second argument to the crypt() function.

Fork me on GitHub