Jump to content

SALT hashing help


Tenaciousmug

Recommended Posts

First off I want to know if this function works well:

define('SALT_LENGTH', 9);

function generateHash($plainText, $saluti=null)
{
if ($saluti==null)
{
	$saluti = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
}
else
{
	$saluti = substr($saluti, 0, SALT_LENGTH);
}

return $saluti . sha1($saluti, $plainText);
}

 

plainText would be the password they type and saluti would be the new generated password.

 

The question is how would I retrieve the password from the database when they login?

I'm not too sure what's going on in this function since I'm just learning it so explanations would be awesome too..

Link to comment
Share on other sites

A hash is a one-way function that turns an existing string into another string.  It cannot be reversed.  It's commonly used for uniqueness checks, passwords, and array keys.

 

Basically what this function does is take a password like "abc123" and turn it into a hash.  With the hash, you cannot recover the original password.  What you have to do is:

- When the user creates a new password, store the hash in the database.

- When the user attempts to log in.

- Take the password they gave and translate it into a hash.

- Compare the hash you just made to the hash in the database.

- If they match, log the user in.

 

This way, if someone breaks in and steals your database, they'll never get the passwords themselves, only the (useless, one-way) hashes. 

 

If you wish to have a password-reset functionality, have a script that changes the user's password to a NEW password and emails it to them.  Better yet, allow them a one-time code to change their password without knowing what the old password was.

 

Also, ALWAYS use this function you posted with a salt (with a second argument) if you're planning on using it for passwords.  If you let the function generate its own salt, the hash will be different every time.

 

-Dan

Link to comment
Share on other sites

Thank you for the explanation. (:

May you explain this sentence:

Also, ALWAYS use this function you posted with a salt (with a second argument) if you're planning on using it for passwords.  If you let the function generate its own salt, the hash will be different every time.

 

What do you mean with a second argument?

So if I were to generate their password with the function I'm using.

I would generate the password they type to login with the same function? And then compare them?

But as you stated, it would generate a different hash each time so how do I prevent it from doing so?.. I'm so confused.

Link to comment
Share on other sites

The second argument is an additional modification to the password (i.e. SALT) that is to be done BEFORE creating the hash. But, you must use the SAME salt each time you create/compare passwords. The reason for this is that people have created what are called Rainbow Tables which are large collections of values and their corresponding hashes (with no salt).

 

So, lets say a malicious user has gained access to our database. There is a column with all the users' hashed passwords. If there was no salt on those hashes then the malicious user could run those hashed values against the rainbow table and, potentially, determine the users' passwords. That is why it is so important for user to use passwords that are not just basic dictionary words. It would be impossible to generate a database with all possible passwords and their corresponding hashes due to CPU and memory requirements. But, these tables do include most if not all possible passwords that contain simple "words".

 

By applying a SALT to the value before hashing it a malicious user would have to 1) know how the salt is created and 2) generate a unique rainbow table just to attempt to backward engineer your hashes. That would be an extravagant amount of work and may return little if any results.

 

So, when you add a salt to a value and store the hashed result you will need to apply the same salt when comparing the user entered value when they attempt to log in. So, you must always use the same salt, but it can be unique to each user. For example, you could append the timestamp of when their account was created. But, the SALT can be any manipulation of the password such as reversing the text, appending other text, etc.

 

 

Link to comment
Share on other sites

Also, this function you posted creates a new random salt every time it runs if you omit the second argument.  That means it cannot be used for passwords without the second argument, because each time you run it it will produce a different password.

 

-Dan

Link to comment
Share on other sites

But as you stated, it would generate a different hash each time so how do I prevent it from doing so?.. I'm so confused.

 

When a user first registers, you only call the first argument. Since no salt was defined it will create a new salt. Then, it hashes the password and salt together and then sticks the salt onto the beginning of the hashed string. So let's say the plaintext password is "pass1234", and it generates the salt "salt1234". The hash of the password and salt are "hash1234". You end up with this string: "salt1234hash1234".

 

Now you store that string in your database. When they want to log in, you get the hash from the database. Then, you call your function with that string as the second argument. Since it is not null this time it is going to skip creating a new one and instead, it's going to strip the first X characters off the beginning (X being the salt length) which is the salt. So it will strip "salt1234" off the beginning. Now you can hash the password now that you know the salt, and end up with the same hash.

Link to comment
Share on other sites

Random salt stored beside your hash. This is the BEST way to salt up your hashes.

 

It takes a VERY clever attacker to reverse the basic method shown in OP's function.

 

It's nearly impossible if you break apart the salt and mix it in to the hash variably, and use 256+ bit hash algos.

 

Use hash_hmac with a random key if you can, and include that key mixed into the hash.

Link to comment
Share on other sites

Random salt stored beside your hash. This is the BEST way to salt up your hashes.

 

It takes a VERY clever attacker to reverse the basic method shown in OP's function.

 

It's nearly impossible if you break apart the salt and mix it in to the hash variably, and use 256+ bit hash algos.

 

Use hash_hmac with a random key if you can, and include that key mixed into the hash.

 

While I won't argue that the method shown would provide some additional complexity, it really doesn't provide any additional security. An attacker would already have to have some knowledge of the hashing method and salt (in addition to the hashed values in the database). The only way to gain that knowledge would be to view the code (unless your database has an actual field called hash!). Even just using the username, timestamp of date created, etc. are all just as good as the function above. With a unique salt for each user the attacker would have to use the same hashing methodology and then loop through hundreds of thousands of "potential" passwords in order to try and decipher a user's password. If the user is using a password such as "password" or "apple" their password will be discovered in such a brute force attempt.

 

The reality is that 1) In order to do this the attacker would have to already have access to the data. So, the only thing the attacker would be obtaining is - possibly - the password. 2) The brute force method can be easily thwarted by requiring strong passwords. The CPU/Memory requirements to try and reverse a strong password are hugely significant. 3) Unless this is for a financial or high profile site, no one is going to bother to go to these extremes in the first place.

Link to comment
Share on other sites

Agreed. I am assuming that the compromise would be in database only. If they have your database and your filesystem, then they know how you're salting your hashes and can begin bruteforcing.

 

Complexity can add security if only your database is compromised. With a unique salt, hidden within the hash, bruteforcing even a single password is impossible. I always assume an attacker that has compromised your database could have several sock puppet accounts with known password -> hash combinations. With this information, it's possible to start attempting to reverse engineer your salting method. Once they have that, bruteforcing can begin. If the salt is mixed in variably within the hash, and the salt isn't just appended to the start/end of the password, reversing is pretty much impossible without a LOT of luck or a filesystem compromise.

 

I know it's a little extreme, but you're pretty much just mixing strings around. The overhead added is minimal, and you can rest easy that your user's passwords are extremely safe, even if your database is compromised and the attacker has server password->hash combinations.

Link to comment
Share on other sites

With a unique salt, hidden within the hash, bruteforcing even a single password is impossible.

 

That is what I disagree with. With any salt the attacker needs to know how the salt is applied, ergo they would have to have access to the source code to gain that knowledge. With access to the the source files it would be an elementary exercise to identity that a salt is embedded in the hash itself and how to extract it. Case in point, the function above. By analyzing the code one could decipher how the salt and hash are stored. You did, so why couldn't anyone else? By analyzing that function we now know that the salt is 9 characters and is concatenated to the front of the actual hash, do we not?

Link to comment
Share on other sites

With a unique salt, hidden within the hash, bruteforcing even a single password is impossible.

 

That is what I disagree with. With any salt the attacker needs to know how the salt is applied, ergo they would have to have access to the source code to gain that knowledge. With access to the the source files it would be an elementary exercise to identity that a salt is embedded in the hash itself and how to extract it. Case in point, the function above. By analyzing the code one could decipher how the salt and hash are stored. You did, so why couldn't anyone else? By analyzing that function we now know that the salt is 9 characters and is concatenated to the front of the actual hash, do we not?

 

I believe he is saying that with ONLY the database hash, it is not possible to bruteforce passwords until you come up with that hash, since you don't know how the hash was constructed.

 

Obviously if you have access to the source code then it would be quite trivial.

Link to comment
Share on other sites

With a unique salt, hidden within the hash, bruteforcing even a single password is impossible.

 

That is what I disagree with. With any salt the attacker needs to know how the salt is applied, ergo they would have to have access to the source code to gain that knowledge. With access to the the source files it would be an elementary exercise to identity that a salt is embedded in the hash itself and how to extract it. Case in point, the function above. By analyzing the code one could decipher how the salt and hash are stored. You did, so why couldn't anyone else? By analyzing that function we now know that the salt is 9 characters and is concatenated to the front of the actual hash, do we not?

 

I believe he is saying that with ONLY the database hash, it is not possible to bruteforce passwords until you come up with that hash, since you don't know how the hash was constructed.

 

Obviously if you have access to the source code then it would be quite trivial.

 

Think about that for a moment. You are saying it is better to store the salt as part of the hash in the database because if someone only got the db info they wouldn't be able to brute force the hash. How would that be better than just using a single, hard-coded salt that is stored in the source files? As long as you are using a salt the attacker MUST have some knowledge of how the salt is used. That can only come from the source code. So, as long as you are using a unique salt it doesn't matter how the salt is obtained. Like I have stated before you could simply use the username as the salt. There is no way an attacker will know that is the salt without the source code. So, it is no better or worse than the method described previously.

Link to comment
Share on other sites

Given an unlimited time frame, I don't trust simply throwing keys under the flower pot or door mat, even if there's a combination lock on the door as well.

 

Yeah, for 99.99% of applications, a static salt is enough to deter some of the most persistent attackers. Generally the information stored isn't that valuable - though will more stores using PayPal, and more users with single e-mail/passwords for all of their accounts, this isn't always true.

 

GPUs can brute force hashes extremely fast... again given unlimited time and a known password->hash, you could theoretically 'guess' the salt. If I was given this task and 10 GPUs, The first thing I would do would be to try salt.pass, as almost every

 

Haha, now that I look at it, this

return $saluti . sha1($saluti, $plainText);

Should be

return $saluti . sha1($saluti . $plainText);

Link to comment
Share on other sites

Oops, submitted the post accidentally. Ignore that last bit on the post above.

 

Regardless, I prefer not to be predictable. If the salt is short enough, it can be brute forced with a single user->hash combo. If I was attacking, my first guess would obviously be salt.pass, then pass.salt.

 

A 9 character salt, using HEX values, will have 16^9 possible combinations. That's 68,719,476,736. A good GPU will computer over 1 billion sha1 hashes per second. There aren't many possible algos the hash could be, so in much less than an hour you've tried a LOT of salty combinations. With the salt extracted, I'd try it on another password. If it worked, I could begin to generate a custom rainbow table or attack a single user directly.

 

To find a random salt appended to a hash, an attacker could look for blocks matching their salty hash while bruteforcing. A huge chunk of your salt.hash will be identical to the raw salted hash they're attempting to match. It's pretty obvious that there's a salt buried in the example as well. The salt.hash is 160+36bits. That means its a 192 bit algo with a 4 bit salt, or more likely a 160/36 or 128/68. If they do manage to extract a random salt, they can only attack a single hash at a time, as generating a rainbow table is pointless. If you've mixed in the salt statically in the password, and variably within the salted hash, an attacker would have to be extremely persistent and clever, and have multiple known password->hash combinations.

 

I realize this is all hypothetical, and very few compromised databases are attacked with the persistence required to break a salt. A salt makes an attack much more difficult. Obfuscating that salt makes the attack more difficult still. The overhead necessary to mix them all together is almost non-existent.

 

On topic, the original function could be made a lot more secure if the salt wasn't truncated to 9 characters. I have no idea why this would be done.

Link to comment
Share on other sites

@xyph,

 

You completely missed the point of my post. I was never advocating a single salt. I have only been referring to this statement.

 

Random salt stored beside your hash. This is the BEST way to salt up your hashes.

 

A random salt stored beside the hash is no better or worse than using any other salt that is unique to each user, no matter where it is stored. In fact, the method you described could even be considered worse than using something such as the username as a hash. Why? Because an attacker could see that the hash stored int he database it too long. He could then conclude that the salt is either at the beginning or the end of the hash. The point is that without knowing what value is being used as the salt OR how it is used there is no more or less "security". The only way to get that information would be through the source code or inside information. With a known password/hash combination the attacker might be able to reverse engineer the salt IF it was done in a simplistic manner (such as just appending the salt to the beginning). If I were to put half the salt at the beginning and half at the end and then reverse the characters it would be "realistically" impossible for someone to stumble upon the salting method through brute force.

 

Anyway, rather than continue this discussion which isn't getting us anywhere, I challenge you to crack the following.

 

Password: ********

Salt: 1308148757 (timestamp)

Hash: 6849f5938bfc4e88bfd432f435bdece2

Hashing method: MD5

 

I have provided the salt and the hash. Plus I will even give you the following details about the password. It is 8 characters long and is only comprised of alpha-numeric characters. No special characters or accented letters. It is even a password I have used before, so it isn't just a random bunch of characters. So, you now have a great deal more information than someone who was able to penetrate the DB would have, but I doubt anyone would be able to figure out the password as they do not know how the salt was applied.

Link to comment
Share on other sites

With a unique salt, hidden within the hash, bruteforcing even a single password is impossible.

 

That is what I disagree with. With any salt the attacker needs to know how the salt is applied, ergo they would have to have access to the source code to gain that knowledge. With access to the the source files it would be an elementary exercise to identity that a salt is embedded in the hash itself and how to extract it. Case in point, the function above. By analyzing the code one could decipher how the salt and hash are stored. You did, so why couldn't anyone else? By analyzing that function we now know that the salt is 9 characters and is concatenated to the front of the actual hash, do we not?

 

I believe he is saying that with ONLY the database hash, it is not possible to bruteforce passwords until you come up with that hash, since you don't know how the hash was constructed.

 

Obviously if you have access to the source code then it would be quite trivial.

 

Think about that for a moment. You are saying it is better to store the salt as part of the hash in the database because if someone only got the db info they wouldn't be able to brute force the hash. How would that be better than just using a single, hard-coded salt that is stored in the source files? As long as you are using a salt the attacker MUST have some knowledge of how the salt is used. That can only come from the source code. So, as long as you are using a unique salt it doesn't matter how the salt is obtained. Like I have stated before you could simply use the username as the salt. There is no way an attacker will know that is the salt without the source code. So, it is no better or worse than the method described previously.

 

Well, consider this. If you only used one salt, and the hacker managed to figure out how it is implemented, then ALL of your users are now compromised. If each user has a unique salt, it is that much more difficult for the hacker.

Link to comment
Share on other sites

In fact, the method you described could even be considered worse than using something such as the username as a hash. Why? Because an attacker could see that the hash stored int he database it too long. He could then conclude that the salt is either at the beginning or the end of the hash.

 

Missed this part in your post.

 

You could easily compensate for this by just reducing the hash's length. Then it is still 32, 40, 128..whatever long.

Link to comment
Share on other sites

...Or increasing the salt length. When I do salted hashes, the result is usually 512 bits. Did I use sha512? Did I use haval224(3/4/5) with a 288 bit salt? Even if I don't use PBKDF2 or similar, there are a lot of variables when starting an attack.

 

There's no benefit to cracking that hash for me, so it's not worth it. What I'm trying to say is, for $1000, I can crack over 10 BILLION MD5 hashes per second. If your hash is simply salt.pass or pass.salt, alphanumeric, and 8 character, there's only 218340105584896 * 2 combinations. That's less than a day on a small GPU farm. That's trying every combination of salt.pass AND pass.salt in MD5.

 

My original point was the OP's function should be changed. As of right now, it's easy enough to bruteforce with a known password->hash and I'm not even a skilled attacker.

Link to comment
Share on other sites

As of right now, it's easy enough to bruteforce with a known password->hash and I'm not even a skilled attacker.

 

Really, then tell me what my password was in the example I provided - I provided way more info than a user with access to the DB would have. You can't brute force it because you have no idea how the salt was applied. And, as I have already stated a multitude of times previously an attacker with access to the DB would have no clue how the salt was applied or, just as important, what the salt is. That is why it doesn't matter if you use a random value or some other value unique to the user for the salt. Both are just as valid.

Link to comment
Share on other sites

With my old GPU and basic tools, each salting method you use will take me 2 days to break.

 

If it's salt.pass, or pass.salt, I'll have it in 4 days. If it's more complex, I'm not going to bother. If you throw $500 in escrow, and will give it to me when I break your password, then I'll bother beyond that.

 

The information you've given me is very similar to the information an attacker would have when your DB is compromised. They will know a password->salt combination, and will know that it's most likely hashed with md5 or sha1.

 

I'm done the argument. If you want to use your method go ahead - it's probably enough for whatever application you're using. I'll use mine.

 

If you've gone salt.pass or pass.salt I'll have your password up in a few days.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.