openssl_digest vs hash vs hash_hmac? Difference between SALT & HMAC?

10,432

Solution 1

So, first off, let's clear one thing up. openssl_digest() === hash(). It's just another function by a different name that does the exact same thing. It computes a cryptographic hash of the input.

So, now we have the question: When storing passwords, which is better: hash or hash_hmac?

Short Answer:

Neither

Long Answer:

As it turns out, The Rainbow Table Is Dead. Just using hash($password . $salt) or even hash_hmac($password, $salt) is not good enough for password storage. Period. If you're doing so, stop right now.

The reason is simple: computation time on a computer (or GPU) is incredibly cheap. It's so cheap, that to brute force a list of passwords is cheap enough that you need to worry about it. Remember, hash functions are designed to be fast. Not expensive...

But, as it also turns out, there is a way to make those fast hash functions more expensive. In fact, it's pretty simple: iterate.

Now, I know what you're thinking. You're going to just loop over the hash:

function hash_password($password, $salt) {
    $hash = hash("sha512", $password . $salt);
    for ($i = 0; $i < 1000; $i++) {
        $hash = hash("sha512", $hash);
    }
}

Surely that's good enough, right? Nope. As explained in Fundamental Difference Between Hashing and Encryption, that's not a good idea. So why not just feed back the password and salt in again?

function hash_password($password, $salt) {
    $hash = hash("md5", $salt . $password);
    for ($i = 0; $i < 1000; $i++) {
        $hash = hash("md5", $hash . $password);
    }
}

In fact, this is exactly what PHPASS uses (slightly tweaked, but this is the base algorithm)...

So now 1 call to hash_password executes 1000 hash cycles.

But can we improve on that?

Well, as it turns out, we can. The next logical thing to do would be to see if we can get more hash cycles for the same amount of time. And this is where hash_hmac() comes in. As it turns out, HMAC uses 2 hash cycles each time it's called. And because it's all C, it only takes about 1.5 times the amount of time that hash() takes to do a single round.

So that means if we replace hash with hash_hmac, we can instantly see a 33% increase in the amount of work being done in a specified time. So now we're here:

function hash_password($password, $salt) {
    $hash = hash_hmac("md5", $salt, $password);
    for ($i = 0; $i < 1000; $i++) {
        $hash = hash_hmac("md5", $hash, $password);
    }
}

And this is actually the basic inner-loop of PBKDF2.

But can we get better?

Yes, again, we can get better. If we look closely, we can see that -in addition to password and salt- all of the above algorithms use a very small amount of memory. In the case of sha512, they'll use on the order of 128 to 256 bytes (buffers and state) to hash the password. Since the memory use is so small, it's trivial to run a lot of them at once side-by-side in a GPU. If we could only increase the memory usage...

Well, as it turns out, we can simply use bcrypt, which is an adaptive hashing algorithm. It has an advantage that it uses more memory than the above algorithms (on the order of 4 to 5kb). So it's more resistent to parallelizing. And it's resistent to brute forcing since it's computationally expensive.

Luckily, it's available for PHP:

crypt($password, '$2y$07$usesomesillystringforsalt$')

Note that crypt() uses many algorithms, but the $2y$ and $2a$ algorithms are bcrypt.

But can we improve on this?

Kind-of. There is a relatively new algorithm called scrypt. It's better than bcrypt, because it's just as computationally expensive, but uses a LOT more memory (on the order of 20mb to 40mb to hash a single password). Therefore, it's even more resistent to parallelization...

Unfortunately, scrypt is not available in PHP yet (I'm working on changing that). Until then, use bcrypt...

Sidenote

After the recent lessons from LinkedIn, LastFM, Hotmail, Gawker, etc, the proof is apparent that a lot of people are doing it wrong. Don't do it wrong, use a library with a vetted algorithm. Use CRYPT_BLOWFISH (bcrypt), use PHPASS, use PasswordLib. But don't invent your own just because you don't want to pull a dependency... That's just negligence.

More reading:

Solution 2

HMAC is a specific way to use a hash algorithm (like SHA512). It's used to sign a message and you can then verify that the message is from a specific signer and has not been altered. So this isn't what you want.

A salt is used to add a bit of "randomness" to a text that should be encrypted or hashed. The point is that even if you encrypt the same text several times you'd get different results. This makes it harder to do some attacks. This is what you want: SHA512(salt+password).

For storing passwords, the most secure way I could imagine would be:

(disclaimer: I'm not very experienced with cryptography and there might be a better solution)

  • Client (JavaScript code?) would generate a salt value.
  • The client then combines salt and password, and run the result through your hashing algorithm.
  • The client then transmits both salt and hash value to the server which stores it (preferably in different locations).

To verify a password, you'd then do:

  • Pass the salt to the client.
  • Client combines salt and entered password, runs it through your hashing algorithm.
  • Client sends the hash value to the server.
  • Server compares the hash value with the stored hash value. If they match, it was the same password.

Of course you could transmit the password in plaintext and do the whole salting and hashing on the server, but this would weaken your solution dramatically. You should never transmit the password in plaintext.

But the "pass the salt to the client" part might be a problem. One way that I could imagine to solve this would be to somehow derive the salt from the username (easiest way: simply do lowercase(username) + password), but the problem with that would be that the salt would be predictable and thus weakening your solution a little bit. Yet, it's still way better than transmitting the "raw" hash and you wouldn't even need to store the salt as you could derive it from the username every time. Should your password DB get stolen it would still resist a rainbow table attack with this "salting with username" approach.

The problem is that a man-in-the-middle attack is still possible. If an attacker would intercept username and hash it has all the relevant infos and it wouldn't be any different than transmitting the plaintext password. So you might want to secure the connection with SSL (HTTPS).

Solution 3

According to IT Security experts:

Use Bcrypt Source: https://security.stackexchange.com/a/10905/7599.

I would give answer according to SO point of view.

openssl_digest vs hash vs hash_hmac
  1. openssl_digest - Computes a digest.
  2. hash Generate a hash value (message digest)
  3. hash_hmac — Generate a keyed hash value using the HMAC method

And In cryptography, a hash-based message authentication code (HMAC) is a specific construction for calculating a message authentication code (MAC) involving a cryptographic hash function in combination with a secret key.

As said by ircmaxell, hash or hash_hmac are not better for storing passwords with SHA-512. I would rather say, you can use openssl_digest for storing passwords.

See SHA-512 library for PHP

SALT vs HMAC
  1. A hash, in this context, is a one-way function - i.e. a function that makes it very easy to find the result from the argument (the password) but difficult (or impossible) to find any argument that generates a given result.
  2. A salt is some auxiliary data that augments the argument to a hash function. This is useful as it prevents accidental discovery of passwords through observation that two hashed passwords have identical values. With a salt, the stored/transmitted value will only be identical if both the salt and the password match.
  3. An HMAC refers to the application of a hash (and optional salt) to a "message authentication code" - which, depending upon context might be a password... or, at least, there's nothing stopping you passing a password into the HMAC as if it were the message authentication code.

HMAC is meant to be used in cases where you have a random and secret key. For these cases, HMAC is usually better than other ways of incorporating the key into the hash function. (For example, using HMAC takes care of things like extension attacks, etc.)

Salt is usually a random value that is not secret. That is to say, when you use the term salt you usually refer to situations where there is a random value that may very well be known to the attacker. The security of the system should therefore not depend on the salt being kept secret. In these situations HMAC is often not a very good choice.

HMAC and Salt comparison is not logical. Personally I'd use a salt and a hash function... and I wouldn't be paranoid about the strength of the hash function as its unlikely to be the weak link in any practical system....

See http://www.derkeiler.com/Newsgroups/sci.crypt/2006-01/msg00321.html

Share:
10,432
ThinkingMonkey
Author by

ThinkingMonkey

Free-Thinker, Individualist, INTP

Updated on July 14, 2022

Comments

  • ThinkingMonkey
    ThinkingMonkey almost 2 years

    I want to use SHA512 to store passwords. To do that, which of openssl_digest, hash and hash_hmac should I use and why?


    What is the difference between SALT & HMAC?


    I just read that HMAC is built on top of hash function.

    So is SHA512+SALT+HMAC really necessary or SHA512+SALT or SHA512+HMAC?

  • ThinkingMonkey
    ThinkingMonkey over 12 years
    Thanks for the answer. Wouldn't generating salt at the client aid to attack (rainbow attack)? Wouldn't it be better to generate it at the server? Probably use https for transmission?
  • DarkDust
    DarkDust over 12 years
    You're right, generating the salt on the server might be better. But generating on the client doesn't make rainbow table attacks be successful, as they get defeated simply by the presence of a salt.
  • ThinkingMonkey
    ThinkingMonkey over 12 years
    hmmmm... giving it some thought.
  • ircmaxell
    ircmaxell almost 12 years
    Two points: First off, if hmac is not a good choice for salts, why does the NIST approved PBKDF2 algorithm use it for that very purpose? Second, openssl_digest does the exact same thing as hash(). It computes a cryptographic hash (otherwise known as a digest). In fact, it uses the same algorithms as hash(). So if hash() is not good (as you indicate), neither is openssl_digest()... Additionally, HMAC is proven to not weaken the original hash, something that hash(password + salt) is not...
  • Somnath Muluk
    Somnath Muluk almost 12 years
    That's why I said to use Bcrypt.
  • Jacco
    Jacco over 11 years
    Your linked blog post 'rainbow tables are dead' is based on flawed assumptions on how they work; they are not a hashtable, a good explanation can be found @ security.stackexchange.com. Since modern password hashing algorithms are designed to be slow and storage capacity becomming slow, the time-storage trad off is quickly tipping in favor of the precomputation attacks. Salts are still the best, and much needed, protection against them.
  • ircmaxell
    ircmaxell over 11 years
    @Jacco: Except that you missed the entire point of that post (and this answer). It's not that salts aren't needed. It's that they are not enough. sha512($password . $salt) is for all practical purposes just as bad as sha512($password). You need to use a proper password hashing algorithm which is designed to be slow (and all of them are designed to use a salt). And that's the point of the post. Which is still 100% valid even if the hash-table analogy isn't complete...
  • Jacco
    Jacco over 11 years
    I'm with you on the point of needing a proper algorithm and the writing in general in your answer here on stackoverflow. However, rainbow tables are not dead nor obsolete. They are still a very valid and powerfull tool.