php crypt() blowfish salt length backward compatible
Asked Answered
K

2

6

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 ....

Kilmarx answered 17/7, 2014 at 9:39 Comment(5)
Instead of generating the salt yourself why don't you use PHP's hashing functions?Tannenwald
Exist system need to work still.Kilmarx
"But now I build another site in openSuSE 13.1 with php 5.5.14, This salt failed again."<-- There is no reason at all why you cannot use the proper tools for the job thereTannenwald
That's same system. just copy to another machine with different Linux distribution, using old database. Anyway that's that the point of my question.Kilmarx
I edit my question to make it more clear. Thanks for response.Kilmarx
M
2

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 $).

Monteverdi answered 17/7, 2014 at 10:25 Comment(8)
no luck. I tried all allowable char. Btw the salt part of hash only include 21 chars. the 22th char is not the correct 22th salt ...Kilmarx
@JackyJou - How do you know that the salt only contains 21 chars? The crypt function could have taken some bits from the '$' or padded it. Could you show us such a hash, one that you know the password of, but is not used by a user?Monteverdi
the hash was '$2a$13$xxxxxB9EUUAe7wKKdye36', and work at beginning. on AWS php 5.3.x and my Windows 5.4.4Kilmarx
@JackyJou - Is this the whole hash(?), it should always have a length of 60 characters.Monteverdi
the hash was '$2a$13$xxxxxB9EUUAe7wKKdye36', and work at beginning. on AWS php 5.3.x and my Windows 5.4.4 after I update AWS php to 5.5.14, the return hash always is *0, and I fixed the salt to '$2a$13$xxxxxB9EUUAe7wKKdye36$', that solved problem. But now it failed on openSuSE 13.1 again, always return *0 , which is running PHP 5.5.14 or PHP 5.4.20.Kilmarx
it's salt, not hashed string.Kilmarx
@JackyJou - Ok i meant how the whole hash of a password looks like, with all 60 characters, when you hashed it with the trailing '$'.Monteverdi
Let us continue this discussion in chat.Kilmarx
C
1

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+.

Commissary answered 17/7, 2014 at 11:30 Comment(2)
use '$' does't work on openSuSE 13.1 with it's supporting php 5.4 or 5.5, but works on AWS ec2 which is php 5.5 .... I am so confuse ...Kilmarx
Hmm ... Well, crypt() does rely on the operating system's underlying APIs, so technically having PHP 5.5 doesn't even guarantee Blowfish availability. I don't see how you'd have it working with '$' on a regular PHP 5.5 setup though, I'm baffled by this.Commissary

© 2022 - 2024 — McMap. All rights reserved.