0

I have login and register system in my website I want to use a powerful way to encrypt users passwords before storing them in my MySQL database . I use this code to do encrypt the passwords :

function better_crypt($input, $rounds = 7)
  {
    $salt = "";
    $salt_chars = array_merge(range('A','Z'), range('a','z'), range(0,9));
    for($i=0; $i < 22; $i++) {
      $salt .= $salt_chars[array_rand($salt_chars)];
    }
    return crypt($input, sprintf('$2a$%02d$', $rounds) . $salt);
  }

  $user_password = "123456";
  $password_hash = better_crypt($user_password);
  //$password_hash = "$2a$07$t8Omz2TZhz5u0AI3l8uB4uQxzqYZCoqEsQmRo1gr.Viq5UnNReGMy";=> store in database 

And when a user try to login I use this to check the password :

$password_entered = "123456";

  $database_password_hash = "$2a$07$t8Omz2TZhz5u0AI3l8uB4uQxzqYZCoqEsQmRo1gr.Viq5UnNReGMy";// I get this from database depending on the username

  if(crypt($password_entered, $database_password_hash) == $database_password_hash) 
  {
    echo 'password is correct';
  }
  else
  {
    echo 'not correct';
  }

I use crypt because my PHP version does not support password_verify .

My problem is : I still get not correct all the time .

I want to give each user a different salt' and I want to check it bycrypt`

Do I have to change anything in this code ?why does it give not correct all the time?

  • 4
    If you use SALT in the initial hashing you need to store that salt so you can reuse it in the password checking routine. PS, you cannot just generate another random SALT. – RiggsFolly Oct 09 '14 at 13:58
  • Your attempting to hash the password your comparing with the hash of the stored password. You need to hash the password you want to compare with the original salt and then compare the 2 hashes. – Grice Oct 09 '14 at 13:59
  • 1
    @RiggsFolly - The `crypt()` will include the salt in the resulting hash-value, so verification is possible. – martinstoeckli Oct 09 '14 at 14:23

4 Answers4

1

You are aware that there exists a compatibility pack for the password_hash() function? Probably you can use this function directly then, later when you switch to a new PHP version you can just remove the include to this library and the code will still work.

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

This function works because it includes the salt in the resulting hash-value. The function password_verify() can extract it from there. Actually it is the crypt() function doing it, so your code will include the salt as well.

martinstoeckli
  • 23,430
  • 6
  • 56
  • 87
  • You are missing the fact that he was **USING A SALT** and for good reasons. **YOU ARE NOT** – RiggsFolly Oct 09 '14 at 14:42
  • @RiggsFolly: Yes he is. From the php manual: If omitted, a random salt will be generated by password_hash() for each password hashed. This is the intended mode of operation. – Roel Harbers Oct 09 '14 at 14:44
  • @RiggsFolly - The function [password_hash()](http://www.php.net/manual/en/function.password-hash.php) is just a wrapper around the `crypt()` function and handles the tricky parts like generating a cryptographically safe salt. – martinstoeckli Oct 09 '14 at 14:49
  • Then I guess you did not read the part of his question that said **my PHP version does not support password_verify** – RiggsFolly Oct 09 '14 at 14:58
  • @RiggsFolly - Yes in fact i did. What i'm suggesting here is, that the OP could use the compatibility pack, this was made for earlier PHP versions, from the same author who wrotes the password_hash() function. It offers an implementation of the password_hash() function, until one can use the PHP function directly. – martinstoeckli Oct 09 '14 at 15:02
  • Well its another good day... I have learnt something. But surely storing the algorith and the salt with the hash means if I get access to the database holding these the salt becomes irrelevant and I can just brute force the data part of the hash – RiggsFolly Oct 09 '14 at 15:37
  • @RiggsFolly - Hey, i'm happy that you see it this way. The salt even works if it is known. The purpose of the salt is, that an attacker cannot build a single rainbow-table to brute-force all passwords at once, instead he would have to build a rainbow-table for each salt/password. Maybe you are interested in my tutorial about [secure password storing](http://www.martinstoeckli.ch/hash/en/index.php), maybe something for tomorrow? – martinstoeckli Oct 09 '14 at 16:02
  • I will definitely look at that. But like I said, If I get hold of the password hash done this way, dont I know the 1. Algorithm used and 2. The Salt used. Therefore I am back to a simple rainbox-table to brute just the password. – RiggsFolly Oct 09 '14 at 16:09
  • @RiggsFolly - That's why each password should become its own unique salt. Even if an attacker knows this salt, and builds a rainbow-table with it, then he gets only 1 password. Building a rainbow-table for a single passwords does not makes sense though, you can just stop when you found a match. If you want to add a server side secret there are better ways to apply it, have a look at the end of the tutorial. – martinstoeckli Oct 09 '14 at 16:16
1

The dollar signs in your double-quoted string are interpolated as variables, so the actual value of $database_password_hash in your example is '$2a$07.Viq5UnNReGMy'. Use single-quotes instead.

This works for me:

$password_entered = '123456';
$database_password_hash = '$2a$07$t8Omz2TZhz5u0AI3l8uB4uQxzqYZCoqEsQmRo1gr.Viq5UnNReGMy';// I get this from database depending on the username
if(crypt($password_entered, $database_password_hash) === $database_password_hash) {
  echo 'password is correct';
} else {
  echo 'not correct';
}
Roel Harbers
  • 1,014
  • 1
  • 9
  • 18
0

First when you create your hash, with a SALT, you need to return both the hash and the salt that was used in creating the hash.

function better_crypt($input, $rounds = 7)
{
    $salt = '';
    $salt_chars = array_merge(range('A','Z'), range('a','z'), range(0,9));
    for($i=0; $i < 22; $i++) {
      $salt .= $salt_chars[array_rand($salt_chars)];
    }
    $salt = sprintf('$2a$%02d$', $rounds) . $salt);
    $hash = crypt($input, $salt);
    return( array('hash' => $hash, 'salt' => $salt);
}


$user_password = '123456';
$better_result = better_crypt($user_password);
// Store the $better_result['hash'] 
// AND 
// $better_result['salt'] 
// to the users table in the database

Now when you are validating that the correct password was used at login you do :-

// Get from the database the users hashed password and the salt used to create the hash.

if( crypt($password_entered, $salt_from_users_row) == $database_password_hash) 
{
    echo 'password is correct';
} else {
    echo 'not correct';
}
RiggsFolly
  • 93,638
  • 21
  • 103
  • 149
  • In another [answer](http://stackoverflow.com/a/20399775/575765) i tried to explain the format returned by the `crypt()` function. There you can see that the salt is indeed already part of the hash-value, as well as the cost factor. – martinstoeckli Oct 09 '14 at 15:10
0

Crypt always confuses me. Thats why I just use basic Hash functions.

function verifyPassword($input, $dbHashOfPassword, $dbSavedSaltForThisUser)
{
    return $dbHashOfPassword === $this->hashPassword($input, $dbSavedSaltForThisUser);
}

function hashPassword($password, $salt)
{
    return hash('SHA512', $password.$salt);
}

function createSalt($username, $userid, $systemTime, $anything)
{
    //Do stuff to create a Unique Salt for your user.
    //This has to be stored in the database as well but 
    //will have the impact that every attacked userdata will 
    //need there own rainbow table created.
    return hash('MD5', 'T-'.$systemTime.'-U-'.$username.'-A-'.$anything.'-ID-'.$userid.'-E');
}
chozilla
  • 159
  • 7