For awhile I have been looking for a more secure way to hash a user's password on my website, to be inserted into a database. I have looked into all of the hashing methods available. It's been said that bcrypt is the best because of its slowness. I was thinking that, if I don't need the highest security of, but still staying safe. What if I used sha512 and then md5 on that hash. Would it matter if I reversed the order of the hashing? Keep in mind I will be using a separate salt for each operation. How safe would this be? Are there an other combinations that would do the same?
Any custom method you invent is more likely to have subtle bugs which make your storage method vulnerable. It's not worth the effort, since you're not likely to find these subtle bugs until it's too late. It's much better to use something that has been tried and tested.
Generally, these are your choices when storing a password,
Use bcrypt.
Use a salted, strengthened hash.
The first method is easy, just use bcrypt. It's support in pretty much any language, and has been widely used and tested to ensure it's security.
The second method requires you to use a general purpose hash function (SHA-2 family or better, not MD5 or SHA-1 as they're broken/weak) or better yet, a HMAC, create a unique salt for the user and a unique application wide salt, and then iterate the hash function many times (100,000, etc) to slow it down (called key stretching/strengthening).
e.g. (pseudocode)
sofar = hash("sha512", user_salt + site_salt + input_password);
iterations = 100000; // Should be changed based on hardware speed
while (iterations > 0)
{
sofar = hash("sha512", user_salt + site_salt + sofar);
iterations--;
}
user.save("password", "$sha512$" + user_salt + "$" + iterations + "$" + sofar);
Each iteration should rely on the previous iteration so someone can't parallelize a brute force method to break it. Likewise, the number of iterations should be changed based on the speed of your hardware so that the process is slow enough. Slower is better when it comes to password hashing.
Summary
Use bcrypt.
I don't see the point of employing MD5 at all. It's broken. But multiple rounds is apparently stronger. However the improvement from two rounds is unlikely to make much difference. Applying SHA512 lots and lots of times would be better.
You should instead be looking at user password length and salting the passwords if you're not already doing so
Is "double hashing" a password less secure than just hashing it once? provides a detailed commentary on multiple rounds of an algorithm.
In reality I suspect that the number of SHA-512'd passwords cracked are small and there are more important things to worry about like preventing them seeing the passwords in the first place - ensuring your system is safe from SQL injection, privilege escalation, etc.
Related
I read today on not-implemented.com :
Sha-256 should be chosen in most cases where a high speed hash function is desired. It is considered secure with no known theoretical vulnerabilities and it has a reasonable digest size of 32 bytes. For things like hashing user password, though, a function designed to be slow is preferred: a great one is bcrypt.
Can somebody explain the last sentence :
For things like hashing user password, though, a function designed to be slow is preferred: a great one is bcrypt.
I don't say it's not correct, my question is simply:
Why it is preferred for hashing user password to use a slow function ?
Because if it takes more time to hash the value, it also takes a much longer time to brute-force the password.
Keep in mind that slow means that it requires more computing power. The same goes for when a potential hacker tries to brute-force a password.
On your side, the password hash needs to be computed rather rarely. But an attacker who tries to brute force a password from a stolen hash, relies on computing as many hashes as possible.
So, if your login now takes 100 ms instead of 0.1 (probably less) that's not really a problem for you. But it makes a huge difference for an attacker if he needs 2000 days to break a password instead of 2 days.
bcrypt is designed to be slow and not to allow any shortcut.
It takes more effort to brute force attack the password. The slower the algorithm, the less guesses can be made per second. The extra time won't be noticed by a user of the system, but will make it harder to crack the password.
Brute force a hash password?. It's easy to say than done.
If the passwords are not using a SALT then it is possible to break it, no matter the kind of encryption (because we could use a dictionary / pre-calculated hash attack).
The speed of the algorithm means nothing, it's just a myth that some people are spreading for the wrong reasons.
For example the next example:
Our hash is generated with the next formula:
MD5(SALT+MD5(SALT+VALUE))
Even if we could generate every possible combination of md5 in a split of a second, how we know if we found the right value?. And the answer is no, it's not possible. MD5 (or sha) doesn't check if the value is right or not, it simply generates a sequence of values and nothing more.
We could try a force brute attack if and only if we have a way to determine if our hash generated match some criteria. These criteria could be a dictionary and it means a slow process too and only if we could find some criteria.
Does using multiple algorithms make passwords more secure? (Or less?)
Just to be clear, I'm NOT talking about doing anything like this:
key = Hash(Hash(salt + password))
I'm talking about using two separate algorithms and matching both:
key1 = Hash1(user_salt1 + password)
key2 = Hash2(user_salt2 + password)
Then requiring both to match when authenticating. I've seen this suggested as a way eliminate collision matches, but I'm wondering about unintended consequences, such as creating a 'weakest link' scenario or providing information that makes the user database easier to crack, since this method provides more data than a single key does. E.g. something like combining information the hash to find them more easily. Also if collisions were truly eliminated, you could theoretically brute force the actual password not just a matching password. In fact, you'd have to in order to brute force the system at all.
I'm not actually planning to implement this, but I'm curious whether or not this is actually an improvement over the standard practice of single key = Hash(user_salt + password).
EDIT:
Many good answers, so just to surmise here, this should have been obvious looking back, but you do create a weakest link by using both, because the matches of weaker of the two algorithms can be tried against the other. Example if you used a weak (fast) MD5 and a PBKDF2, I'd brute force the MD5 first, then try any match I found against the other, so by having the MD5 (or whatever) you actual make the situation worse. Also even if both are among the more secure set (bcrypt+PBKDF2 for example), you double your exposure to one of them breaking.
The only thing this would help with would be reducing the possibility of collisions. As you mention, there are several drawbacks (weakest link being a big one).
If the goal is to reduce the possibility of collisions, the best solution would simply be to use a single secure algorithm (e.g. bcrypt) with a larger hash.
Collisions are not a concern with modern hashing algorithms. The point isn't to ensure that every hash in the database is unique. The real point is to ensure that, in the event your database is stolen or accidentally given away, the attacker has a tough time determining a user's actual password. And the chance of a modern hashing algorithm recognizing the wrong password as the right password is effectively zero -- which may be more what you're getting at here.
To be clear, there are two big reasons you might be concerned about collisions.
A collision between the "right" password and a supplied "wrong" password could allow a user with the "wrong" password to authenticate.
A collision between two users' passwords could "reveals" user A's password if user B's password is known.
Concern 1 is addressed by using a strong/modern hashing algorithm (and avoiding terribly anti-brilliant things, like looking for user records based solely on their password hash). Concern 2 is addressed with proper salting -- a "lengthy" unique salt for each password. Let me stress, proper salting is still necessary.
But, if you add hashes to the mix, you're just giving potential attackers more information. I'm not sure there's currently any known way to "triangulate" message data (passwords) from a pair of hashes, but you're not making significant gains by including another hash. It's not worth the risk that there is a way to leverage the additional information.
To answer your question:
Having a unique salt is better than having a generic salt. H(S1 + PW1) , H(S2 + PW2)
Using multiple algorithms may be better than using a single one H1(X) , H2(Y)
(But probably not, as svidgen mentions)
However,
The spirit of this question is a bit wrong for two reasons:
You should not be coming up with your own security protocol without guidance from a security expert. I know it's not your own algorithm, but most security problems start because they were used incorrectly; the algorithms themselves are usually air-tight.
You should not be using hash(salt+password) to store passwords in a database. This is because hashing was designed to be fast - not secure. It's somewhat easy with today's hardware (especially with GPU processing) to find hash collisions in older algorithms. You can of course use a newer secure Hashing Algorithm (SHA-256 or SHA-512) where collisions are not an issue - but why take chances?
You should be looking into Password-Based Key Derivation Functions (PBKDF2) which are designed to be slow to thwart this type of attack. Usually it takes a combination of salting, a secure hashing algorithm (SHA-256) and iterates a couple hundred thousand times.
Making the function take about a second is no problem for a user logging in where they won't notice such a slowdown. But for an attacker, this is a nightmare since they have to perform these iterations for every attempt; significantly slowing down any brute-force attempt.
Take a look at libraries supporting PBKDF encryption as a better way of doing this. Jasypt is one of my favorites for Java encryption.
See this related security question: How to securely hash passwords
and this loosely related SO question
A salt is added to password hashes to prevent the use of generic pre-built hash tables. The attacker would be forced to generate new tables based on their word list combined with your random salt.
As mentioned, hashes were designed to be fast for a reason. To use them for password storage, you need to slow them down (large number of nested repetitions).
You can create your own password-specific hashing method. Essentially, nest your preferred hashes on the salt+password and recurs.
string MyAlgorithm(string data) {
string temp = data;
for i = 0 to X {
temp = Hash3(Hash2(Hash1(temp)));
}
}
result = MyAlgorithm("salt+password");
Where "X" is a large number of repetitions, enough so that the whole thing takes at least a second on decent hardware. As mentioned elsewhere, the point of this delay is to be insignificant to the normal user (who knows the correct password and only waits once), but significant to the attacker (who must run this process for every combination). Of course, this is all for the sake of learning and probably simpler to just use proper existing APIs.
Ok, so I understand why salting a password prior to hashing is such a good idea.
The question is, normally people suggest appending or prepending the salt to the password, why not do both?
My thinking is, so if Mr hacker got hold of the DB and wants to get the password for person x,
he thinks to himself, well most people suggest appending or prepending the salt, so lets do that..
He generates a rainbow table with of all the combinations of password + salt, and tries his luck. If that doesn't work he does the same but salt + password.
To make much it more difficult to do the attack why don't developers go the step further and do 'salt + password + salt', or 'reverse(salt) + password + salt', or you could be fancy and start cutting up the password/salt, start putting bits of salt here and there etc.
The only way the hacker would be able to find the password is if he has access to the source code (to know how the salt was weaved into the password prior to hashing)
A further note is, people suggest doing a minimum of 1000 iterations when key-stretching, again why not 1147, 1652, etc :)
A 2nd further note, when looking at a hash string, is it possible to work out the hashing function used?
It's much easier to guess the manner in which the salt is applied than it is to brute for the passwords, especially in the cases in which the attacker has a database of hashed passwords and one known match (his own password). Even if he has no knowledge of it, he can simply use his known password and the known hash to brute force the salt and salting algorithm.
The same goes with the hashing algorithm. There are only a few unbroken hash functions, and the chances are that any competent administrator would be using one of those.
One of the premises of cryptography is that ALL of the information about the algorithms used is assumed to be public. You should not rely on attackers to be unable to break your system because you are using an obscure algorithm to hash things, because compared to the expense of brute forcing passwords on a compromised database like that, brute forcing every hash algorithm is very inexpensive.
If you distribute your program to users, they can figure out exactly how it hashes things by disassembling or debugging it. If it's a server program, they can break in with some other vulnerability, or they can buy/steal/acquire your software, or whatever. I would even go so far as to say that ALL GOOD CRYPTOGRAPHIC SOFTWARE IS OPEN SOURCE: even though the entire world knows how it works, its still not breakable.
What you are trying to rely upon is security by obscurity. Lots of people and companies have used this as a method of securing their products. The last big incident I can remember was when the source code of Symantec's PCAnywhere software was stolen. You might remember how that turned out. Moral of the story is it isn't secure if nobody knows how it works, its secure if EVERYONE knows how it works (and it's cryptographically sound).
Reverse engineering your code would not be too hard for a determained hacker, once that happens, every one of your passwords is now compromised.
You should use proven hashing techniques. Take, for example, something similar to the bcrypt algorithm. When you want to hash a password, go through the following steps:
Generate a sufficiently strong random salt (16 - 32 bytes)
Set a hash cost (15 - 20) (the larger the cost, the slower and stronger the hash)
Calculate the number of hash rounds you will perform (2^cost)
Do the following:
hash = ""
for(numberOfHashRounds)
{
hash = SHA256(hash + salt + password)
}
Then store the hash along with the salt and cost used. When you need to verify, do the same with the stored salt and cost. As computers get faster, you can up the cost of the algorithm. Try and get it so your hash takes ~500ms to compute, or as long as you are willing to sacrafice.
This is secure because a cracker would have to generate a rainbow table for every salt, and perform the same number of rounds. This will take decades even with a GPU array used to crack.
If you want to add obfuscation on top of that, go ahead, just dont break the security of your algorithm in the process.
I mean actually making it hard to exploit even if the user has chosen a relatively simple password(s)? I can't think of anything besides using additional cryptographic functions.
There are a few things you can do:
A cryptographically stronger hashing algorithm.
Salts
Key strengthening (e.g. bcrypt / scrypt / PBKDF2)
Use all these techniques for the best security.
The last is not particularly efficient in terms of performance, but that's deliberate. The problem with most commonly used cryptographic hash functions is that they are designed to be fast to compute, which means that they are also fast to crack if the password is a dictionary word. The idea of key strengthening is to make the algorithm so slow to compute that even a weak password will take a long time to crack.
Don't think, read ;) (and ask on SO) You'll want to salt passwords with their own individual salt so that the same password won't result in the same hash
http://en.wikipedia.org/wiki/Salt_(cryptography)
You might want to add a salt http://en.wikipedia.org/wiki/Salt_(cryptography) to the password you're going to hash. Anyway, be aware that there'll always be some risk associated with hashing a password, take a look at this article http://www.f-secure.com/weblog/archives/00002095.html
Leave crypto security, and analysis of it, to the experts, and just use a better crypto function.
Not using MD5 for hashing passwords. The same goes for about any hash function that's optimized for throughput. The idea of SHA1 and MD5 is, that you can generate a compact representation of virtually unlimited amounts of data, so that you can check it's integrity and also sign it cryptographically.
The idea of hashing passwords is, that you cannot retrieve the password from the hash. However most passwords are shorter than their hash, and implementing a brute force or dictionary attack is trivial. So given a hash, the used hash function one can implement the check logic locally -- possibly on a massive parallel computer, think GPU -- and break passwords reasonably fast.
What you actually want to do is using a hash function, that's so computationally intense that hashing takes so much time, that even attempting a brute force attack on a 4 character password took hours.
Just add some salt to the user entered password.
$salt = 'random string';
md5(sha1(md5($salt . $_POST['password'])));
Almost no way that result can be cracked.
What is the slowest (therefore best) hash algorithm for passwords in ASP Classic?
EDIT: For those unaware, when hashing passwords, slower hashes are preferred to faster to help slow rainbow table style attacks.
EDIT2: And yes, of course speed isn't the only valid concern for hash selection. My question assumes that All other things being equal, the slowest hash method is preferred when hashing a password. Though collision/reverse engineering is of course a concern too, I'm prioritizing speed in this question since it is arguably the most critical factor to consider when comparing popular hash algorithms for use on passwords.
Thanks!
A lot of people seem to be beating on the question-asker because he's looking for a slow hash function. Actually, all other aspects being equal, a slower hash function is more secure than a fast one. This is because a slower hash function results in slower generation of rainbow tables and slower brute forcing or dictionary attacks on the password.
From Thomas Ptacek at http://www.securityfocus.com/blogs/262, as referenced in this Coding Horror article:
The problem is that MD5 is fast. So
are its modern competitors, like SHA1
and SHA256. Speed is a design goal of
a modern secure hash, because hashes
are a building block of almost every
cryptosystem, and usually get
demand-executed on a per-packet or
per-message basis.
Speed is exactly what you don’t want
in a password hash function.
Modern password schemes are attacked
with incremental password crackers.
Incremental crackers don’t
precalculate all possible cracked
passwords. They consider each password
hash individually, and they feed their
dictionary through the password hash
function the same way your PHP login
page would. Rainbow table crackers
like Ophcrack use space to attack
passwords; incremental crackers like
John the Ripper, Crack, and LC5 work
with time: statistics and compute.
The password attack game is scored in
time taken to crack password X. With
rainbow tables, that time depends on
how big your table needs to be and how
fast you can search it. With
incremental crackers, the time depends
on how fast you can make the password
hash function run.
The better you can optimize your
password hash function, the faster
your password hash function gets, the
weaker your scheme is. MD5 and SHA1,
even conventional block ciphers like
DES, are designed to be fast. MD5,
SHA1, and DES are weak password
hashes. On modern CPUs, raw crypto
building blocks like DES and MD5 can
be bitsliced, vectorized, and
parallelized to make password searches
lightning fast. Game-over FPGA
implementations cost only hundreds of
dollars.
Some comments on the PHP MD5 documentation also discuss preference for slowness.
To answer your question, it looks like BCrypt is the way to go. However, I have not been able to find any implementations for ASP Classic. If that's true, I would stick with a regular hash function like SHA512.
I'll ignore the slow part, and instead go for the "good" part.
I suggest you use SHA-512 with a salt to defeat dictionary and rainbow table attacks. I don't believe there are any known vulnerabilities for SHA-512.
If you are trying to defeat brute force attacks you are better off enforcing some failed attempts window/count rather than relying on the speed of the hashing (or hash comparison) mechanism to make the attack take longer to succeed. Lock out the account after a certain number of failed attempts within the failure window and only let new attempts be made after a significant amount of time has elapsed.
This could leave you open to a DOS attack against a well-known (administrative) account, but you could exempt certain accounts from the lockout policy or have an alternate way -- using a security question/answer -- to logon to a locked out account before the reset period has elapsed.
[EDIT] To help defeat rainbow attacks -- where the attacker has retrieved your hashed passwords and finds suitable matches that hash to the same values -- consider both using a random salt unique to each user's hashed password and a fixed salt that is part of the algorithm, not the data. For example:
testHash = computeHash( user.salt + "98hloj5674" + password );
if (testHash == user.hashedPassword)
{
valid = true;
}
This should invalidate the rainbow tables since, even knowing the user's salt and the hash algorithm, the values in the attacker's rainbow tables won't map onto your hashed passwords because of the addition of the fixed salt in the algorithm.
With ASP Classic, you'd have to do this in a library instead of on the page to make sure that the user couldn't see your fixed salt.
Dim sPassword, sSalt
sPassword = "Lorem"
sSalt = "Ipsum"
With CreateObject("CAPICOM.HashedData")
.Algorithm = 0 ' CAPICOM_HASH_ALGORITHM_SHA1
.Hash sPassword & sSalt
Response.Write "Here is your hash: " & .Value
End With
Capicom documentation
Algorithm is any of the following:
CAPICOM_HASH_ALGORITHM_SHA1 = 0
CAPICOM_HASH_ALGORITHM_MD2 = 1
CAPICOM_HASH_ALGORITHM_MD4 = 2
CAPICOM_HASH_ALGORITHM_MD5 = 3
CAPICOM_HASH_ALGORITHM_SHA_256 = 4 - Not supported on Windows XP or 2000
CAPICOM_HASH_ALGORITHM_SHA_384 = 5 - Not supported on Windows XP or 2000
CAPICOM_HASH_ALGORITHM_SHA_512 = 6 - Not supported on Windows XP or 2000
Actually, the best hash function is the one that generates no colisions and is not suspectible to rainbow-table attacks.
That means: Add a Salt (preferably a different Salt for every user), and think of using a SHA2 Hash function (or maybe RIPE-MD, I have not looked at that much):
One implementation of SHA-256 is here (i love how they call it "one-way encryption"):
http://www.freevbcode.com/ShowCode.Asp?ID=2565
Have not tested it though, but there are certainly SHA2 implementations for Classic ASP.
I personally prefer the Whirlpool algorithm for all of my hashing needs. It produces a 512 bit output and thus has equal space requirements to SHA-512. Regretfully, I cannot speak authoritatively as to whether one is more secure than the other, but there do not appear to be any flagrant weaknesses in this the third version of Whirlpool.
The reference implementations are in the public domain, which is good because I rarely find this implemented by default in various tools and languages.
(If anyone knows of a good reason why SHA should be favored over Whirlpool, please let me know.)
psuedocode for the slowest method:
function hashPassword(password)
sleep for 10 seconds
return password
end function
This certainly isn't the most secure (or at all) but it's slow...
(I'm just pointing out that making it slower is not the answer...)