1

I'm using salt to encrypt my users' passwords. I'm using PHP, and here's a quick sample of what happens during a users registers.

Here it is:

PHP code:

    // Gives me my random key. My salt generator.
    $salt = uniqid(mt_rand());

    // My password via what users inputs.
    $userpwd;

    // Then the encryption. I use a HMAC hash.
    $encrypted = hmac_hash("sha256", $userpwd, $salt);
?>

Now that all works for me in my script. But my question is, how do I authenticate a user logging in? The new encrypted password is random, so I can't compare the password from the login form to the saved encrypted password in the database.

I've searched and can't find a solution. Maybe I haven't searched hard enough, but is there a way to decrypt the password? What can I do to authenticate the user with my script?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mario
  • 13
  • 1
  • 1
  • 4

6 Answers6

8

You need to generate a unique salt for each user's password, and then store the value of the salt somewhere you can retrieve it. For example, by saving the salt to a user table along with the username and hashed password. That way you can extract the known salt and run it through your function when you go to authenticate a user.

Here is an article that contains more information: Storing Passwords - done right!

And for more information about salts: salt-generation-and-open-source-software

Community
  • 1
  • 1
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
  • A salt must random. (if it is not random, we call it a key) http://stackoverflow.com/questions/1645161/salt-generation-and-open-source-software/1645190#1645190 – Jacco Nov 09 '10 at 14:58
  • 3
    Absolutely. From that post: "Use a new salt whenever you create a new password or change a password". I agree that you need to compute a new, unique salt each time a password is generated. Then you can store that salt in the database, as I suggested. I see how my answer really did not explain this clearly, so I revised it... – Justin Ethier Nov 09 '10 at 15:50
3

You hash the user's inputted password the same way, then compare if the hash is the same as the one you stored.

if (hmac_hash("sha256", $_POST['password'], $saltFromDatabase) === $hashFromDatabase)
    $login = true;

You also have to store the salt since it's different for each user. I would also recommend using a second salt that is constant across the application (stored on a hard config file, so that even if the database is compromised, the passwords are still safe).

Note: Hashing is not the same as encryption; It is an irreversible process.

Core Xii
  • 6,270
  • 4
  • 31
  • 42
  • Thanks, that's what I'll do then. Ill store my salt in a config file. I have read many people saying to store the salt in the db but I didn't feel comfortable with it. Just incase the db was compromised. – Mario Nov 09 '10 at 14:31
  • 1
    But keep in mind that using the same salt for everyone reduces the required computation time for a brute force attacker. – Halil Özgür Nov 09 '10 at 15:05
  • It will also lead to the same hash if more than one person has the same password. It is much better to have a salt per user (per password). – Aether Nov 09 '10 at 16:09
  • 2
    Guys, it's not an either-or. Use _both_, an application-global salt and a per-user random salt. I like to call the latter "pepper". – Core Xii Nov 09 '10 at 16:37
  • I got it. Thanks guys. My question is answered. – Mario Nov 09 '10 at 16:58
0

You don't decrypt what you've stored. You hash the entered password and compare it with what was stored at registration. This is because if two hashes match then (to all intents and purposes) you can be confident that the source data matches.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pauljwilliams
  • 19,079
  • 3
  • 51
  • 79
0

You encrypt the password used to log in and compare it with the encrypted password in your database. :)

Nathan MacInnes
  • 11,033
  • 4
  • 35
  • 50
0

You compute the hash of the password user has entered, just as you do when registering them. Note that the code is semi-pseudo code, you need to adapt it to your libraries or functions.

$res = db('SELECT etc FROM users WHERE user=? AND pass=?',
    $_POST['user'], hmac_hash("sha256", $_POST['pass'], $salt));
if(numRows($res) > 0) {
    // continue with authentication
}

If the salt is stored in the db, then you have to either fetch it first, or do the comparison in the db.

Halil Özgür
  • 15,731
  • 6
  • 49
  • 56
  • 1
    you should fetch the salt from the db first instead of sending the non-hashed password to the db. – Jacco Nov 09 '10 at 15:05
-2

Your salt needs to be constant, and not random. That way when you are checking the password against the hash, all you have to do is hash the input with the salt again, and the resulting hash should be the same as what came out before.

Kevin Wiskia
  • 461
  • 2
  • 9
  • Ok. So don't have a random generated salt? Use a constant salt? Ive read many people saving the salt string in the db. Is that a good practice? – Mario Nov 09 '10 at 14:27
  • 1
    A salt, by definition is *not* a constant, but a random value. http://stackoverflow.com/questions/1645161/salt-generation-and-open-source-software/1645190#1645190 – Jacco Nov 09 '10 at 14:59
  • @Jacco constant to the piece of information that password identifies with. So in this case, maybe some user specific data. Unique, not random. – Kevin Wiskia Nov 09 '10 at 19:14
  • 2
    You should read info in the link I posted, Unique must be unique in the entire world, not just on a single machine. This cannot be done, that is why random is the only valid option. – Jacco Nov 09 '10 at 22:13
  • @KevinWiskia I think people are misunderstanding you when you say "not random". What I'm assuming you mean is that it is not random every time it is used for each user, but stored relating to a specific user (the salt per user is random, but still relates to a single user) (sorry for reviving such an old thread) – Brett Gregson May 28 '13 at 14:58