December 24th, 2013, 12:43 AM
Problem with CRYPT_BLOWFISH
Not sure why it keeps saying: Match!
It is not supposed to match.
public function index()
public function generate_hash($password=NULL)
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH)
$salt = '$2y$11$' . substr(md5(uniqid(rand(), true)), 0, 22);
return crypt($password, $salt);
public function verify($password, $hashedPassword)
return crypt($password, $hashedPassword) == $hashedPassword;
December 24th, 2013, 05:59 AM
do not use crypt() directly! I'm pretty sure I already told you this several times, but I'll repeat it as often as you want.
Using crypt() properly is very difficult. Almost everybody gets it wrong, even the people who specialize in security.
On a quick glance, I already see 6 massive errors on your part, one of the breaking the whole authentication mechanism. Isn't that a clear warning sign? What more do you need?
Use a library, seriously. When you end up opening your admin account to everybody, the whole bcrypt magic is useless.
I usually recommend password_compat, but it also has some issues currently, so I'll recommend PHPass instead. It's from the same person who wrote the original bcrypt implementation of PHP, and it's very mature.
Cryptography isn't the right place for playing around. It's very different from, say, programming a web application, because you have no margin of error. Screwing up some GUI elements doesn't hurt anyone. Screwing up a password hash does.
For the sake of completeness, those are the errors:
- wrong randomness source, massively weakening the salt
- wrong salt encoding, again weakening the salt
- wrong last digit of salt
- no error checking; you don't even make sure that the hashing actually worked
- wrong comparison technique
- wrong order of arguments
Please note that I'm not suggesting to fix this. I'm suggesting to stop and use a library.
December 24th, 2013, 06:14 AM
I think I'll actually back up Jacques on this one. His vitriol aside, it does kinda look like you're not sure how to use the code, and the reason you're getting the result you are is because of (a) not using the code right and (b) sheer luck.
Passing numbers around? That doesn't make sense: generate_hash() is supposed to take a password you hash (not a number), and the arguments to verify() are respectively the original password (not the hashed password) and the hashed password (not a number).
December 26th, 2013, 10:00 AM
CRYPT_BLOWFISH maybe isn't defined. In that situation, the function returns null regardless of input.
HEY! YOU! Read the New User Guide and Forum Rules
"They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety." -Benjamin Franklin
"The greatest tragedy of this changing society is that people who never knew what it was like before will simply assume that this is the way things are supposed to be." -2600 Magazine, Fall 2002
Think we're being rude? Maybe you asked a bad question
or you're a Help Vampire.
Trying to argue intelligently? Please read this.
December 26th, 2013, 12:34 PM
The problem has been solved.
For those who are interested in the bug itself, the problem is caused by a whole chain of errors:
He has mixed up the arguments and passes the integer 32 to the salt parameter of crypt. This causes the function to apply the ancient DES-crypt algorithm with two digits of salt. Then he uses the weak equality operator on the hash and the number 32. Since the hash happens to begin with the two salt digits, converting it to an integer does in fact yield 32 -- so the comparison is true.
Bugs like this are very common. I'd say that 95% of the people using crypt() directly in fact use it wrong. It's a very error-prone function with exotic requirements and weird behaviour:
- Mistakes will lead to very different reactions, depending on what exactly went wrong. The function may fall back to a weak algorithm (MD5-crypt or DES-crypt), or it may return an invalid hash, or it may return one of the error strings "*0" or "*1".
- The salt must be encoded with a special Base64 variant. Contrary to popular belief, you can't just take common Base64, remove the padding and replace "+" with ".". The crypt Base64 encoding uses completely different digits.
- The salt requirements are somewhat arcane. bcrypt has 22 digits of salt, but only the first two bits of the last digit are used. So the last digit can only be ".", "O", "e" or "u". The current bcrypt implementation will fix the digit for you if you screw it up, but other implementations may be less robust.
- And of course there's all the usual problems of cryptography: choosing a proper randomness source, making sure to not leak timing information etc.
That's why I always recommend to not use this function unless you really, really know what you're doing. It's simply too easy to screw up.