All Projects → iamcal → lib_bcrypt

iamcal / lib_bcrypt

Licence: MIT license
Shut up and use bcrypt

Programming Languages

PHP
23972 projects - #3 most used programming language

lib_bcrypt (for PHP) - Store passwords less awfully

If you're storing passwords for user accounts, you should use bcrypt. Don't argue. Just do it.

Do it more easily by using this library:

require('lib_bcrypt.php');

$hasher = new BCryptHasher();

$hash = $hasher->HashPassword($plaintext_password);

Store $hash in your database. When a user logs in and you need to check their password is correct:

if ($hasher->CheckPassword($entered_password, $hash)){

    # password is legit

}else{

    # Y U NO USE CORRECT PASSWORD????
}

Are there options???

There is only one option that you can use while creating a password hash - the work factor. You can pass a value between 4 and 31:

$weak_hash = $hasher->HashPassword($plaintext_password, 4);

$crazy_hash = $hasher->HashPassword($plaintext_password, 31);

This value is the base-2 logarithm of the iteration count of the hashing function. This means that the bigger the number, the slower the hashing. Slow is a good thing!

Some example timings for computing a single hash on my laptop:

Work FactorApprox. Time
42 ms
66 ms
825 ms
10105 ms
12400 ms
141700 ms

The default value is 8, which is pretty fast (though much slower than md5() or sha1()). You might want to pick a higher value if you have beefy servers. The bigger the better, but balance it against how often your app needs to validate logins. Allowing your servers to be DOS'd by submitting a few hundred login attempts per second would suck.

Because the work factor is built into the hash, you can change the value you use over time in your application and the code that checks for valid passwords will not need to be changed.

But I already use some other (bad) hashing function!

If you already store your passwords using md5(), sha1() or something similar, you can't easily generate bcrypt hashes, since you don't have the plaintext passwords.

But it's ok, you can fix this.

All bcrypt hashes start with the string $2a$, so it's easy to tell if a stored hash is from bcrypt or not. When your user logs in, have code something like this:

if (substr($hash, 0, 4) == '$2a$'){

  # good, we have a bcrypt hash already
  $is_ok = $hasher->CheckPassword($entered_password, $hash);

}else{

  # old, bad, hash
  $is_ok = md5($entered_password) == $hash;

  if ($is_ok) update_stored_hash($hasher->HashPassword($entered_password));
}

Using a mechanism like this, you can upgrade your stored hashes the next time a user logs in (or changes their password, or whatever).

If you want to get fancy, you could detect the work factor used to generate the hash you've already got stored and re-hash the password if it's too low. Using this technique, you can keep increasing your work factor as servers become more powerful.

Testing

If you have perl's Test::Harness installed (you almost certainly do), you can run the tests using:

prove --exec 'php' test.php

Notes

Bcrypt will only use the first 72 bytes of the password as part of the hash. If you supply a longer string, only the first 72 bytes will be hashed.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].