Почему выходные данные для hash_pbkdf2 (PHP) отличаются от реализации.NET / C#

В моем небольшом проекте мне нужно вычислить хэш функции.

У меня есть рабочий пример 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#.

Вот что я попробовал: 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://stackru.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();
        }
    }
}

2 ответа

Решение

Проблема здесь с вашей солью. Это всего 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, появится "Запрос комментариев", в котором упоминается, что соль должна быть не менее 8 байтов (64 бита). Поэтому использование меньшего количества ведет к конфликтам, как вы уже столкнулись.

ОБНОВИТЬ

Теперь, если вы действительно хотите использовать менее безопасную соль с <8 байтами, вы можете взглянуть на следующую реализацию PBKDF2 стекового потока в C# с Rfc2898DeriveBytes для версии aC#, которая не требует минимальной длины.

Похоже, что метод Pack не является необходимым, но необходимо, чтобы ваша соль была не менее 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://stackru.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();

    }
}

Из ваших комментариев кажется, что вы можете развиваться в соответствии с требованиями ограничений. Если вы не можете контролировать требования к соли, вы можете посмотреть на этот ответ.

Другие вопросы по тегам