Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 513
ThinkingMonkey Avatar asked Jan 21 '12 12:01

ThinkingMonkey


People also ask

What is difference between hash and HMAC?

They are message encryption, message authentication code, and hash functions. The major difference between MAC and hash (HMAC here) is the dependence of a key. In HMAC we have to apply the hash function along with a key on the plain text. The hash function will be applied to the plain text message.

What is HMAC sha256?

HMAC(Hash-based message authentication code) is a message authentication code that uses a cryptographic hash function such as SHA-256, SHA-512 and a secret key known as a cryptographic key. HMAC is more secure than any other authentication codes as it contains Hashing as well as MAC.


2 Answers

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:

  • Properly Salting Passwords - The Case Against Pepper
  • GPU Accelerated PBKDF2
  • Many Hash Iterations, Append Salt Every Time?
  • MD5 Decoding, How Do They Do It
like image 162
ircmaxell Avatar answered Sep 20 '22 12:09

ircmaxell


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).

like image 36
DarkDust Avatar answered Sep 20 '22 12:09

DarkDust