Store and validate hashed password with salt

2019-08-09 05:18发布

问题:

I simulate storing password hashes and validate it in login process.

I have a method called hashPassword(String password) to get a String password and returns it's hash with adding of salt.

I choose salt an static value and in this example, i choose an identical value for password (hello123)

public class T1 {

public static void main(String[] args) {
    String userDefinedPassword = "hello123";
    String hashedPassToStoreInDB = String.valueOf(hashPassword(userDefinedPassword));
    System.out.println("what stores in DB: " + hashedPassToStoreInDB);
    // store in database

    //Password Verify
    String inputPassword = "hello123";
    String hashedInputPassword = String.valueOf(hashPassword(inputPassword));
    System.out.println("Users hashed password: " + hashedInputPassword);

    if (hashedPassToStoreInDB.equals(hashedInputPassword)) {
        System.out.println("Correct");
    } else {
        System.out.println("Incorrect");
    }
}

private static byte[] hashPassword(String password) {
    byte[] salt = new byte[16];
    byte[] hash = null;
    for (int i = 0; i < 16; i++) {
        salt[i] = (byte) i;
    }
    try {
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        hash = f.generateSecret(spec).getEncoded();

    } catch (NoSuchAlgorithmException nsale) {
        nsale.printStackTrace();

    } catch (InvalidKeySpecException ikse) {
        ikse.printStackTrace();
    }
    return hash;
}
}

But the result is:

what stores in DB: [B@219c9a58
Users hashed password: [B@305918a5
Incorrect

Why this two value is not identical?

What is wrong with my code?

回答1:

The problem is here:

String hashedPassToStoreInDB = String.valueOf(hashPassword(userDefinedPassword));

and here:

String hashedInputPassword = String.valueOf(hashPassword(inputPassword));

You're creating a String from the byte[] returned from hashPassword method, but using the wrong method. Since there's no overload for byte[] in String#valueOf method, it ends calling String#valueOf(Object obj) which will use Object#toString internally, and the string representation of an array by itself is meaningless.

Use new String(byte[] byteArray) instead.

String hashedPassToStoreInDB = new String(hashPassword(userDefinedPassword));
//...
String hashedInputPassword = new String(hashPassword(inputPassword));


回答2:

You are generating two different instances of a byte[] array, whose String representation follows the one from Object.toString.

Hence the hashes of your two byte[]s are different.

Try comparing Arrays.equals(yourSaltedPassword, yourOtherSaltedPassword) instead.

For instance:

byte[] foo = {1,2};
byte[] bar = {1,2};
System.out.println(foo == bar);
System.out.println(String.valueOf(foo).equals(String.valueOf(bar)));
System.out.println(Arrays.equals(foo, bar));

Output

false
false
true

If you need to store your byte[]s as Strings, you can represent them equally (for equal byte[]s) with Arrays.toString(myByteArray).

The comparisons between the two equal passwords will then return equal Strings.



回答3:

You have stumbled on to the fact that java arrays do not override toString.

Bug why use arrays: You can get a basic salt working by just concatenating strings, then using hashCode() on the result:

int hash = (password + salt).hashCode();


标签: java hash