php crypt() blowfish salt length backward compatib

2019-02-17 12:55发布

问题:

I used crypt() to hash password, with a blowfish salt like this:

$2a$, 2 digits, $, 21 chars in [a-zA-Z0-9]

Here I made a mistake that chars length after third $ is 21 not 22. But it worked fine so I didn't find the error.

It works on my desktop which running windows and php 5.4.4 and on AWS ec2 which running Amazon linux with php 5.3.x, with that too short salt.

One day I updated AWS php to 5.5.14. then the problem occurred. crypt() return *0 all the time.

After some try, I added a $ at end of the salt so , it become 22 chars. And it works again and return the same hash string as before. Although it doesn't obey the blowfish rule, chars should be [./a-zA-Z0-9]

But now I duplicate this site to another machine which running openSuSE 13.1 with php 5.5.14, This salt failed again.

I downgrade php to 5.4.20 but not help.

The new site still need old database so I have to make that password hash works.

What is the library or module that effect this blowfish salt length error compatibility issue? Tt seems not PHP's version. AWS 5.5.14

Or is there another magic char can save me again? I tried replace th tail $ to each one in [./a-zA-Z0-9] but no lucky, the hash string is different ....

回答1:

First i would strongly recommend to use the new functions password_hash() and password_verify() to generate and verify new hashes. Of course this doesn't solve your actual problem with the old hashes, but it may be a good idea to mark them as old, so they can be updated the next time the user logs in.

For this old hashes i would try to verify them, generating a salt with a valid last character 22. The crypt function does actually use only part of the bits of character 22 (126 bits of the salt instead of 128). So groups of the last character 22 will end up in the same hash-value.

See the answer to this question Why does crypt/blowfish generate the same hash...

If you try out all relevant characters [.Oeu] as the character 22, the chance is good that one combination will generate the same result as your invalid salt.

EDIT:

Since the used salt becomes part of the password-hash, you should be able to see what was used as character 22 (the 22th character after the third $).



回答2:

Using (again) '$' as the last character should make your passwords work if you downgrade to PHP 5.4.

This is however, not a long-term solution. Using '$' as the last character has made all your passwords forward-incompatible, because that's not a valid Base64 character (regardless of whether that's regular or bcrypt-compatible Base64).

For as long as you can use PHP 5.4, and that means as long as PHP 5.4 is officially supported, you should re-hash all old passwords whenever they are used. After PHP 5.4 support is dropped, you'll have no other choice but to just generate new random passwords for your users who've remained with the old hashing scheme and e-mail them.

I must also suggest that you use the password-compat package for your updated passwords. It will give you the password_*() functions that are otherwise available only on PHP 5.5+. The package's author is the same person who implemented the functions in PHP itself, so you can be sure that it is both safe and 100% compatible, providing you with forward-compatibility when you upgrade to 5.5+.