phpinicryptblowfish

How to check php.ini / php settings about crypting (BLOWFISH)


My websites's user login function suddenly stopped working on a rented server( web hosting service) ( It worked wonderfully before for YEARS.) Because I didn't changed anything, the database is also untouched (not hacked or altered), i thought maybe something happened with the PHP settings or modules on the server (because it's a rented server I cannot reach the config files) The server's helpdesk team told me they did nothing / didn't upgrade. ( they don't want to help me solve this. )

As far as I could research the crypt() function "stopped working" (gives back *0 instead of the correct hash as before).

I tried to google for information about how to check the server side settings about or state of crypting / BLOWFISH, but I couldn't find anything, so any help is greatly appreciated!

The salt that worked million times before is look like this:

$salt=  '$2a$05$2m6Jboi4zN5V2F/bvUCpH$' ;
$hashed_password = crypt($login_password,$salt);

It doesn't work with my admin login either ( the login credentials are 100% correct )

The users and admin cannot login, the systems tells them the credentials are wrong, which is caused by the checking /matching of a non-existing hash (*0) produced by the crypt() function. ( $password_hash_from_database !== $hashed_password_provided_by_crypt )

Server PHP version is 7.3

Thank you in advance


Solution

  • I'm not very sure, but it's probably because of this security patch: BCrypt hashes erroneously validate if the salt is cut short by `$. Although the version it mentions does not involve PHP 7, due to this being a security vulnerability and easy to fix, it is estimated that your server administrator has applied this patch to your PHP.

    Here's a workaround, use $2a$05$2m6Jboi4zN5V2F/bvUCp.. instead of your salt. You will obtain the same encryption result, then to replace the salt part in the result with $2a$05$2m6Jboi4zN5V2F/bvUCpH.. then to compare the hashed results except for the first 29 characters.

    $salt2 = '$2a$05$2m6Jboi4zN5V2F/bvUCp..';
    $hashed_password = crypt($login_password, $salt2);
    if(substr($hashed_password, 29) === substr($hashed_password_indb, 29))
    ...
    

    Explanation to the workaround.

    The last $ in your old salt $2a$05$2m6Jboi4zN5V2F/bvUCpH$ is not a valid character, according the manual, the valid characters are ./0-9A-Za-z.

    The blowfish algorithm in PHP will convert the last 22 characters of the salt into 4 ints in groups of 4 characters (check the source code)

    Because of the vulnerability, the last $ and the preceding H are actually discarded, and these two bytes will be treated as 0 in actual calculations (. is the first valid character, so it will be treated as 0). If $ is in another position, there are more digits to be discarded. You can check the following example for comparison:

    $login_password = '123345345SDFHSD3453';
    $salt1 = '$2a$05$2m6Jboi4zN5V2F/$vUCpH8';
    $salt2 = '$2a$05$2m6Jboi4zN5V2F........';
    $hashed_password1 = crypt($login_password, $salt1);
    $hashed_password2 = crypt($login_password, $salt2);
    
    # $hashed_password1 & $hashed_password2:
    # $2a$05$2m6Jboi4zN5V2F/$vUCpHu4CWNoXuc3r8QkJHciPMdM3J.4y2lS.S
    # $2a$05$2m6Jboi4zN5V2F........4CWNoXuc3r8QkJHciPMdM3J.4y2lS.S
    

    The first 29 characters are the salt, so it's not necessary to take care of them.