We are migrating our authentication module from PHP to Java. Currently the password hash+salt is stored in the database using BCrypt algorithm. This value is generated by using PHP's password_hash() function. For validating plain text password, we are using PHP's password_verify() function.
PHP code
$hash = password_hash($password,PASSWORD_DEFAULT); //stored in db
if(password_verify($candidate,$hash)===TRUE) { //$hash fetched from DB
echo "valid";
}
For migrating this auth module to Java, we are using jBCrypt library by using jBCrypt-0.4.jar
Java code
private static String hashPassword(String password) {
String hashed = BCrypt.hashpw(password, BCrypt.gensalt());
return hashed;
}
private static boolean checkpasword(String candidate, String hashed){
boolean matches = false;
if (BCrypt.checkpw(candidate, hashed)){
matches = true;
}
return matches;
}
However, the passwordhash+salt generated from php is not being validated in java. For the string 'abcd' , the hash+salt generated is
PHP - $2y$10$SA4iLMAniuNO6p9P1ZJElePaJvlN5eHGZ2dDt2Mutle4FQr1OY4hC
Java - $2a$10$YnqJT5NPCPTI8qKBbLfgIOIOW4eckdbE1R85tJGNRUJKmxz1TLkWG
When I tried matching the string generated using PHP in Java using
if (BCrypt.checkpw("abcd", "$2y$10$SA4iLMAniuNO6p9P1ZJElePaJvlN5eHGZ2dDt2Mutle4FQr1OY4hC")){
matches = true;
}
I was getting the below
Exception in thread "main" java.lang.IllegalArgumentException: Invalid salt revision at org.mindrot.jbcrypt.BCrypt.hashpw(BCrypt.java:665) at org.mindrot.jbcrypt.BCrypt.checkpw(BCrypt.java:764)...`
How do I make both compatible ?
The hash generated by
password_hash()
in PHP includes the salt. Which means when you're checking it against the plain-text password, the same salt is used to generate a hash against the plain-text password, and the two hashes are compared in a constant time manner for verification.What you're doing in Java is generating a different salt each time, which means you can't compare the two. Your Java implementation is using a different version, denoted by the
$2a$
in your hash. Notice PHP is using$2y$
and the salts are clearly different.From the PHP manual
So you shouldn't be generating a new hash in Java to validate the existing hash that was generated by PHP and stored in your database. Instead, supply the stored hash to
BCrypt.checkpasword
for validation.