Created
June 29, 2011 17:01
-
-
Save dsibilly/1054317 to your computer and use it in GitHub Desktop.
Simple PHP 5.3+ Bcrypt class adapted from phpass
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
Adaptation by Marco Arment <me@marco.org>. | |
Adapted from Portable PHP Password Hashing Framework (phpass) version 0.3: | |
http://www.openwall.com/phpass/ | |
phpass was by Solar Designer <solar at openwall.com> in 2004-2006 and is in | |
the public domain. This adaptation is also in the public domain. | |
THERE IS ABSOLUTELY NO WARRANTY. | |
Major differences from phpass in this adaptation: | |
- Removed support for versions of PHP prior to 5.3 | |
- Removed "portable" hash support, since it was mostly for those earlier | |
versions of PHP | |
- Replaced manual randomness generation with openssl_random_pseudo_bytes() | |
(thanks, Marc Hedlund) | |
- Added convenience features for migrations from legacy password hashes | |
- Refactored to a more appropriate and modern structure and style for PHP 5 | |
Usage example: | |
// In a registration or password-change form: | |
$hash_for_user = Bcrypt::hash($_POST['password']); | |
// In a login form: | |
$is_correct = Bcrypt::check($_POST['password'], $stored_hash_for_user); | |
// In a login form when migrating entries gradually from a legacy SHA-1 hash: | |
$is_correct = Bcrypt::check( | |
$_POST['password'], | |
$stored_hash_for_user, | |
function($password, $hash) { return $hash == sha1($password); } | |
); | |
if ($is_correct && Bcrypt::is_legacy_hash($stored_hash_for_user)) { | |
$user->store_new_hash(Bcrypt::hash($_POST['password'])); | |
} | |
*/ | |
class Bcrypt | |
{ | |
const DEFAULT_WORK_FACTOR = 8; | |
public static function hash($password, $work_factor = 0) | |
{ | |
if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above'); | |
if (! function_exists('openssl_random_pseudo_bytes')) { | |
throw new Exception('Bcrypt requires openssl PHP extension'); | |
} | |
if ($work_factor < 4 || $work_factor > 31) $work_factor = self::DEFAULT_WORK_FACTOR; | |
$salt = | |
'$2a$' . str_pad($work_factor, 2, '0', STR_PAD_LEFT) . '$' . | |
substr( | |
strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'), | |
0, 22 | |
) | |
; | |
return crypt($password, $salt); | |
} | |
public static function check($password, $stored_hash, $legacy_handler = NULL) | |
{ | |
if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above'); | |
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'); | |
} | |
return crypt($password, $stored_hash) == $stored_hash; | |
} | |
public static function is_legacy_hash($hash) { return substr($hash, 0, 4) != '$2a$'; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment