我有一个使用MVC构建的.NET网站,它有一个用户管理模块。此模块生成符合RFC2898规范的用户密码哈希值,并将其存储在数据库中。我正在使用的具体实现是System.Web.Helpers.Crypto.HashPassword()
中的快速方便的方法。
查看找到here的方法的源代码,它正在包含对Rfc2898DeriveBytes类的调用,该类实际上创建了散列。
到目前为止一切顺利。我面临的问题是我们有一个用PHP编写的Web服务,必须进行实际的用户身份验证。这意味着它必须能够从用户接收原始密码并生成相同的哈希。
NET Crypto.HashPassword()
函数创建一个base64编码的字符串,其中包含salt和key。我们正确地(我认为)在下面的PHP实现中提取这些数据,因此salt输入应该是相同的。
两种实现也执行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。
我不是这个主题的领域专家,所以我们可能会遗漏一些明显的东西..
提前致谢!
答案 0 :(得分:2)
1)Crypto.HashPassword()
使用SHA1,您的PHP代码使用SHA256。
2)密码需要UTF8编码(对于普通的拉丁密码无关紧要,但无论如何都要这样做。)
另外,你$hashed_pass
是不正确的(它给出的盐不符合“Welcome4”)。请从不做这些事情。这浪费了我很多时间。 Welcome4的真实哈希的一个例子是ALtF3x2vx6u6gJIOm1MdTNwvL4yNBeKjuwscgkLgJUAI9TE2N8nYTjanAuXJjcqYpA==
。试试吧。
所以,正确的电话是:
$result = $this->pbkdf2("sha1", utf8_encode($pass), $salt, 1000, 32, true);