david wong

Hey ! I'm David, a security consultant at Cryptography Services, the crypto team of NCC Group . This is my blog about cryptography and security and other related topics that I find interesting.

How to compare password hashes in PHP? May 2015

The wierdness of ==

Do you know what happens when you run this code in PHP?

var_dump(md5('240610708') == md5('QNKCDZO'));
var_dump(md5('aabg7XSs') == md5('aabC9RqS'));
var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
var_dump('0010e2' == '1e3');
var_dump('0x1234Ab' == '1193131');
var_dump('0xABCdef' == '     0xABCdef');

Check the answer here. That's right, everything is True.

This is because == doesn't check for type, if a string looks like an integer it will first try to convert it to an integer first and then compare it.

More about PHP == operator here

This is weird and you should use === instead.

Even better, you can use hash_equals (coupled with crypt)

Compares two strings using the same time whether they're equal or not.
This function should be used to mitigate timing attacks; for instance, when testing crypt() password hashes.

Here's the example from php.net:

$expected  = crypt('12345', '$2a$07$usesomesillystringforsalt$');
$correct   = crypt('12345', '$2a$07$usesomesillystringforsalt$');
$incorrect = crypt('apple',  '$2a$07$usesomesillystringforsalt$');

hash_equals($expected, $correct);

Which will return True.

But why?

the hashed strings start with 0e, for example both strings are equals in php:

md5('240610708') = 0e462097431906509019562988736854
md5('QNKCDZO')   = 0e830400451993494058024219903391

because php understands them as both being zero to the power something big. So zero.


Now, if you're comparing unencrypted or unhashed strings and one of them is supposed to be secret, you might have potentialy created the setup for a timing-attack.

Always try to compare hashes instead of the plaintext!

Well done! You've reached the end of my post. Now you can leave me a comment :)


Good job, merci!

Michal Špa?ek

Thanks for sharing, if you're interested in more of these "collisions" check out https://github.com/spaze/hashes – it includes all the hashes I've generated so far including these you've used.


cool page michal!


Still can't find the advantage over === anywhere, other than explicitly raising people's awareness of how poorly == works for certain things.