I'm having some difficulty producing the same encrypted password using the PBKDF2 algorithm on both Java and PHP.
I'm using the following Java implementation to generate the hash with a random byte array which is 16 bytes in size. I'm then storing the hash and salt separately in a MySQL database, however when I go to do the same operation in PHP using the salt retrieved from the database, I get almost the exact same encryption except the hash has a leading 0 and I cannot for the life of me figure out why.
Java:
public String hashPassword(String password, byte[] salt){
char[] passwordChars = password.toCharArray();
PBEKeySpec spec = new PBEKeySpec(
passwordChars,
salt,
ITERATIONS,
KEY_LENGTH
);
SecretKeyFactory key = null;
try {
key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] hashedPassword = null;
try {
hashedPassword = key.generateSecret(spec).getEncoded();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return String.format("%x", new BigInteger(hashedPassword));
}
I found the above code at https://adambard.com/blog/3-wrong-ways-to-store-a-password/
PHP:
$query = $database->query('SELECT * FROM USERS');
$password = 'hello';
$iterations = 1000;
foreach($query as $user){
$hash = hash_pbkdf2("sha1", $password, $user['salt'], $iterations, 40, false);
}
echo $hash;
Note: There is only one user stored in the database, I know the above code isn't great, I created it quickly for testing purposes.
For both implementations I'm using an iteration count of 1000, a key length of 160 in Java and a key length of 40 in PHP (to compensate for setting raw-output to false)
Java Output - 971f0dddc1bc2e899f2bca178f16ea79bfbbb13
PHP Output - 0971f0dddc1bc2e899f2bca178f16ea79bfbbb13
Any help is much appreciated, thank you.
It is the BigInteger
that is killing the leading 0.
Hashes are not integers, they are an array of 8-bit bytes. Do not try to convert to a BigInteger
.
Either use it as a byte[]
or encode as a hexadecimal or Base64 string. To match PHP hexadecimal encode hashedPassword
.
PHP is returning a hexadecimal string encoded hash because raw_output
is set to FALSE
.