Search code examples
javauser-interfacehashpbkdf2

Java's implementation of PBKDF2 with HMAC SHA1 return different hash every time an button is pushed?


I created a simple GUI with a password field, a enter button and a text area to display generated hash of password when enter button is pushed. But when I press the button again, the hash is change even though input password still the same. I can't compare the input password with the stored one since output hash change every time.

Here is the code:

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;
}

It only return the same hash every time if I call it from main method. Why is that? How to make it return the same value every time I input the same password and push the button?

I think that I find out the problem when covert string to chararray back and forth. Edit method hashPassword to hashPassword(char[] password, String salt) and got it work now.

Somehow when convert String to CharArray, output is different everytime. Here is the test code:

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

It's very strange since pw0 and pw1 are equal "password".toCharArray(). I wonder if there's a bug in String.toCharArray()??


Solution

  • Technically, you call

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

    This will result in

    [C@abcdef10
    

    So what you'll get is always another value everytime you run it.

    What you should do is:

    jTextArea1.append("\nCase1: "+hashPassword(new String(pw0), "salt"));
    ...