HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpModerate

Password hashing method

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
hashingmethodpassword

Problem

I am having some issue to use PHP5 password_hash() function. My server is not supporting it, so I am using a function to hash. Is this one secure?

public function Pass_Hash ($password) {

      $blowfish_salt = bin2hex(openssl_random_pseudo_bytes(22));
      $hash = md5(crypt($password, "X1;G^COU8U`Bo*A6@9<on5yQ6P87M]".$blowfish_salt)); 
      return $hash;

}


I read lot of articles regarding password hashing. Can anyone help me rewrite it more securely?

Solution

NO NO NO NO NO!

Besides what others have pointed out, I find some serious flaws in your code.

  • You are not actually using blowfish. To use blowfish, your salt must begin with something like $2y$07$ see the PHP Documentation



  • Removing your $blowfish_salt variable from the code makes no difference! This will produce the same output. Therefore, we conclude that you are actually using a constant salt in your code.



  • The output of crypt is more secure than MD5. MD5 is an algorithm that is known to have a lot of duplicates. Many different inputs will produce the same results. That's not optimal. Using real blowfish algorithm is even more secure than what you currently have.



Here is some testing code I used to come to my conclusions:

";

$first = crypt($password, "X1;G^COU8U`Bo*A6@9";

$hash = md5($first); 
echo $hash . " ... md5-ed version of above. This is the result of your current code";
echo md5(crypt($password, "X1;G^COU8U`Bo*A6@9";

$first = crypt($password, "X1;G^COU8U`Bo*A6@9";

$first = crypt($password, $blowfish_salt);
echo $first . " ... only blowfish salt";
echo "";
echo "BELOW USING 2Y PADDING:";
echo "";
$first = crypt($password, "\$2y\$07\$X1;G^COU8U`Bo*A6@9";

$first = crypt($password, "\$2y\$07$\X1;G^COU8U`Bo*A6@9";

$first = crypt($password, "\$2y\$07\$".$blowfish_salt);
echo $first . " ... only blowfish salt. And now THAT is blowfish!";

echo "";
echo "Now back to md5 with this result again:";

$hash = md5($first); 
echo $hash;
?>


The output of this is:

salt is 11b19e4e03d32f27f9db5646e56f63458113e9da56f7
X154A2VqJVf4I ... constant with what you call blowfish
7b5f3730488255efcff9441a238d5c5d ... md5-ed version of above. This is the result of your current code
7b5f3730488255efcff9441a238d5c5d ... and oops, that was exactly the same!
X154A2VqJVf4I ... constant salt
11Xw1fe5HDjyo ... only blowfish salt

BELOW USING 2Y PADDING:

*0 ... a lot, with blowfish. Causes error because salt is too long
*0 ... constant salt. Still causes error because salt is too long
$2y$07$11b19e4e03d32f27f9db5uyeLJeUJh/VUoi1RFtAoDAE.eegj4bwO ... only blowfish salt. And now THAT is blowfish!

Now back to md5 with this result again:
e35cb490b47d3211dac9f85acfc2fb15


Please, take your time and study these results. Look at the code. Look at the results. Look at the code again. Look at the results again. Now look at the code one more time: Do you see the flaws? If you don't, I pointed them out at the beginning of my answer.

What you should do:

  • Generate a salt, store that somewhere (as suggested by Chris). Get rid of that constant-salt you have.



-
Use the real blowfish, and don't use MD5 afterwards

public function Pass_Hash ($password, $blowfish_salt) {
      $hash = crypt($password, "\$2y\$07\$" . $blowfish_salt)); 
      return $hash;
}
$generated_salt = bin2hex(openssl_random_pseudo_bytes(22));
Pass_Hash("a very secret password", $generated_salt);


Now we're talking.

However, I should add that I am not a security experts. There are likely several more aspects that one can think of. If you are interested in security and secure stuff, I recommend paying our StackExchange friends at Information Security a visit. But in the end I think that the question is: How secure do you want to be?

Code Snippets

<?php
$password = "bubu";
  $blowfish_salt = bin2hex(openssl_random_pseudo_bytes(22));

$blowfish_salt = "11b19e4e03d32f27f9db5646e56f63458113e9da56f7"; // Since this is the only randomness, I have replaced the randomness with this constant.

echo "salt is $blowfish_salt<br />";

$first = crypt($password, "X1;G^COU8U`Bo*A6@9<on5yQ6P87M]".$blowfish_salt);
echo $first . " ... constant with what you call blowfish<br />";

$hash = md5($first); 
echo $hash . " ... md5-ed version of above. This is the result of your current code<br />";
echo md5(crypt($password, "X1;G^COU8U`Bo*A6@9<on5yQ6P87M]")) . " ... and oops, that was exactly the same!<br />";

$first = crypt($password, "X1;G^COU8U`Bo*A6@9<on5yQ6P87M]");
echo $first . " ... constant salt<br />";

$first = crypt($password, $blowfish_salt);
echo $first . " ... only blowfish salt<br />";
echo "<br />";
echo "BELOW USING 2Y PADDING:<br />";
echo "<br />";
$first = crypt($password, "\$2y\$07\$X1;G^COU8U`Bo*A6@9<on5yQ6P87M]".$blowfish_salt);
echo $first . " ... a lot, with blowfish. Causes error because salt is too long<br />";

$first = crypt($password, "\$2y\$07$\X1;G^COU8U`Bo*A6@9<on5yQ6P87M]");
echo $first . " ... constant salt. Still causes error because salt is too long<br />";

$first = crypt($password, "\$2y\$07\$".$blowfish_salt);
echo $first . " ... only blowfish salt. And now THAT is blowfish!<br />";

echo "<br />";
echo "Now back to md5 with this result again:<br />";

$hash = md5($first); 
echo $hash;
?>
public function Pass_Hash ($password, $blowfish_salt) {
      $hash = crypt($password, "\$2y\$07\$" . $blowfish_salt)); 
      return $hash;
}
$generated_salt = bin2hex(openssl_random_pseudo_bytes(22));
Pass_Hash("a very secret password", $generated_salt);

Context

StackExchange Code Review Q#41571, answer score: 17

Revisions (0)

No revisions yet.