Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simple PHP 5.3+ Bcrypt class
<?php
/*
By Marco Arment <me@marco.org>.
This code is released in the public domain.
THERE IS ABSOLUTELY NO WARRANTY.
*/
class Bcrypt {
private $work_factor;
public function __construct($work_factor = 8) {
if (CRYPT_BLOWFISH != 1) {
throw new Exception("Bcrypt not supported in this installation. See http://php.net/crypt");
}
if (!function_exists('openssl_random_pseudo_bytes')) {
throw new Exception('Bcrypt requires openssl PHP extension');
}
if ($work_factor < 4 || $work_factor > 31) {
throw new Exception("Bcrypt only supports work factors between 4 and 31 inclusive");
}
$this->work_factor = $work_factor;
}
public function hash($password) {
$salt =
'$2a$' . str_pad($this->work_factor, 2, '0', STR_PAD_LEFT) . '$' .
substr(
strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'),
0, 22
)
;
return crypt($password, $salt);
}
public function check($password, $stored_hash, $legacy_handler = NULL) {
if (self::is_legacy_hash($stored_hash)) {
if ($legacy_handler) return call_user_func($legacy_handler, $password, $stored_hash);
else throw new Exception('Unsupported hash format');
}
$hash = crypt($password, $stored_hash);
if (strlen($hash) !== strlen($stored_hash)) {
return false;
}
// check each and every character to prevent timing attack against == operator
$result = 0;
for ($i = 0, $j = strlen($hash); $i < $j; $i++) {
$result |= ord($hash[$i]) ^ ord($stored_hash[$i]);
}
return $result == 0;
}
public static function is_legacy_hash($hash) { return substr($hash, 0, 4) != '$2a$'; }
}
?>
@gavD

This comment has been minimized.

Copy link

commented Jun 14, 2012

Useful snippet, thanks

minor gotcha: In the hash function, the $work_factor parameter doesn't seem to be used, it always uses the $this->work_factor

@coastwise

This comment has been minimized.

Copy link
Owner Author

commented Jun 14, 2012

Thanks for the tip, thats what I get for editing source in a web form. ;)
Kudos for the original code should go to Marco. Mine is but a humble fork

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.