Search code examples
phphashpasswordscrypt

Crypt function outputting two different values depending on PHP version


Using the password "testtest" and the hash "KFtIFW1vulG5nUH3a0Mv" with the following code results in different hashes depending on the PHP version (as shown in the image below):

$salt = "KFtIFW1vulG5nUH3a0Mv";
$password = "testtest";

$key = '$2a$07$';
$key = $key.$salt."$"; 

echo crypt($password, $key);

Output 1 (PHP v.5.3.0 - 5.4.41, 5.5.21 - 5.5.25, 5.6.5 - 5.6.9): $2a$07$KFtIFW1vulG5nUH3a0Mv$.0imhrNa/laTsN0Ioj5m357/a8AxxF2q

Output 2 (PHP v.5.5.0 - 5.5.20, 5.6.0 - 5.6.4): $2a$07$KFtIFW1vulG5nUH3a0Mv$e0imhrNa/laTsN0Ioj5m357/a8AxxF2q

Here is an example of the problem: http://3v4l.org/dikci

This is a massive issue if crypt is being used to hash passwords for a login, as depending on PHP version the hash will be different. Anybody understand what this issue is from and how to deal with it?

enter image description here


Solution

  • This is not so much an issue as you may think.

    First you should note, that your code is not absolutely correct, BCrypt requires a 22 character salt, but you provided a 20 character salt. This means that the terminating '$' (which is not necessary btw) will be seen as part of the salt, as well as the first letter of your password. The $ is not a valid character for a BCrypt salt though.

    Another thing to consider is that not all bits of character 22 are used, this is due to the encoding, ircmaxell gave a good explanation about this. So different salts can result in the same hash, you can see this well in this answer. How different implementations handle this last bits of the character 22 could theoretically change. As long as the crypt function can verify the password with both hashes there is no problem.

    The generation of the salt with its pitfalls is one of the reasons, why the functions password_hash() and password_verify() where written, they make the password handling much easier.