Skip to content

Instantly share code, notes, and snippets.

@ircmaxell
Created June 18, 2012 16:53
Show Gist options
  • Save ircmaxell/2949382 to your computer and use it in GitHub Desktop.
Save ircmaxell/2949382 to your computer and use it in GitHub Desktop.
Password API Example
<?php
define('PASSWORD_SHA256', '$5$');
define('PASSWORD_SHA512', '$6$');
define('PASSWORD_BCRYPT', '$2y$');
define('PASSWORD_SCRYPT', '$7$'); // made up here
$password_algos = array();
function password_register_algo($prefix, Callable $create, Callable $validate) {
global $password_algos;
$password_algos[$prefix] = array($create, $validate);
}
function password_hash($password, $algo = PASSWORD_BCRYPT, array $options = array()) {
global $password_algos;
$salt = '';
switch ($algo) {
case PASSWORD_SHA256:
case PASSWORD_SHA512:
$rounds = isset($options['rounds']) ? $options['rounds'] : false;
$random = password_create_salt(16);
$salt = $algo;
if ($rounds) {
$salt .= 'rounds=' . $rounds . '&';
}
$salt .= $random;
break;
case PASSWORD_BCRYPT:
$cost = isset($options['cost']) ? $options['cost'] : 14;
$random = password_create_salt(22);
$salt = '$2y$' . str_pad($cost, 2, '0', STR_PAD_LEFT) . $random;
break;
default:
if (isset($password_algos[$algo])) {
return $password_algos[$algo][0]($password, $options);
}
trigger_error(E_WARNING, 'Invalid Algorithm Specified');
}
$return = crypt($password, $salt);
if (strlen($return) < 13) {
trigger_error(E_WARNING, 'Crypt Routine Failed');
return false;
}
return $return;
}
function password_validate($password, $hash) {
global $password_algos;
$algo = substr($hash, 0, strpos($hash, '$', 1));
if (isset($password_algos[$algo]) && !in_array($algo, array(PASSWORD_SHA256, PASSWORD_SHA512, PASSWORD_BCRYPT, PASSWORD_SCRYPT))) {
$testHash = $password_algos[$algo][1]($password, $hash);
} else {
$testHash = crypt($password, $hash);
}
$testSalt = password_create_salt(strlen($hash));
$hash = hash_hmac('sha512', $hash, $testSalt);
$testHash = hash_hmac('sha512', $testHash, $testSalt);
$length = strlen($hash);
$result = 0;
for ($i = 0; $i < $length; $i++) {
$result |= ord($hash[$i]) ^ ord($testHash[$i]);
}
return $result === 0;
}
function password_create_salt($length) {
// Prepare for base64 encoding
$size = ceil($length * 3 / 4);
if (function_exists('mcrypt_create_iv')) {
$random = mcrypt_create_iv($size, MCRYPT_DEV_URANDOM);
} elseif (function_exists('openssl_random_pseudo_bytes')) {
$random = openssl_random_pseudo_bytes($size);
} else {
$random = '';
for ($i = 0; $i < $size; $i++) {
$random .= chr(mt_rand(0, 255));
}
}
// base64 encode it for crypt
$text = base64_encode($random);
$salt = strtr($text, '+', '.');
return substr($salt, 0, $length);
}
<?php
$password = '1234';
$hash = password_hash($password);
if (password_validate($password, $hash)) {}
$hash = password_hash($password, PASSWORD_BCRYPT);
if (password_validate($password, $hash)) {}
$hash = password_hash($password, PASSWORD_BCRYPT, array('cost' => 13));
if (password_validate($password, $hash)) {}
$hash = password_hash($password, PASSWORD_SHA512, array('rounds' => 50000));
if (password_validate($password, $hash)) {}
$hash = password_hash($password, '$P$');
// E_WARNING
password_register_algo('$P$', array('PHPASS', 'create'), array('PHPASS', 'validate'));
$hash = password_hash($password, '$P$');
if (password_validate($password, $hash)) {}
@gergoerdosi
Copy link

A typo in usage, the constant should be PASSWORD_BCRYPT instead of PASSWORD_BLOWFISH.

@ircmaxell
Copy link
Author

gergo, fixed...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment