PBKDBF2散列 - PHP中的.NET rfc2898DerivedBytes类的复制功能 [英] PBKDBF2 hash - duplicating functionality of .NET rfc2898DerivedBytes class in PHP

查看:168
本文介绍了PBKDBF2散列 - PHP中的.NET rfc2898DerivedBytes类的复制功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用MVC构建的具有用户管理模块的.NET网站。该模块生成符合RFC2898规范的用户密码散列并将它们存储在数据库中。我使用的具体实现是在 System.Web.Helpers.Crypto.HashPassword()中找到的快捷方法。



查看该方法的源代码,发现 here ,它正在调用Rfc2898DeriveBytes类,该类实际上创建了散列。



到目前为止这样好。我面临的问题是我们有一个用PHP编写的Web服务,它必须执行实际的用户身份验证。这意味着它必须能够接收来自用户的原始密码并生成相同的散列。
$ b NET Crypto.HashPassword()函数创建一个base64编码的字符串,其中包含salt以及键。我们正确地(我认为)在下面的PHP实现中提取这些数据,所以盐输入应该是相同的。



这两个实现都执行1000次迭代。



我们的PHP实现:

 函数hashtest(){
//用户
$ pass =Welcome4的密码;

//由Crypto.HashPassword()生成的哈希
$ hashed_pa​​ss =AP4S5RIkCIT1caoSUocllccY2kXQ5UUDv4iiPCkEELcDK0fhG7Uy + zD0y0FwowI6hA ==;

$ decode_val = base64_decode($ hashed_pa​​ss);
echo< br />解码值是:。$ decode_val;
echo< br />解码字符串的长度是:.strlen($ decode_val);

$ salt = substr($ decode_val,1,16);
$ key = substr($ decode_val,17,49);
echo< br />盐是:。$ salt。< br />关键是:。$ key;

$ result = $ this-> pbkdf2(sha256,$ pass,$ salt,1000,32,true);
echo< br /> PBKDF2的结果是:。$ result;

if($ key == $ result)
echo< br /> MATCHED!;
else
echo< br /> NOT MATCHED;

和pbkdbf2实现:

函数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 =;
$ b $ for($ i = 1; $ i <= $ block_count; $ i ++){
// $ i编码为4字节,大字节。

$ last = $盐。包(N,$ i);
//第一次迭代

$ last = $ xorsum = hash_hmac($ algorithm,$ last,$ password,true); ($ j = 1; $ j< $ count; $ j ++){
$ xorsum ^ =($;
)//执行另一个$ count - 1迭代

last = hash_hmac($ algorithm,$ last,$ password,true));

}
$ output。= $ xorsum;


$ b if($ raw_output)
return substr($ output,0,$ key_length);
else
return bin2hex(substr($ output,0,$ key_length));





$ b

所以我的问题是:任何人都可以告诉我,如果这个PHP实现应该生成与.NET Rfc2898DerivedBytes实现相同的输出?它们都被认为符合RFC2898。



我不是这个主题的领域专家,所以我们可能在这里错过了一些明显的东西。



$ p

解决方案

1) Crypto.HashPassword()使用SHA1,您的PHP代码使用SHA256。
2)密码需要使用UTF8编码(对于普通的拉丁密码无关紧要,但无论如何都是这样做的)。



另外,您 $ hashed_pa​​ss 不正确(它不符合给定salt的Welcome4)。请从不做这样的事情。浪费了我很多时间。 Welcome4的一个真正的散列的例子是 ALtF3x2vx6u6gJIOm1MdTNwvL4yNBeKjuwscgkLgJUAI9TE2N8nYTjanAuXJjcqYpA == 。试试看。

所以,正确的调用是:

$ $ $ $ $ $ $ c $ $结果$ this-> pbkdf2(sha1,utf8_encode($ pass),$ salt,1000, 32,true);


I have a .NET web site built using MVC that has a user-management module. This module generates user passwords hashed conforming to the RFC2898 spec and stores them in a db. The specific implementation I'm using is the quick and convenient method found in System.Web.Helpers.Crypto.HashPassword().

Looking at the source code for that method as found here, it is wrapping a call to the Rfc2898DeriveBytes class, which actually creates the hash.

So far so good. The problem I'm facing is that we have a web service written in PHP that must do the actual user authentication. This means it must be able to receive a raw password from a user and generate the same hash.

The NET Crypto.HashPassword() function creates a base64 encoded string that contains the salt as well as the key. We are correctly (I think) extracting this data in the below PHP implementation so the salt input should be the same.

Both implementations also perform 1000 iterations.

Our PHP implementation:

    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));
                }

So my question is: Can anyone tell me if this PHP implementation supposed to generate the same output as the .NET Rfc2898DerivedBytes implementation? They are both supposedly conforming to RFC2898.

I'm not a domain expert in this subject matter, so it's possible we're missing something obvious here..

Thanks in advance!

解决方案

1) Crypto.HashPassword() uses SHA1 and your PHP code uses SHA256. 2) The password needs to be UTF8-encoded (doesn't matter for plain latin passwords, but do it anyway).

Also, you $hashed_pass is incorrect (it does NOT correspond to "Welcome4" given the salt). Please, never do such things. It wasted a lot of my time. An example of real hash for Welcome4" is ALtF3x2vx6u6gJIOm1MdTNwvL4yNBeKjuwscgkLgJUAI9TE2N8nYTjanAuXJjcqYpA==. Try it.

So, the correct call is:

$result = $this->pbkdf2("sha1", utf8_encode($pass), $salt, 1000, 32, true);

这篇关于PBKDBF2散列 - PHP中的.NET rfc2898DerivedBytes类的复制功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆