2

I am new to PHP programming and PHP security issues. Is it safe to hash multiple times a password? Others over the internet said that it brings collisions or it was not safe at all, so my question is can a hashing method be secure if implemented like this. Ihave tried multiple things and combinations and results aren't the same, but does it really make the password more secure?

$input_pass = 'example';
$step1 = md5($input_pass);
$final_pass = hash('sha512',crypt(pi(),hash('sha512',$input_pass)));
Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111
  • 1
    No it does not make it more secure. If you are using php 5.5 look into password_hash function http://php.net/manual/en/function.password-hash.php If you are using less than that look into phpass http://www.openwall.com/phpass/ – Kris Jun 29 '13 at 20:33
  • Yes, it helps against brute force. But like Kris said use the new 5.5 Functions or you can use backport for these function when you have PHP 5.3 or higher. – AlucardTheRipper Jun 29 '13 at 20:38
  • 1
    Pleeeez don't use md5 of sha. Choose a stronger hashing algorithm like bcrypt, scrypt, or PBKDF2, and add salt to it. Also, check out the answers over to the right under Related. – DOK Jun 29 '13 at 20:38
  • Possible duplicate of http://stackoverflow.com/questions/348109/is-double-hashing-a-password-less-secure-than-just-hashing-it-once – Dave Chen Jun 29 '13 at 20:40
  • 2
    How does it help against brute forcing??? – ircmaxell Jun 30 '13 at 23:40
  • This is not strictly a PHP-related or PHP-security related question. PHP is effectively used here simply for codifying sample scenarios. – Erik Kaplun Dec 05 '22 at 09:01

2 Answers2

21

So, to demonstrate why specifically this is a spectacularly bad idea (to put it lightly), let's examine the code that you have:

$input_pass = 'example';

$step1 = md5($input_pass);

Ok, so you generate an MD5, and then completely ignore it...

$t1 = hash('sha512',$input_pass);

Now you hash the password with SHA512

$t2 = crypt(pi(),$t1);

And then run crypt over the output of pi() (as the input for the password field), passing in the SHA512 hash as the "salt" (more on that in a second)

$final_pass = hash('sha512',$t2);

And then hash the entire result a second time...

Now, to see why this is so bad, let's look at the outputs of each step:

$t1 = string(128) "3bb12eda3c298db5de25597f54d924f2e17e78a26ad8953ed8218ee682f0bbbe9021e2f3009d152c911bf1f25ec683a902714166767afbd8e5bd0fb0124ecb8a" 
$t2 = string(13) "3b5PQJpjs2VBk" 
$final_pass = string(128) "ec993177685eb6f2aa687d1202f47f7c5c0e17954fe1409115ed8b2170839029a065a189a3d2af6fe8d05869f7a6980743c199d7eb9d00c7e036af790231549a"

Hmm, wait a second, I wonder something. Let's try changing the password to something else. Say foobar:

$t1 = string(128) "0a50261ebd1a390fed2bf326f2673c145582a6342d523204973d0219337f81616a8069b012587cf5635f6925f1b56c360230c19b273500ee013e030601bf2425"
$t2 = string(13) "0aTQxuCXvbnbY"
$final_pass = string(128) "6cd37aeccd93e17667563fadfae96d50427b5187cffb1c2865ee4bcce76d6c767f2b9b6c542988fd5559efb499d988b204e49b8ed60428db45e2ccb3945f33f2"

Hmmm, interesting. The first 2 characters of $t2 match the first 2 characters of $t1... I wonder if we can use that to exploit this code. Let's build a little brute-forcer to find a random password that collides with the first 2 characters of that SHA512:

$target = '3b';

$runs = 0;

do {
    $runs++;
    $pass = genRandomPass();
    if ('3b' == substr(hash('sha512', $pass), 0, 2)) {
        echo "Found match: $pass\n In $runs Runs\n";
        die();
    }
} while (true);

function genRandomPass() {
    $length = mt_rand(8, 12);
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $charLen = strlen($chars);
    $result = '';
    for ($i = 0; $i < $length; $i++) {
        $result .= $chars[mt_rand(0, $charLen - 1)];
    }
    return $result;
}

And running it:

~$ time php test.php 
Found match: olhUhIWp5Xd
 In 49 Runs

real    0m0.013s
user    0m0.004s
sys     0m0.012s

Woah! In 0.013 seconds, it picked a random collision!!! Let's try it out:

$t1 = string(128) "3ba21ea28adb4543755bf62133eb0337569170c90ae4f3eaca9b777bf88f3a2eb9f9d0e40e4ff9e8844814ac7944ccf61e2222c184ebbf91e43fcdc227c80416"
$t2 = string(13) "3b5PQJpjs2VBk"
$final_pass = string(128) "ec993177685eb6f2aa687d1202f47f7c5c0e17954fe1409115ed8b2170839029a065a189a3d2af6fe8d05869f7a6980743c199d7eb9d00c7e036af790231549a"

Yup! In 0.013 seconds of CPU time, I just found a collision for that hash method.

WHY

Your hash will be limited by the narrowest component. You're incorrectly feeding the password into the salt component of crypt() when using CRYPT_DES (which is horrifically weak).

So that means that all of the entropy of the password is being put into 2 characters. 2 characters that have 64 combinations each. So the total possible entropy of your end hash is 4096 possibilities, or 12 bits.

Compare that to bcrypt which provides 576 bits of entropy, and you can see why it's bad...

Conclusion

As I've said before: Face It, Cryptography Is Hard, Don't try to invent something yourself, but use a library. There are plenty available.

There is just absolutely no valid reason to invent it yourself...

Check This Answer for a breakdown of the different libraries available (that are currently recommended).

Community
  • 1
  • 1
ircmaxell
  • 163,128
  • 34
  • 264
  • 314
  • 1
    But it still helps keeping original password secured, doesn't it? – zerkms Jul 01 '13 at 00:43
  • 1
    @zerkms: depends on your definition of secured. It unlocks this application. Also, let's imagine that an attacker got this database and another BCRYPT hashed database. And that a user used the same password in each. The attacker could use this database as a Bloom Filter towards which candidates to try against bcrypt. Cutting his time to attack the BCrypt database down by a factor of 4096... Which is singificant.... – ircmaxell Jul 01 '13 at 00:56
4

No it doesn't make it more secure. A hashing algorithm doesn't care that it's hashing plaintext or another hash. If I recall, sometimes multiple hashing is used in larger security protocols for encryption (I forget the details...) But just using the hashing algorithm to store passwords, it doesn't make it more secure.

For more secure passwords, however, you will want to look into salting your passwords (https://en.wikipedia.org/wiki/Salt_(cryptography)). If your site were ever compromised and data stolen, salting will help protect against certain kinds of attacks to crack the stored passwords.

dsw88
  • 4,400
  • 8
  • 37
  • 50
  • e.g.: $final_pass = crypt('example', '$6$somesalt$'); Where "somesalt" is a random String consisting of a-zA-Z./ No need for hash() at all and the hashes are compatible with other programming languages or databases as all know crypt(). – lathspell Jun 30 '13 at 21:58