Реализация PBKDF2 в Java с HMAC SHA1 возвращает разные хеши каждый раз, когда нажимается кнопка?

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

Вот код:

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public PBKDF2() {
    initComponents();
}

private void initComponents() {//"Generated Code"
...... 
}

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
    password= jPasswordField1.getPassword();
    jTextArea1.setText(null);
    try {
        jTextArea1.append(hashPassword(password.toString(), "salt"));
    } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
        Logger.getLogger(PBKDF2.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new PBKDF2().setVisible(true);
            }
        });
    }

 public static String hashPassword(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException{
    char[] pw = password.toCharArray();
    byte[] slt = salt.getBytes(StandardCharsets.UTF_8);
    PBEKeySpec spec = new PBEKeySpec(pw,slt,2000,160);
    SecretKeyFactory key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    byte[] hashedPassword = key.generateSecret(spec).getEncoded();
    return String.format("%X", new BigInteger(hashedPassword));
  }

    public static char[] password;
    public javax.swing.JButton jButton1;
    public javax.swing.JPasswordField jPasswordField1;
    public javax.swing.JScrollPane jScrollPane1;
    public javax.swing.JTextArea jTextArea1;
}

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

Я думаю, что я узнаю проблему, когда скрывает строку в chararray туда и обратно. Измените метод hashPassword на hashPassword (char [] пароль, String salt) и теперь он работает.

Каким-то образом при преобразовании String в CharArray вывод каждый раз разный. Вот тестовый код:

Code:
char[] pw0="password".toCharArray();
char[] pw1="password".toCharArray();

jTextArea1.append("\nCase1: "+hashPassword(pw0.toString(), "salt"));
jTextArea1.append("\nCase2:"+hashPassword(pw1.toString(), "salt"));

Result:        
Case1: -48b7cb730ce85dd46cb2cac6960eb1971f2d30e4
Case2:64765fbdada52d536d89bf2fac72b058397e9ec9

Это очень странно, так как pw0 и pw1 равны "паролю".toCharArray(). Интересно, есть ли ошибка в String.toCharArray()??


person Luke Martin    schedule 25.03.2016    source источник
comment
Соленый хэш, по определению, каждый раз разный — и не без причины. Почему вы ожидаете, что они будут одинаковыми? Если это то, чего вы хотите, давайте каждый раз одну и ту же соль. Но, пожалуйста, не делайте этого на производстве.   -  person fge    schedule 25.03.2016
comment
@fge, одна и та же соль должна возвращать одно и то же хэш-значение.   -  person A.Grandt    schedule 25.03.2016
comment
Начните с упрощения задачи и просто протестируйте метод hashPassword, вызвав его с фиксированными значениями из основного метода, и напечатайте вывод в System.out.   -  person A.Grandt    schedule 25.03.2016
comment
@A.Grandt Я думаю, что нашел проблему: при преобразовании пароля (char) в строку происходит ошибка.   -  person Luke Martin    schedule 25.03.2016
comment
@LukeMartin, это еще одна вещь, не преобразовывайте пароль в строку, просто сохраните его как массив символов, который вы получаете из поля пароля.   -  person A.Grandt    schedule 25.03.2016
comment
Фактически вы хэшируете объект hashCode() вместо фактического пароля.   -  person rkosegi    schedule 25.03.2016


Ответы (1)


Технически, вы звоните

"abc".toCharArray().toString();

Это приведет к

[C@abcdef10

Так что вы всегда будете получать другое значение каждый раз, когда вы его запускаете.

Что вы должны сделать, это:

jTextArea1.append("\nCase1: "+hashPassword(new String(pw0), "salt"));
...
person Olivier Grégoire    schedule 25.03.2016