1

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();
        }
    }
}
7
  • Regardless of your current problem: the reversed password makes for a shitty salt. And Encoding.ASCII is problematic for any password including non-ASCII characters. Commented May 11, 2014 at 14:27
  • @Јοеу - yes, i know, but that is what i have to implement. Commented May 11, 2014 at 14:28
  • 2
    Rfc2898DeriveBytes is what you are looking for. msdn.microsoft.com/en-us/library/… Commented May 11, 2014 at 14:29
  • @PaulK - yes, but generated hash is differnt :( Commented May 11, 2014 at 14:37
  • 200 Bounty will be awarded one who helps with proper solution ! Commented May 11, 2014 at 14:39

2 Answers 2

4
+200

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.

Salt inspector

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Thnx for the answer, but just say that the password length is less than 8 chars, in that case how does PHP function is able to calculate hash if minimum of 8 bytes is needed ?
Its not required to create a hash, it is recommended and the native Rfc2898DeriveBytes method requires it. I updated my answer with a link to a valid c# implementation that does not require the minimal salt length.
i should have put more effort into search :P !
cant give bounty for next 13 hrs m8 !
2

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.

4 Comments

Why did you feel the need to provide the exact same answer again?
Hi Hugo. You did beat me to all but the link to the other implementation. I apologize that I did not see your answer before posting.
No problem, and it is correct afterall including the link I was editing in at the same time. So I guess +1 for the effort.
Thanks, Hugo. Maybe next time I'll be a bit quicker on the draw :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.