为什么比.NET / C#实现不同的输出hash_pbkdf2(PHP) [英] Why is the output for hash_pbkdf2 (PHP) different than the .NET / C# implementation
问题描述
在我的一个小项目,我需要计算一个函数的哈希值。
我有PHP哈希的工作示例
$通=123456;
$ mysalt = strrev($通行证);
回声hash_pbkdf2(SHA1,$传球,$ mysalt,1000,32); //使用PHP内置函数
回声< / BR>中;
include_once('PasswordHash.php');
回声PBKDF2(SHA1,$传球,$ mysalt,1000,16); //使用外部code
他们都具有相同的输出: 523d904c8f2df96634d9eed3b444838e
现在我需要我的code是落后与生成的密码将通过PHP服务器进行验证C#兼容。并且请求是由一个C#应用程序来发送。
下面是我的尝试:输出= 8e59ead5f90c6af11cf80641d51c241c
公共静态类节目
{
公共静态字符串ReverseString(这个字符串s)
{
的char [] ARR = s.ToCharArray();
Array.Reverse(ARR);
返回新的字符串(ARR);
}
静态无效的主要(字串[] args)
{
变种通=123456;
byte []的盐= Encoding.ASCII.GetBytes(pass.ReverseString());
//https://github.com/defuse/password-hashing/blob/master/PasswordHash.cs
//越来越错误的盐不是8个字节,
//http://stackoverflow.com/questions/1647481/what-is-the-c-sharp-equivalent-of-the-php-pack-function
盐=包(pass.ReverseString());
VAR哈希= PasswordHash.PBKDF2(通,盐,1000,16);
Console.WriteLine(BitConverter.ToString(散).Replace( - ,的String.Empty).ToLower());
Console.ReadKey();
}
公共静态byte []的包(字符串盐)
{
使用(VAR毫秒=新的MemoryStream())
{
使用(VAR体重=新的BinaryWriter(MS))
{
VAR数据= Encoding.ASCII.GetBytes(盐);
bw.Write(data.Length + 4); // ASCII字符串+长度尺寸(4字节INT)
bw.Write(数据);
}
返回ms.ToArray();
}
}
}
这里的问题是与你的盐。只有6个字节长, PHP
处理这种不同,那么你的 C#
code。如果您更新code以下内容:
< PHP
$传球=1234567890;
$ mysalt = strrev($通行证);
回声hash_pbkdf2(SHA1,$传球,$ mysalt,1000,32);
?>
你的输出是:42e8bfc7fc5fd4686915d49d5a29bc1e
然后调整 C#
code到:
VAR通=1234567890;
byte []的盐= Encoding.ASCII.GetBytes(pass.ReverseString());
//禁用压缩方法
//盐=包(pass.ReverseString());
VAR哈希= PasswordHash.PBKDF2(通,盐,1000,16);
Console.WriteLine(BitConverter.ToString(散).Replace( - ,的String.Empty).ToLower());
Console.ReadKey();
输出结果是:42e8bfc7fc5fd4686915d49d5a29bc1e
的差别来自于你的包
方法,它随机增加了4个字节的盐。你可以看到,很容易在VS的检查。
所以简单的解决方法是使用这是由你的 C#$ C盐有ATLEAST 8个字符(最低为
Rfc2898DeriveBytes
$ C> code)和不使用你的包
方法
如果你看一下 的的PHP文档的 有一个请求征求意见是提到,盐必须是ATLEAST 8个字节(64位)。因此,使用更少的操作将导致冲突,像你已经遇到过。
更新
现在,如果你真的想使用以&lt安全性较低的盐,8个字节,你可以看看下面的计算器问题 PBKDF2执行在C#与Rfc2898DeriveBytes 了解,这并不需要的最小长度C#版本。
In a small project of mine i need to calculate the hash of a function.
I have a working example of PHP hash
$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
Both of them has same output : 523d904c8f2df96634d9eed3b444838e
Now i need my code to be backward be compatible with C# generated as the password has will be verified by a PHP server. and the Request is to be sent by a C# application.
Here is what i tried : output = 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();
}
}
}
The problem here is with your salt. It is only 6 bytes long and PHP
handles this different then your c#
code. If you update the code to the following:
<?php
$pass = "1234567890";
$mysalt = strrev($pass);
echo hash_pbkdf2('sha1', $pass, $mysalt, 1000, 32);
?>
your output is: 42e8bfc7fc5fd4686915d49d5a29bc1e
Then adjust your c#
code to:
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();
The output is: 42e8bfc7fc5fd4686915d49d5a29bc1e
The difference comes from your Pack
method, it randomly adds 4 bytes to the salt. You can see that easily in the inspector in VS.
So the easy fix is to use a salt that has atleast 8 chars (minimum for Rfc2898DeriveBytes
which is used by your C#
code) and dont use your Pack
method
If you look at the php docs there is a "Request for comments" that mentions that the salt must be atleast 8bytes (64bit). So using less leads to conflicts, like you already encountered.
UPDATE
Now if you realy want to use the less secure salt with <8 bytes, you can look at the following stackoverflow question PBKDF2 implementation in C# with Rfc2898DeriveBytes for a c# version that doesnt require a minimum length.
这篇关于为什么比.NET / C#实现不同的输出hash_pbkdf2(PHP)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!