【问题标题】:Why is the output for hash_pbkdf2 (PHP) different than the .NET / C# implementation为什么 hash_pbkdf2 (PHP) 的输出与 .NET / C# 实现不同
【发布时间】:2014-06-28 21:46:37
【问题描述】:

在我的一个小项目中,我需要计算一个函数的哈希值。

我有一个 PHP 哈希的工作示例

$pass = "123456";
$mysalt = strrev($pass);
echo hash_pbkdf2('sha1', $pass, $mysalt, 1000, 32); //using the PHP inbuilt function

echo "</br>";
include_once('PasswordHash.php');
echo pbkdf2('sha1', $pass, $mysalt, 1000, 16);  //using external code

它们都有相同的输出:523d904c8f2df96634d9eed3b444838e

现在我需要我的代码向后兼容生成的 C#,因为密码将由 PHP 服务器验证。并且请求将由 C# 应用程序发送。

这是我尝试过的:输出 = 8e59ead5f90c6af11cf80641d51c241c

public static class Program
{
    public static string ReverseString(this string s)
    {
        char[] arr = s.ToCharArray();
        Array.Reverse(arr);
        return new string(arr);
    }

    static void Main(string[] args)
    {
        var pass = "123456";
        byte[] salt = Encoding.ASCII.GetBytes(pass.ReverseString());


        //https://github.com/defuse/password-hashing/blob/master/PasswordHash.cs
        //was getting error salt not 8 byte,
        //http://stackoverflow.com/questions/1647481/what-is-the-c-sharp-equivalent-of-the-php-pack-function
        salt = Pack(pass.ReverseString());
        var hash = PasswordHash.PBKDF2(pass, salt, 1000, 16);
        Console.WriteLine(BitConverter.ToString(hash).Replace("-", string.Empty).ToLower());

        Console.ReadKey();

    }

    public static byte[] Pack(string salt)
    {
        using (var ms = new MemoryStream())
        {
            using (var bw = new BinaryWriter(ms))
            {
                var data = Encoding.ASCII.GetBytes(salt);
                bw.Write(data.Length + 4); // Size of ASCII string + length (4 byte int)
                bw.Write(data);
            }

            return ms.ToArray();
        }
    }
}

【问题讨论】:

  • 不管你当前的问题是什么:密码颠倒了。并且 Encoding.ASCII 对于包括非 ASCII 字符在内的任何密码都是有问题的。
  • @Јοеу - 是的,我知道,但这就是我必须实施的。
  • Rfc2898DeriveBytes 是您正在寻找的。 msdn.microsoft.com/en-us/library/…
  • @PaulK - 是的,但是生成的哈希值不同 :(
  • 200 赏金将奖励一位帮助解决问题的人!

标签: c# php .net pbkdf2 rfc2898


【解决方案1】:

这里的问题在于你的盐。它只有 6 个字节长,PHP 处理这与您的 c# 代码不同。如果您将代码更新为以下内容:

<?php
$pass = "1234567890";
$mysalt = strrev($pass);
echo hash_pbkdf2('sha1', $pass, $mysalt, 1000, 32);
?>

你的输出是:42e8bfc7fc5fd4686915d49d5a29bc1e

然后将您的c# 代码调整为:

var pass = "1234567890";
byte[] salt = Encoding.ASCII.GetBytes(pass.ReverseString());

//DISABLE YOUR PACK METHOD
//salt = Pack(pass.ReverseString());

var hash = PasswordHash.PBKDF2(pass, salt, 1000, 16);
Console.WriteLine(BitConverter.ToString(hash).Replace("-", string.Empty).ToLower());

Console.ReadKey();

输出为:42e8bfc7fc5fd4686915d49d5a29bc1e

区别来自您的Pack 方法,它随机向盐添加4 个字节。您可以在 VS 的检查器中轻松看到这一点。

因此,简单的解决方法是使用至少有 8 个字符的盐(Rfc2898DeriveBytes 的最小值,由您的 C# 代码使用)并且不要使用您的 Pack 方法

如果您查看php docs,则有一个“请求 cmets”,其中提到盐必须至少为 8 字节(64 位)。因此,使用 less 会导致冲突,就像您已经遇到的那样。

更新

现在,如果您真的想使用 PBKDF2 implementation in C# with Rfc2898DeriveBytes 以获得不需要最小长度的 c# 版本。

【讨论】:

  • 谢谢回答,但只是说密码长度小于 8 个字符,在这种情况下,如果需要最少 8 个字节,PHP 函数如何计算哈希?
  • 不需要创建哈希,推荐使用,原生Rfc2898DeriveBytes方法需要。我用一个链接更新了我的答案,该链接指向不需要最小盐长度的有效 c# 实现。
  • 我应该在搜索上付出更多的努力:P!
  • 不能在接下来的 13 小时 m8 中给予赏金!
  • 没问题。很高兴我能帮上忙。
【解决方案2】:

看起来 Pack 方法不是必需的,但你的 salt 至少需要 8 个字节。

$pass = "12345678";
$mysalt = strrev($pass);
echo hash_pbkdf2('sha1', $pass, $mysalt, 1000, 32); //using the PHP inbuilt function

这会输出381dae25b08b6f141671c74715961b1b

此 C# 代码提供相同的输出。

public static class Program
{
    public static string ReverseString(this string s)
    {
        char[] arr = s.ToCharArray();
        Array.Reverse(arr);
        return new string(arr);
    }

    static void Main(string[] args)
    {
        var pass = "12345678";
        byte[] salt = Encoding.ASCII.GetBytes(pass.ReverseString());


        //https://github.com/defuse/password-hashing/blob/master/PasswordHash.cs
        //was getting error salt not 8 byte,
        //https://stackoverflow.com/questions/1647481/what-is-the-c-sharp-equivalent-of-the-php-pack-function
        var hash = PasswordHash.PBKDF2(pass, salt, 1000, 16);
        Console.WriteLine(BitConverter.ToString(hash).Replace("-", string.Empty).ToLower());

        Console.ReadKey();

    }
}

从您的 cmets 看来,您可能是在需求限制下进行开发的。如果您无法控制盐的要求,您可以查看this answer

【讨论】:

  • 您为什么觉得需要再次提供完全相同的答案?
  • 嗨雨果。除了指向其他实现的链接之外,您确实击败了我。很抱歉,在发布之前我没有看到您的答案。
  • 没问题,毕竟包括我同时编辑的链接都是正确的。所以我想 +1 的努力。
  • 谢谢,雨果。也许下次我会在平局上快一点:-)
猜你喜欢
  • 1970-01-01
  • 2020-10-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
  • 2013-03-07
  • 1970-01-01
  • 1970-01-01
  • 2016-10-10
相关资源
最近更新 更多