На старой машине с Linux, работающей PHP 5.3.x
У меня есть следующий код для хеширования и проверки паролей. Этот код также проверяет пароли, хэшированные с помощью c#
GetPbkdf2Bytes
Моя проблема hash_pbkdf2
на более новой машине с Linux, работающей PHP 5.6.x
Native PHP5.6
hash_pbkdf2
не проверяетсяхэши паролей, используя PHP5.3
замена hash_pbkdf2
или c#
GetPbkdf2Bytes
Также собственный PHP5.6
hash_pbkdf2
генерирует более длинные хэши, чем PHP5.3
замена hash_pbkdf2
, которую PHP5.3
не может проверить.
Очевидно, что я могу переименовать hash_pbkdf2
в hash_pbkdf2_old
и использовать его на PHP5.6
, но я хочу понять, почему замена hash_pbkdf2
на самом деле не является полной заменой? Какая разница?
function hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = true) {
$algorithm = strtolower($algorithm);
if (! in_array($algorithm, hash_algos(), true))
die("PBKDF2 ERROR: Invalid hash algorithm `$algorithm`.");
if ($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');
$hash_length = strlen(hash($algorithm, "", $raw_output));
$block_count = ceil($key_length / $hash_length);
$output = "";
for ($i = 1; $i <= $block_count; $i ++) {
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j ++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
if ($raw_output)
return substr($output, 0, $key_length);
else
return bin2hex(substr($output, 0, $key_length));
}
if (! function_exists('hash_equals')) {
function hash_equals($str1, $str2)
{
if (strlen($str1) != strlen($str2)) {
return false;
} else {
$res = $str1 ^ $str2;
$ret = 0;
for ($i = strlen($res) - 1; $i >= 0; $i --)
$ret |= ord($res[$i]);
return ! $ret;
}
}
}
function generateSalt($SaltByteSize) {
if (function_exists('mcrypt_create_iv') && false) {
$buffer = mcrypt_create_iv($SaltByteSize, MCRYPT_DEV_URANDOM);
if ($buffer) {
$buffer_valid = true;
}
}
if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
$buffer = openssl_random_pseudo_bytes($SaltByteSize, $strong);
if ($buffer) {
$buffer_valid = true;
}
}
return base64_encode($buffer);
}
function cSharpHashPassword($password) {
$SaltByteSize = 24;
$HashByteSize = 20;
$iterations = 65536;
$salt = generateSalt($SaltByteSize);
$hash = hash_pbkdf2("sha1", $password, $salt, $iterations, $HashByteSize);
return $iterations . ":" . base64_encode($salt) . ":" . base64_encode($hash);
}
function cSharpValidatePassword($password, $csharphash) {
$chunks = explode(":", $csharphash);
$iterations = $chunks[0];
$salt = $chunks[1];
$hash = $chunks[2];
//$HashByteSize = mb_strlen(base64_decode($hash));
$HashByteSize = (int) (strlen(rtrim($hash, '=')) * 3 / 4);
$testhash = base64_encode(hash_pbkdf2("sha1", $password, base64_decode($salt), $iterations, $HashByteSize));
return hash_equals($testhash, $hash);
}