0

I'm using pbkdf2 to hash my passwords. I take a plain string password, I generate a salt, and I hash it like this:

byte[] salt = SecureRandom.getSeed(16);

KeySpec spec = new PBEKeySpec(
            password.toCharArray(),
            salt,
            iterations,
            keyLength * 8
            );
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");

byte[] generatedSecret = f.generateSecret(spec).getEncoded();

Then I save the salt (BINARY(64)) and the hashed password (BINARY(255)) inside my MySQL table using prepared statement SELECT.

When I try to validate a user, I first fetch the salt, with it I generate the password hash and I use it inside the SELECT query for the user. The salt gets fetched correctly and is the same every time, but the generated hash is always different.

I reproduced it here

Edit: in the link above the error is indeed the fact that I have to use Arrays.equals(a, b) to compare two byte[].

leverglowh
  • 734
  • 1
  • 7
  • 23
  • `byte[]` does not have a `equals` that looks at the actual contents of the array and compares them. Two byte arrays are only equal if they are the actual java object. – luk2302 Jun 14 '20 at 15:01
  • The problem is not the equals, I use the generated hash inside my SELECT query and that fails, which means the generated hash is actually different from the one saved in db. I tried quering with the salt which is fine, so the problem is not how I handle `byte[]` – leverglowh Jun 14 '20 at 15:07
  • Then the select is the problem. The linked code *does* produce the same hash every time, as is totally expected. Don't know what db you use and wether or not they can compare binary properly. I would not do that in the select at all. You already have a query on the db to get the salt. There is no reason to select a second time afterwards, just retrieve the salt and the hash at once, generate the current hash and compare them in java. Performing two db requests is actually a bad thing. – luk2302 Jun 14 '20 at 15:08
  • I apologise, `Arrays.equals` does return true, my bad. The reason I chose to make separate queries is because I though it was bad to fetch information about the user before validating them, does it not matter? – leverglowh Jun 14 '20 at 18:35
  • No, that does not matter. Fetch whatever you want. If you do not trust your app to handle the user data properly why would you trust your application to not just `return true` in the `hasUserEnteredTheCorrectPassword(...)` method? – luk2302 Jun 14 '20 at 18:48

1 Answers1

0

My problem is the fact that MySQL fills the byte[] with zeros when I INSERT both salt and password as BINARY() so when I fetched it, they all have trailing 0s. I fixed my problem by changing my salt and password length to match the db.

leverglowh
  • 734
  • 1
  • 7
  • 23