|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #62372 crypt() and broken backwards compability in SHA rounds
Submitted: 2012-06-20 10:58 UTC Modified: 2014-07-19 02:03 UTC
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: jani dot ollikainen at mmd dot net Assigned: yohgaki (profile)
Status: Wont fix Package: *Encryption and hash functions
PHP Version: * OS: *
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2012-06-20 10:58 UTC] jani dot ollikainen at mmd dot net

"CRYPT_SHA512 - SHA-512 hash with a sixteen character salt prefixed with $6$. If the salt string starts with 'rounds=<N>$', the numeric value of N is used to indicate how many times the hashing loop should be executed, much like the cost parameter on Blowfish. The default number of rounds is 5000, there is a minimum of 1000 and a maximum of 999,999,999. Any selection of N outside this range will be truncated to the nearest limit."

Why is that N put to minium of 1000? Now if I've made hash with old PHP (or with anything else) which has "$6$rounds=10$" I cannot check that, because if there's rounds mentioned PHP will do minimum of 1000 rounds and I get totally different hash to compare.

Sounds very nice! I can understant that rounds limit if I don't give salt to crypt(), but if I give a salt which has "$6$rounds=10$" it really should do just those 10 rounds!

Fails with:
PHP 5.4.4 (cli) (built: Jun 20 2012 13:48:48)
PHP 5.3.14 (cli) (built: Jun 20 2012 13:39:44)
PHP 5.3.3 (cli) (built: May  7 2012 19:58:17)

Works with:
PHP 5.1.6 (cli) (built: May  7 2012 15:03:06)

Test script:
echo "HASH: $h - CRYPT: $c\n";
if ($c == $h)
  echo "MATCH OK\n";
  echo "NO MATCH\n";

Expected result:
HASH: $6$rounds=10$qNElXs2yMnL2.GNS3kiM7DqmGbFLdQfIwu2691aJgT3xgJazPLtw7RPKz3Dp8RIc4b5fmJ7qvlq/mPN8a.rE40 - CRYPT: $6$rounds=10$qNElXs2yMnL2.GNS3kiM7DqmGbFLdQfIwu2691aJgT3xgJazPLtw7RPKz3Dp8RIc4b5fmJ7qvlq/mPN8a.rE40

Actual result:
HASH: $6$rounds=10$qNElXs2yMnL2.GNS3kiM7DqmGbFLdQfIwu2691aJgT3xgJazPLtw7RPKz3Dp8RIc4b5fmJ7qvlq/mPN8a.rE40 - CRYPT: $6$rounds=1000$qNElXs2yMnL2.GNS$/q7trYkbKkoJernsumbObt2IysdXGRx/ytFaG0HBC97rHHhYRQvUcyEuRHP6h5yj8V.fH7XKEw5hjofVmYONw1


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2012-06-20 11:44 UTC] jani dot ollikainen at mmd dot net
Tested with patched 5.4.4 where:
#define ROUNDS_MIN 1

HASH: $6$rounds=10$qNElXs2yMnL2.GNS3kiM7DqmGbFLdQfIwu2691aJgT3xgJazPLtw7RPKz3Dp8RIc4b5fmJ7qvlq/mPN8a.rE40 - CRYPT: $6$rounds=10$qNElXs2yMnL2.GNS$YwaYQmhwsN2RzBImxlEjIL.0/YLlfYCDmyfozkCQWNKdKgZQtTpK3Y/TAw31deCnJrDzgrqpI6ckvJCBsoeNB/

So problem isn't only in ROUNDS_MIN. Also I know that my hash hasn't $ after salt, but that's how PHP 5.1.6 creates it. Tested also with adding $ and result is similar:

HASH: $6$rounds=10$qNElXs2yMnL2.GNS$3kiM7DqmGbFLdQfIwu2691aJgT3xgJazPLtw7RPKz3Dp8RIc4b5fmJ7qvlq/mPN8a.rE40 - CRYPT: $6$rounds=10$qNElXs2yMnL2.GNS$YwaYQmhwsN2RzBImxlEjIL.0/YLlfYCDmyfozkCQWNKdKgZQtTpK3Y/TAw31deCnJrDzgrqpI6ckvJCBsoeNB/

So something else is also different...
 [2012-06-20 19:32 UTC] arjen at react dot com
Looks like PHP <= 5.1.7 has a limit on the saltstring of 9 chars.
If no $rounds is specified AND a salstring of 9 chars, all versions return the 
same hash: (2nd line, 1st line is with long hash).
 [2012-06-20 20:33 UTC] jani dot ollikainen at mmd dot net
Oh now I get what I did wrong with PHP 5.1.6. It doesn't understand rounds at 
all, it's just looks like it does, but it uses it as salt and new PHP doesn't 
allow = in salt, so it doesn't work as they see different salt in it. So the 
compatibility issue is with salt string, not in rounds at all. 

This can be work around in PHP 5.1.6 not to use salt's which newer versions 
don't understand, but if you already use them, then you're in big trouble.

Another one is that if I have password like:
The hash is generated with patched PHP 5.4.4 with ROUNDS_MIN 1, but it could be 
from some other system. PHP cannot verify it, as the rounds limit 1000 is 
enforced. To me enforcing it seems to limit compability.
 [2013-02-26 08:23 UTC] m dot staab at complex-it dot de
I have the very same issues. Updating from PHP5.2.4 to PHP5.4.11 and now my passwords which were hased using PHP5.2.4 do not match any longer on PHP5.4.11.

I found no way how to re-produce passwords on PHP5.4.11 like they were generated on PHP5.2.4 and therefore I have no way to upgrade users which already have a password to a newly generated with PHP5.4.11..

The only way I can think of is a password-reset for all of our users?!
 [2014-07-15 22:47 UTC]
-Status: Open +Status: Verified -Operating System: +Operating System: * -PHP Version: 5.4.4 +PHP Version: *
 [2014-07-15 22:47 UTC]

HASH: $6$rounds=10$qNElXs2yMnL2.GNS3kiM7DqmGbFLdQfIwu2691aJgT3xgJazPLtw7RPKz3Dp8RIc4b5fmJ7qvlq/mPN8a.rE40 - CRYPT: $6$rounds=1000$qNElXs2yMnL2.GNS$/q7trYkbKkoJernsumbObt2IysdXGRx/ytFaG0HBC97rHHhYRQvUcyEuRHP6h5yj8V.fH7XKEw5hjofVmYONw1

rounds became 10 to 1000.
 [2014-07-15 23:00 UTC]
-Assigned To: +Assigned To: yohgaki
 [2014-07-19 02:03 UTC]
-Status: Verified +Status: Wont fix
 [2014-07-19 02:03 UTC]
This issue will not be addressed.
Users who has obsolete password data should migrate their password data before upgrades. i.e. Update password hash upon successful login. Ask users to reset password who have not logged in. Developers can use password_needs_rehash() for this.

This bug is related to
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Tue May 11 12:01:23 2021 UTC