Использование PBKDF2 в Java и PHP

У меня возникли трудности с созданием одного и того же зашифрованного пароля с использованием алгоритма PBKDF2 как на Java, так и на PHP.

Я использую следующую реализацию Java для генерации хэша со случайным массивом байтов размером 16 байт. Затем я сохраняю хэш и соль отдельно в базе данных MySQL, однако, когда я выполняю ту же операцию в PHP с использованием соли, полученной из базы данных, я получаю почти такое же шифрование, за исключением того, что хеш имеет начальный 0, а я хоть убей не могу понять почему.

Джава:

public String hashPassword(String password, byte[] salt){

 char[] passwordChars = password.toCharArray();

     PBEKeySpec spec = new PBEKeySpec(
         passwordChars,
         salt,
         ITERATIONS,
         KEY_LENGTH
     );
     SecretKeyFactory key = null;
    try {
        key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }

    byte[] hashedPassword = null;

    try {
        hashedPassword = key.generateSecret(spec).getEncoded();
    } catch (InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
     return String.format("%x", new BigInteger(hashedPassword));

}

Я нашел приведенный выше код на странице https://adambard.com/blog/3-wrong-ways-to-store-a-password/

PHP:

$query = $database->query('SELECT * FROM USERS');

$password = 'hello';
$iterations = 1000;

foreach($query as $user){
    $hash = hash_pbkdf2("sha1", $password, $user['salt'], $iterations, 40, false);

}
echo $hash;

Примечание. В базе данных хранится только один пользователь, я знаю, что приведенный выше код не очень хорош, я быстро создал его для целей тестирования.

Для обеих реализаций я использую количество итераций 1000, длину ключа 160 в Java и длину ключа 40 в PHP (чтобы компенсировать установку raw-output на false)

Java Output - 971f0dddc1bc2e899f2bca178f16ea79bfbbb13
PHP Output - 0971f0dddc1bc2e899f2bca178f16ea79bfbbb13

Любая помощь очень ценится, спасибо.


person Astronought    schedule 16.03.2016    source источник
comment
Возможный дубликат Как преобразовать байт массив в шестнадцатеричную строку в Java?   -  person Artjom B.    schedule 16.03.2016
comment
@artjom B. Проблема была в преобразовании массива байтов в шестнадцатеричную строку. Вместо этого я использовал String Builder для выполнения процесса преобразования, и он работал, как задумано.   -  person Astronought    schedule 20.03.2016


Ответы (1)


Это BigInteger убивает ведущий 0.

Хэши не являются целыми числами, это массив из 8-битных байтов. Не пытайтесь конвертировать в BigInteger.

Либо используйте его как byte[], либо закодируйте как шестнадцатеричную строку или строку Base64. Для соответствия шестнадцатеричному кодированию PHP hashedPassword.

PHP возвращает хеш-код в виде шестнадцатеричной строки, потому что для raw_output установлено значение FALSE.

person zaph    schedule 16.03.2016
comment
Спасибо, это преобразование BigInteger было виновником, я использовал String Builder для создания шестнадцатеричной строки, и он работал правильно. - person Astronought; 20.03.2016