PBKDF2 — невозможно сгенерировать один и тот же ключ в кодировке Base64 с помощью Node и Java.

Я работаю над проектом, в котором используется ручное хеширование паролей в Java, и мне поручено дублировать схему хеширования в NodeJS, чтобы пользователям не приходилось сбрасывать свои пароли.

Кажется, я не могу написать функцию хеширования, которая генерирует ключ, идентичный ключу, сгенерированному устаревшим кодом.

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

Реализация Java:

public static String hash(byte[] salt, String password) throws HashException {
    try {
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        return encode(f.generateSecret(spec).getEncoded());
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
        throw new HashException("Issues hashing the password", e);
    }
}

Моя попытка в NodeJS:

const crypto = require("crypto")

const encodedsalt = "oFoz+aZuGX5Ad/HAa35HLw=="
const encodedpass = "fp+gXqcO7fBKuXuhZQPY/A=="

// decode 
const decodedsalt = Buffer.from(encodedsalt, "base64")
const decodedpass = Buffer.from(encodedpass, "base64")

var key = crypto.pbkdf2Sync("13111789", decodedsalt, 65536, 16, "sha1")
var encodedKey = key.toString("base64")

Я ожидаю, что ключи будут совпадать, потому что каждая реализация использует идентичный массив байтов для соли и идентичную строку для пароля. Вместо этого ключи совпадают только по длине. Я уверен, что есть какая-то особенность реализации, которую я не замечаю, но я ее не вижу! Любая помощь приветствуется - все остальные вопросы PBKDF2 были сосредоточены на какой-то другой незначительной проблеме, поэтому я здесь в растерянности.


person Jared Cuffe    schedule 24.09.2019    source источник
comment
Также добавьте используемые значения для salt и password в части Java.   -  person Robert    schedule 24.09.2019


Ответы (1)


код, который вы разместили, в основном в порядке. вы не определили encode в своем Java-коде, поэтому проблема может заключаться в этом. вот код Java для рабочего примера:

import java.util.Base64;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public static String hash(byte[] salt, String password) throws Exception {
    SecretKeyFactory pbkdf2 = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
    byte[] secret = pbkdf2.generateSecret(spec).getEncoded();

    return Base64.getEncoder().encodeToString(secret);
}

это можно запустить как:

String base64_salt = "oFoz+aZuGX5Ad/HAa35HLw==";
byte[] salt = Base64.getDecoder().decode(base64_salt);

System.out.println(hash(salt, "13111789"));

даю мне: On7VbkKDXdz8aTWo5tDBXw==

эквивалентный код JS будет:

const crypto = require("crypto");

function hash(salt, password) {
    const key = crypto.pbkdf2Sync(password, salt, 65536, 16, "sha1");
    return key.toString("base64");
}

который можно запустить как:

const base64_salt = "oFoz+aZuGX5Ad/HAa35HLw==";
const salt = Buffer.from(base64_salt, "base64");

console.log(hash(salt, "13111789"));

также дает мне: On7VbkKDXdz8aTWo5tDBXw==

person Sam Mason    schedule 30.09.2019