Unable to validate passwordhash+salt created using php password_hash() using jBcrypt

2.3k Views Asked by At

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 ?

1

There are 1 best solutions below

2
On

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

Versions of PHP before 5.3.7 only support "$2a$" as the salt prefix: PHP 5.3.7 introduced the new prefixes to fix a security weakness in the Blowfish implementation. Please refer to » this document for full details of the security fix, but to summarise, developers targeting only PHP 5.3.7 and later should use "$2y$" in preference to "$2a$".

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.