2

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?

  • On a side note: You should handle passwords as char array instead of Strings: see [here](http://stackoverflow.com/questions/8881291/why-is-char-preferred-over-string-for-passwords) – jHilscher Jan 08 '15 at 16:14

3 Answers3

3

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));
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
0

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.

Mena
  • 47,782
  • 11
  • 87
  • 106
  • So, i need to store user hashed password in `byte` in database, not in `String`, Correct? –  Jan 08 '15 at 15:34
  • 1
    @user3808021 no, you have to use [`new String(byte[])`](http://docs.oracle.com/javase/8/docs/api/java/lang/String.html#String-byte:A-) constructor instead of `String#valueOf(byte[])`. – Luiggi Mendoza Jan 08 '15 at 15:35
  • @user3808021 assuming this is all for test/learning (i.e. real security is out of scope), you can store `Arrays.toString(yourByteArray)`. The comparison will then return equal. – Mena Jan 08 '15 at 15:35
  • @LuiggiMendoza I agree but that couldn't that cause further issues with encoding in this specific context? – Mena Jan 08 '15 at 15:38
  • @Mena you could use `new String(byte[], CharSet)` if needed. – Luiggi Mendoza Jan 08 '15 at 15:43
  • @LuiggiMendoza I know :) Just being picky here. – Mena Jan 08 '15 at 15:45
0

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();
Bohemian
  • 412,405
  • 93
  • 575
  • 722