简体   繁体   中英

Store and validate hashed password with salt

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?

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

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 String s, you can represent them equally (for equal byte[] s) with Arrays.toString(myByteArray) .

The comparisons between the two equal passwords will then return equal String s.

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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM