Many hash iterations: append salt every time? - php

I have used unsalted md5/sha1 for long time, but as this method isn't really secure (and is getting even less secure as time goes by) I decided to switch to a salted sha512. Furthermore I want to slow the generation of the hash down by using many iterations (e.g. 100).
My question is whether I should append the salt on every iteration or only once at the beginning. Here are the two possible codes:
Append every time:
// some nice big salt
$salt = hash($algorithm, $salt);
// apply $algorithm $runs times for slowdown
while ($runs--) {
$string = hash($algorithm, $string . $salt, $raw);
}
return $string;
Append once:
// add some nice big salt
$string .= hash($algorithm, $salt);
// apply $algorithm $runs times for slowdown
while ($runs--) {
$string = hash($algorithm, $string, $raw);
}
return $string;
I first wanted to use the second version (append once) but then found some scripts appending the salt every time.
So, I wonder whether adding it every time adds some strength to the hash. For example, would it be possible that an attacker found some clever way to create a 100timesSha512 function which were way faster than simply executing sha512 100 times?

In short: Yes. Go with the first example... The hash function can lose entropy if feed back to itself without adding the original data (I can't seem to find a reference now, I'll keep looking).
And for the record, I am in support of hashing multiple times.
A hash that takes 500 ms to generate is not too slow for your server (considering that generating hashes are typically not done the vast majority of requests). However a hash that takes that long will significantly increase the time it will take to generate a rainbow table...
Yes, it does expose a DOS vulnerability, but it also prevents brute force attacks (or at least makes them prohibitively slow). There is absolutely a tradeoff, but to some the benefits exceed the risks...
A reference (more like an overview) to the entire process: Key Strengthening
As for the degenerating collisions, the only source I could find so far is this discussion...
And some more discussion on the topic:
HEKS Proposal
SecurityFocus blog on hashing
A paper on Oracle's Password Hashing Algorithms
And a few more links:
PBKDF2 on WikiPedia
PBKDF2 Standard
A email thread that's applicable
Just Hashing Is Far From Enough Blog Post
There are tons of results. If you want more, Google hash stretching... There's tons of good information out there...

In addition to re-hashing it multiple times, I would use a different salt for each password/user. Though I think 5000 iterations is a bit too much, try a lower number. There's a trade-off here; you'll have to tweak it according to your needs and hardware.
With different salts for each password, an attacker would be forced to bruteforce each password individually instead of constructing a rainbow table, which increases the workload considerably.
As always, here's a recommended read for this: Just hashing is far from enough
EDIT: Iterative hashing is a perfectly valid tactic. There are trade-offs, but everything has them. If you are worried about computation time, why not just store the plaintext password?

Please please please do not roll your own crypto. This is what libraries like OpenSSL are for. Here's few good examples of how you would use it to make salted hashes.
Salted Hashes in OpenSSL

The reason for iterative hashing is to make process as slow as possible. So you can do even better: use different salts for each iteration. It can be done by encrypting you original data again and again on each iteration with fixed key and XORing with salt value.

I prefer to go with a double sha1 with two different salts and prevent DoS delaying the answer incrementally (with a simple usleep) for every invalid password check.

Related

Why is password hashing, e.g. php's password_hash so slow?

I am using password_hash for password encryption. However there is a strange question, password_hash cost very long time. Here is a sample code.
this code will cost more than 1 second. Is that normal?
<?php
$startTime = microtime(TRUE);
$password='123456';
$cost=13;
$hash=password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
password_verify($password,$hash);
$endTime = microtime(TRUE);
$time = $endTime - $startTime;
echo $time;
?>
the result is :1.0858609676361
After running on 3v4l that seems perfectly normal.
Password hashing is not something you want optimize. In the words of Leigh on the hash documentation:
If you are hashing passwords etc for security, speed is not your friend. You should use the slowest method.
Slow to hash means slow to crack and will hopefully make generating things like rainbow tables more trouble than it's worth.
The default algorithm for password_hash, bcrypt, is designed to be slow.
http://en.wikipedia.org/wiki/Key_stretching
In cryptography, key stretching refers to techniques used to make a possibly weak key, typically a password or passphrase, more secure against a brute force attack by increasing the time it takes to test each possible key. Passwords or passphrases created by humans are often short or predictable enough to allow password cracking. Key stretching makes such attacks more difficult.
http://en.wikipedia.org/wiki/Rainbow_table#Defense_against_rainbow_tables
Another technique that helps prevent precomputation attacks is key stretching. When stretching is used, the salt, password, and a number of intermediate hash values are run through the underlying hash function multiple times to increase the computation time required to hash each password. For instance, MD5-Crypt uses a 1000 iteration loop that repeatedly feeds the salt, password, and current intermediate hash value back into the underlying MD5 hash function. The user's password hash is the concatenation of the salt value (which is not secret) and the final hash. The extra time is not noticeable to users because they have to wait only a fraction of a second each time they log in. On the other hand, stretching reduces the effectiveness of a brute-force attacks in proportion to the number of iterations because it reduces the number of computations an attacker can perform in a given time frame. This principle is applied in MD5-Crypt and in bcrypt. It also greatly increases the time needed to build a precomputed table, but in the absence of salt, this needs only be done once.
A full second is probably a little long - you could experiment with dropping $cost by one or two to bring it more to something like a tenth of a second, which will retain the effective protection while making the delay unnoticeable to your users.
Yes, it's normal. That's what the cost parameter is for: it allows you to tweak the iteration count, making the hash slower or faster as needed.
You should always make the hash as slow as possible and as fast as necessary. The reason being that the only feasible attack on a password hash is brute force. You want to make the cost so large that it takes prohibitively long to simple brute force all possible values. That's your only real defence against attackers with password hashing to begin with.
One whole second seems prohibitively for your own use. You should lower that cost a bit to stay within a few hundred milliseconds at most. Adjust to your target systems as needed.
To begin, password_hash is not encryption.
password_hash() creates a new password hash using a strong one-way hashing algorithm. password_hash() is compatible with crypt(). Therefore, password hashes created by crypt() can be used with password_hash().
A hash is one-way, and whatever you pass into it will always have the same end-result, however there is no way for you get the original string from the hash. This is ideal for passwords because you want to store an obfuscated version of the user's password that you can easily compare at login without actually storing what the password is. This means if the database is compromised, so long as the passwords were hashed, the attacker wouldn't get the passwords, they would get the hashed passwords which are essentially useless (you can use rainbow tables and I'm sure other techniques to get the resulting hashes, but it takes a decent amount of effort).
This leads into your original question. Why are password hashes slow? They are slow because one of the only ways to get the original string from a hash is to re-generate that hash. So if it takes 1 second to generate each hash it becomes a bigger time sink than it would have been had you used a fast hash such as md5 of a version of sha. Fast hashes are great for pretty much everything except for password storage.
Hopefully this answers your question. Just as an aside, I would strongly recommend generating a unique salt for each user and passing that in as one of the options into password_hash. This salt can be stored as plain-text in the database alongside the hashed password. Using a different salt for each password will add that into the password so a would-be attacker would have to generate a rainbow table for every salt that's in the database. At this point the attacker would likely utilize other techniques to get the passwords instead of a database breach.

Encryption - does it work this way or am I thinking wrong?

So I know that MD5's are technically a no-no in new applications, but I randomly had a thought of this:
Since
md5($password);
is insecure, wouldn't
md5(md5($password))
be a better alternative?
would it keep getting more secure the more I use it? Say if I made a function like this
function ExtremeEncrypt($password)
{
$encryptedpass = md5(sha1(md5(md5($pass))));
return $encryptedpass;
}
Would this function be a good alternative to say using a random salt for every account like vbulletin does.
Double hashing a string does nothing except limit your key space and make collisions more likely. Please don't do this. Double md5 hashing is actually less secure than a single hash with some attack vectors.
A better option would be to use the password_hash function in php 5.5 or ircmaxell's password_compat library for earlier php versions.
First of: hash and encryption are not the same. Hash is a one-way function while encryption expects data could be decrypted.
You should not try to invent your own solution when it comes to security. In PHP, since 5.5 version, there is native solution called Password Hashing. md5() is insecure and you should be aware of that.
If you have PHP below 5.5 version, you should use salt to hash & store your passwords.
You have lots of answers here and they are accurate but they don't really explain why.
MD5 is a hashing algorithm. What a Hashing algorithm does, is take a long piece of data and analyse it cryptographically in a way that creates a smaller piece of data. So from ABCDEFGHIJKLMNOPQRSTUVWXYZ with my custom hash algorithm I might create a single digit hash 5.
When that is done, you lose information - ABCDEFGHIJKLMNOPQRSTUVWXYZ contains far more information than 5 and there is no way to make the translation the other way.
The problem with hashing in a way that only allows an outcome of 0-9 ( this is effectively a Checksum ) is that if you take two pieces of text, the chances are quite high that they will have the same hash. So maybe with my algorithm ZZZZZZZZZ will also produce a hash of 5. This is what is termed a Hash Collision.
Now what happens if I take the hash of my hash? Well, my starting point is already very low information - the most it can possibly be is one of ten digits, so the chance of a collision is now exceedingly high. Supposing when my hash algorithm runs on numbers it returns 1 if it is odd and 0 if it is even- so if I have a hash of ABCDEFGHIJKLMNOPQRSTUVWXYZ which comes to 5 then I have a 10% chance of a collision. But if I make a hash of that hash, I will now have a 50% chance of a collision.
The trick of cryptography is hiding information in such an enormous possible space that it is unbelievably hard to find. The more you shrink that possible space, the less well hidden your information is.
Short answer: No.
md5 is easy to break using brute-force. Adding additional layers of hashing only slows down a brute-force attack linearly.
First of all md5 isn't really encryption, because there isn't a decryption method to it. It's called hashing.
The standard practice is to salt your passwords:
$salt = [some random/unique number, people usually use user_id or timestamp]
$hashed_password = sha1($salt . $password)
Remember that you need to know the salt, hence usually it means storing it along with the hashed password.
You can have multiple salts, and arrange them however you like.

md5 hash of hash

This is theoretical question but I am curious about it. What if I do this (code in PHP, but the language isn't really matter in this case):
$value = ''; //starting value
$repeat = false;
while(true)
{
$value = md5($value);
/*Save values in database, one row per value*/
/*Check for repeated hash value in db, and set $repeat flag true if there is one*/
if($repeat)break;
}
As you can see I suspect that there will be repeated hash values. I think there is no way that every existing text has its own value as it should mean that every hash value has its own and that doesn't make sense.
My questions are: Is there any article about this "problem" out there? It can happen I got the same value in one system for example when I hash files for check if they are valid? Can this caused problems anywhere in any system?
If you care about multiple texts hashing to the same value, don't use MD5. MD5 has fast collision attacks, which violated the property you want. Use SHA-2 instead.
When using a secure hash function, collisions for 128 hashes are extremely difficult to find, and by that I mean that I know of no case where it happened. But if you want to avoid that chance, simply use 256 bit hashes. Then finding a collision using brute-force is beyond the computational power of all humanity for now. In particular there is no known message pair for which SHA-256(m1) == SHA-256(m2) with m1 != m2.
You're right that hashed can't be unique(See Pidgeonhole principle), but the chances of you actually finding such a case are extremely low. So don't bother with handling that case.
I typically aim for a 128 bit security level, so when I need a collision free hash function, I use a 256 bit hash function, such as SHA-256.
With your hash chain you won't find a collision, unless you're willing to wait for a long time. Collisions become likely once you have around 2^(n/2) times, which is 2^64 in the case of 128 bit hashes such as md5. I know of no brute-force collisions against a 128 bit hash. The only collisions I know are carefully crafted messages that exploit weaknesses in the hashing scheme you use (those exist against md5).
Hash it multiple times by same method or different method, Then it would be nearly impossible to repeat its self, Also check if they repeat then repeat the hash function until the values are different, Then save in database or use it where ever you like...

Is it useful to loop an hmac hash?

I need to store a password in a database, and I used to store an sha1 hash of a salted password alongside a random salt, which was looped, like so:
$salt = sha1(microtime().mt_rand());
for ($i=0; $i < 4000; $i++) {
$password = sha1($password.$salt);
}
(In my example, $password and $salt were stored inside the db).
I recently discovered the hash_hmac() function, which apparently is a much more secure function than a simple SHA1 hash. I plan on using it with the same pattern (the salt being the secret key), but I was wondering if it was worthwile to loop it like in my previous example. If anyone could give me some insight, that'd be much appreciated.
Yes.
What you're doing here is known as key stretching and it multiplies the time an attacker has to take to check each candidate password against a hash. In your example, it increases the time by 4000x. The specific threat you are protecting against here is when an attacker gets hold of your hashes (such as what happened with LinkedIn, Last.fm and eHarmony recently) and can devote as much CPU power as he can afford to cracking them.
Rather than rolling your own, if this is anything other than a research project, you should use a well-known and publicly tested function like bcrypt(), PBKDF2() or scrypt().
The number in that loop should be much higher than 4000 and since your attacker will be using a C loop rather than a PHP loop, you won't be able to do as many in a reasonable time as he will. Even in a PHP loop, I can do 500,000 in 0.3 seconds. The above hashing algorithms solve this problem since they will be implemented in C. (Not all of them may be available in PHP.) It seems bcrypt is in 5.3 but it's called CRYPT_BLOWFISH. Details on how to use it are on the crypt() page.
hash_hmac() is not a more secure hashing algorithm but rather is used for a different purpose. See the end of Thomas' answer here. Algorithms like MD5 and the SHA family are general purpose hashing algorithms that are normally used as part of a more specific algorithm for a particular purpose. For instance, some of the above password hashing algorithms use general purpose hashing algorithms many times. has_hmac() asks you which general purpose hashing algorithm you would like to use.

MD5 password twice

I know MD5's safety is under question lately and this is the reason a lot of people are using salt (I dont understand this at all btw) but I was wondering if you wanted to easily implement a safe system in php can you just md5 something twice?
like test > 098f6bcd4621d373cade4e832627b4f6 > fb469d7ef430b0baf0cab6c436e70375
So basically:
$val = 'test';
$val = md5($val);
$val = md5($val);
Would that solve the whole rainbow security stuff? Is there an easy/noob proof way of making secure database passwords in php?
Hashing twice makes little real sense and doesn't accomplish much. In general, however, multiple hashing can make some sense. For example, if you hash enough times to take something like 100 ms (or so, depending on hardware) it can help a little. The basic idea of it is pretty simple: adding 100 ms to a normal login is a barely noticeable delay -- but if you're trying to build something like a table for a dictionary attack, multiplying the time by something like a thousand (or whatever exactly it works out to) starts to make a real difference -- a table that you could normally compute in (say) a day, takes a few years instead. That's enough difference that anything but really serious attackers will often give up (or just get bored) long before they finish the job.
Salt is an entirely separate tool. Using it does not make up for weakness in the underlying hash function. The idea here is that the size of a table for a dictionary attack becomes substantially larger (e.g., for a one-byte salt, 256 times larger). The salt is not normally kept secret, but it's relatively random, so an attacker who's doing a dictionary attack can't just hash each word as-is, but has to take each possible salt value into account. At the risk of repetition: it deals with a weakness in how (most) people pick passwords, not any weakness in the hash function itself.
If you don't believe in MD5, you can try a higher algorithm by using the hash() function:
$hash1 = hash('sha1', 'The string to hash by SHA-1');
$hash2 = hash('sha256', 'The string to hash by SHA-256');
$hash3 = hash('sha512', 'The string to hash by SHA-512');
$hash4 = hash('ripemd160', 'The string to hash by RIPEMD-160');
In my opinion it does not make sense to hash twice.
EDIT: Fixed typo in last line of code.
Whether or not you use the MD5 algorithm...
No, an attacker can always have two rainbow tables (one for the extra level of hashes, and one for the passwords). And from another answer of mine:
[...] it still just requires the password and nothing more to crack. In other words, you are just applying the hashing functions to the same thing a few times more.
You use a salt to make it more difficult for the attacker to get at your passwords, because then he would need to know the salt so that he can use it in computing the hashes for your passwords.
Storing passwords securely is tricky, most the advice posted here is not accurate. So I will defer to Thomas Ptacek's widely cited post on the subject: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
For the record, I evaluated that
$val = 'test';
$salt='somerandom!!aa##9900';
$val = md5($salt.$val);
$val = md5($val);
Its pretty safe. The secret is in the salt.
However, md5 is short so the chances of concurrences are "high" (one in 1.208.925.819.614.629.174.706.176 = 32^16, 32 words with an hexadecimal each one)

Categories