I realize that this topic have been brought up sometimes, but I find myself not entirely sure on the topic just yet.
What I am wondering about how do you salt a hash and work with the salted hash? If the password is encrypted with a random generated salt, how can the we verify it when the user tries to authenticate? Do we need to store the generated hash in our database as well?
Is there any specific way the salt preferably should be generated? Which encryption method is favored to be used? From what I hear sha256 is quite alright.
Would it be an idea to have the hash "re-salted" when the user authenticates? And lastly is it any major security boost to rehash it a bunch of times?
Thank you!
The answer is to not do it yourself. The one-liner that will do everything you need in PHP is to use bcrypt.
Read this, it's easy to understand and explains everything you asked: http://codahale.com/how-to-safely-store-a-password/
bcrypt takes into account the hashing by itself, and can be configured to be as "complex" as necessary to maintain the integrity of your users' passwords in the event of being hacked.
Oh, and we don't "encrypt" passwords, we hash them.
You need to store both the hash and the salt that has been used to calculate the hash.
If you then want to check if an input is equivalent to the original input value, you can re-calculate the hash with the same salt and compare the stored hash with the new calculated one. If they are equal both input values are identical (up to some particular probability).
The choice of hashing algorithm is also important. Because there are fast hashing algorithms and rather slow hashing algorithms. And as you want to make is hard to find a collision (at least in brute-force), use a slower hashing algorithm.
What I am wondering about how do you
salt a hash and work with the salted
hash? If the password is encrypted
with a random generated salt, how can
the we verify it when the user tries
to authenticate? Do we need to store
the generated hash in our database as
well?
Yes. First you generate a salt, then generate a hash from the password plus the salt and save both hash and salt together.
Is there any specific way the salt
preferably should be generated?
I doubt that there's consensus on what's preferable. I use /dev/random. e.g.
$salt = '$2a$12$'
. strtr(substr(base64_encode(shell_exec(
'dd if=/dev/random bs=16 count=1 2>/dev/null'
)), 0, 22), '+', '.')
. '$';
$hash = crypt($input, $salt);
Which encryption method is favored to
be used? From what I hear sha256 is
quite alright.
See Computer Guru's answer, i.e. use bcrypt as in the example above. See the PHP manual page on crypt()
. If bcrypt isn't on your system, one way to get it is the Suhosin patch.
Would it be an idea to have the hash
"re-salted" when the user
authenticates?
The salt just makes dictionary attacks slower. If you have a decent random salt to start with I wouldn't think changing it frequently would help. You'd probably be better off investing your effort in making users choose good passwords, changing them often enough and keeping your Blowfish cost parameter at a sensible value.
And lastly is it any major security
boost to rehash it a bunch of times?
That question belongs in the world of cryptographic design. I recommend you leave that to the experts. In other words: forget it—just use best common practices.
What generally you do is something like:
salted = HASH(password . key); // DON'T DO IT LIKE THIS
Where key is "the salt" - the secret key stored in configuration files. So in order to crack the password you would need both the secret key and the DB so it is good to store them
in separate places.
Because the schema I had shown is not strong enough, it is better to use HMAC for this purpose rather then hand written salting. Such an operation is as simple as hash and PHP supports this.
salted = hash_hmac('sha1',password,key); // <-- this is ok
See this: http://php.net/manual/en/function.sha1.php
Three simple rules. Okay, five:
- Most important thing, if you want to consider your password storage being safe: allow strong passwords only e.g. at least 8 chars with some different case letters and numbers and even punctuation marks
- Allow users to use strong passwords only. Make a routine to check length and character range and refuse weak passwords. Even get yourself John the ripper database and check against it.
- Torture users wickedly, beat them up, until they choose good long and random enough passwords. Passwords! Not salt, of which everyone is delighted to talk for hours, but password itself should be random enough!
- Salt your passwords and store that salt along with user info. you can use user email and username as a perfect salt, no need to invent something extraordinary random.
- Certain algorithm is not that important, you can use MD5 as well. In real world there are very few people who would bother themselves with cracking user database of your famous Fishing And Grocery Fans Society site forums.