У меня есть веб-сайт .NET, построенный с использованием MVC, который имеет модуль управления пользователями. Этот модуль создает хэшированные пароли пользователей, соответствующие спецификации RFC2898, и сохраняет их в db. Конкретная реализация, которую я использую, – это быстрый и удобный метод, найденный в System.Web.Helpers.Crypto.HashPassword()
.
Рассматривая исходный код этого метода, как он найден здесь , он завершает вызов класса Rfc2898DeriveBytes, который фактически создает хэш.
Все идет нормально. Проблема, с которой я сталкиваюсь, заключается в том, что у нас есть веб-сервис, написанный на PHP, который должен выполнять фактическую аутентификацию пользователя. Это означает, что он должен иметь возможность получать необработанный пароль от пользователя и генерировать один и тот же хэш.
Функция NET Crypto.HashPassword()
создает строку с кодировкой base64, содержащую соль, а также ключ. Мы правильно (я думаю) извлекаем эти данные в приведенной ниже реализации PHP, поэтому вход соли должен быть одинаковым.
Обе реализации также выполняют 1000 итераций.
Наша реализация PHP:
function hashtest(){ //password from user $pass = "Welcome4"; //hash generated by Crypto.HashPassword() $hashed_pass = "AP4S5RIkCIT1caoSUocllccY2kXQ5UUDv4iiPCkEELcDK0fhG7Uy+zD0y0FwowI6hA=="; $decode_val = base64_decode($hashed_pass); echo "<br/>Decoded value is: ".$decode_val; echo "<br/>Length of decoded string is: ".strlen($decode_val); $salt = substr($decode_val, 1, 16); $key = substr($decode_val, 17, 49); echo "<br/>Salt is: ".$salt."<br/>Key is: ".$key; $result = $this->pbkdf2("sha256", $pass, $salt, 1000, 32, true); echo "<br/>PBKDF2 result is: ".$result; if($key == $result) echo "<br/>MATCHED!"; else echo "<br/>NOT MATCHED"; And the pbkdbf2 implementation: function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false){ $algorithm = strtolower($algorithm); if(!in_array($algorithm, hash_algos(), true)) die('PBKDF2 ERROR: Invalid hash algorithm.'); if($count <= 0 || $key_length <= 0) die('PBKDF2 ERROR: Invalid parameters.'); $hash_length = strlen(hash($algorithm, "", true)); $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)); }
Поэтому мой вопрос: может ли кто-нибудь сказать мне, должна ли эта реализация PHP генерировать тот же результат, что и реализация .NET Rfc2898DerivedBytes? Оба они якобы соответствуют RFC2898.
Я не являюсь экспертом по предмету в этом предмете, так что, возможно, нам не хватает чего-то очевидного здесь.
Заранее спасибо!