native hash_pbkdf2 не проверяет хэши паролей с использованием замены hash_pbkdf2 (PHP 5.3.x) - PullRequest
0 голосов
/ 14 октября 2019

На старой машине с 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);
}
...