Reputation: 20565
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();
}
}
}
Upvotes: 1
Views: 1707
Reputation: 14163
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.
Upvotes: 4
Reputation: 365
It looks like the Pack method is not necessary, but it is necessary that your salt be at least 8 bytes.
$pass = "12345678";
$mysalt = strrev($pass);
echo hash_pbkdf2('sha1', $pass, $mysalt, 1000, 32); //using the PHP inbuilt function
This outputs 381dae25b08b6f141671c74715961b1b
.
This C# code provides the same output.
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();
}
}
From your comments, it seems like you may be developing under requirements constraints. If you are not able to control the requirements around salt, you might look at this answer.
Upvotes: 2