Search code examples
phpsalt-cryptographybcryptpassword-hashphp-password-hash

PHP password_hash function salt length 21 or 22?


Code:

echo password_hash("stackoverflow", PASSWORD_DEFAULT, ['salt' => 'twenty-one-characters'] );

Result:

Warning: password_hash(): Provided salt is too short: 21 expecting 22 

code:

echo password_hash("stackoverflow", PASSWORD_DEFAULT, ['salt' => 'twenty-one-charactersA'] );

Result:

$2y$10$dHdlbnR5LW9uZS1jaGFyYOVyX13hK9eb4/KXMAkHsAJX..YR7t/32

code:

echo password_hash("stackoverflow", PASSWORD_DEFAULT, ['salt' => 'twenty-one-charactersB'] );

$2y$10$dHdlbnR5LW9uZS1jaGFyYOVyX13hK9eb4/KXMAkHsAJX..YR7t/32

Question:

As you see, by appending A and B to 21 character strings we created two different salts of 22 characters, but, the HASHES are same! That is the 22nd character is ignored? If it is ignored then why does it ask for 22 character salt?


Solution

  • First, please don't provide your own salt. You're not going to do a better job generating it than the library does. And using static salts (like you did in the example) will compromise security. Just let it generate its own salt (incidentally, I believe letting a salt in is the biggest mistake I made in that API).

    As far as 21 vs 22 characters, give this answer a read.

    Basically, the salt is base64 encoded. This means that every 6 bits of the salt is encoded into 8 bits. So every byte of encoded salt is 6 bits.

    21 characters is 126 bits. That means that only part of the 22nd character is used (the first 2 decoded bits). The reason you get the same hash with A and B, is that the leading 2 bits are the same for both characters.

    In fact, there are only 4 unique hashes for the 22nd byte.