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
?
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
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).
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
- openssl_digest - Computes a digest.
- hash Generate a hash value (message digest)
- 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
- 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.
- 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.
- 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