5
$\begingroup$

Cryptography is not my area, so pardon me if the question is annoying.

Some time ago, I implemented an Internet site, which database had a users table. To keep the password in its user table field, I used

encrypted_password= sha1(md5(raw_password));

What are the pros and cons of the approach I used?

$\endgroup$
  • 7
    $\begingroup$ It's a fast unsalted hash, i.e. it's as weak as they come. See How to securely hash passwords? on security.se for how to do it properly. $\endgroup$ – CodesInChaos Oct 1 '16 at 10:48
  • $\begingroup$ Just using a hash function is not sufficient and just adding a salt does little to improve the security. Instead iIterate over an HMAC with a random salt for about a 100ms duration and save the salt with the hash. Use functions such as PBKDF2, password_hash, Bcrypt and similar functions such as Argon2. The point is to make the attacker spend a lot of time finding passwords by brute force with a popular password list. $\endgroup$ – zaph Oct 3 '16 at 3:10
10
$\begingroup$

Pros: The only pro is that your method is very slightly better than storing passwords in plaintext.

Cons: If an attacker gains access to your database, he will easily be able to recover 99% of passwords with only a bit of work, and he won't even need anything more than a laptop.

The lesson here is the usual one. Never build your own crypto. Use a secure password hasher like Argon2. All the information you could need on secure password hashing can be found in this post.

Also, a minor nitpick: "encryption" is not the term you are looking for. Encrypting a value implies a transformation that is invertible, e.g. the result can be decrypted to recover the original value. Hashing, on the other hand, implies a one-way transformation that cannot easily be reversed (other than trying all possible inputs and checking the result).

$\endgroup$
  • $\begingroup$ I edited the subject and tags to remove the template encryption for clarity $\endgroup$ – rmalayter Oct 2 '16 at 14:25
  • $\begingroup$ I did not use the term "encryption" anywhere, but the nitpick in your answer made me think how can I translate "hashing" to other languages, namely Portuguese. I think it is untranslatable! $\endgroup$ – sergiol Oct 2 '16 at 22:35
  • $\begingroup$ @sergiol you certainly did use the term encryption exclusively; see the edit history of your question. That's just fine though... the entire point of this site is to have people ask questions about things they don't fully understand. Editing questions to make them more accurate and search-friendly is part of that process. $\endgroup$ – rmalayter Oct 24 '16 at 2:13
9
$\begingroup$

The short answer

DO NOT DO THAT. It is not secure.

The long answer

Background

There are three main types of attacks against password based systems:

  • Guessing (e.g. birth date of the person, wife's name, etc.)
  • Brute force - trying all possible inputs
  • Dictionary attacks

To prevent an outside attacker (somebody NOT having access to your web server, just the public interface of it), the best way is to slow down the login, also implement counters per user, e.g. lock out the user for 5 minutes after 5 tries, and send a notification to the user in email.

However, this does not protect you from attacker having access to your password database, e.g. due to a breach your password database is leaked. It is quite possible, just think about Yahoo!, eBay, Adobe, etc.

Why "naked" hash function is not secure?

To show the problem, let's say user has a password "apple123".

encrypted_password = sha1("apple123")

The encrypted_password will be "ec1e7fb8656dba32737acabc2e5a1fb2d02a973f".

Now search for this hash. What you will see, is the password. How? Did Google cracked SHA-1?

Obviously not. There are tons of dictionaries out there, in which Google searches. And believe me, there are much-much better ones, than what is published to the web.

The only limit you may think, is the storage what a "good" dictionary would require. Well, there are techniques to significantly reduce the storage of a dictionary (meaning - millions of times), using a technique called Rainbow tables. I will not go into the details of if, overly simplified it is a heavily compressed password/hash dictionary.

Another thing to note, that once the password database is leaked, an attacker has also the possibility to brute force, by calculating the SHA-1 of each possible combinations. Takes time, but with GPUs it

How to protect against dictionary attacks?

If you have a good rainbow table or other compressed dictionary, it is created for one specific hash function. So, the idea to protect against rainbow tables is creating multiple hash functions - millions, billions of hash function, by adding a public random, called salt.

salted_password = sha1("apple123 s6589fvj3e785s72o57zd8934sncag4")

The salt need to be random, and different for each users. So, you need to store the salt in the password database, next to the salted_password, and once the user submitted the password, you should calculate the salted version.

I would suggest using HMAC_SHA_256 for this purpose, with 256 bit random salt.

How to protect against brute force attacks by using CPUs?

The idea is to artificially slowing down the hash function by "stretching", on top of salting, by introducing lot of iterations. The naive implementation is

stretched_password = HMAC_SHA_256(salt, HMAC_SHA_256( salt, HMAC_SHA_256( ..., "apple123"))...)

DO NOT use the naive implementation, use PBKDFv2 instead of that, which has protection against CPU parallelization and pre-computation as well.

How to protect against brute force attacks by using GPUs?

Unfortunately, simple streching is not enough, when a simple computer can have tens of thousands of processing units - called GPU based password cracking. To slow down the GPUs there are large pseudo-random memory maps are used for the calculation, because GPU processing units have very-very slow individual access to the memory. bcrypt or scrypt provide protection against such attacks.

Any further protection

The very best is using Password Authenticated Key Exchange, or PAKE, in combination with scrypt. I personally prefer SRPv6 and AugPAKE, but there are other protocols as well.

Compared to the the previous examples, for you PAKE would require client side, JavaScript implementation of the the PAKE protocol (or using special TLS extension, which is not widely supported), which is hard.

If you are interested on a fully implemented, secure authentication, you may consider using 0_kit, a project I am involved in.

The bottom line

If you want server only, logic, go with scrypt.

The next chart shows the reason why: the question is not how fast can you break the password anymore, because you can build a huge GPU farm and do it obviously faster than using 1 CPU. Colin Percival created a nice calculation (in 2009!), how much would it cost you to break a password in 1 year.

A table with estimated costs

If you want to go a bit further, use SRP or AugPAKE, but that would require client side logic as well.

If you want to have secure password authentication, all of that implemented off-the-shelf, consider using 0_kit, a project I am involved in.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.