5

Possible Duplicate:
Is “double hashing” a password less secure than just hashing it once?

I'm encrypting passwords using sha1 in PHP, but I'm wondering if hashing the hash is any more secure than just hashing the password.

For example:

Is

$hash = sha1($pwd);

any less secure than

$hash = sha1(sha1($pwd));

I don't see why it wouldn't be, because reverse-lookup sites will not be able to find a match of the hash of a hash.

Community
  • 1
  • 1
Jack Greenhill
  • 10,240
  • 12
  • 38
  • 70
  • 1
    Have a look at http://stackoverflow.com/questions/348109/is-double-hashing-a-password-less-secure-than-just-hashing-it-once – Michael Nov 27 '12 at 10:36
  • 3
    Fast SHAs are useful in all sorts of places, password storage is not one of them. Password hashing should be done with expensive to compute algorithms, such as PBKDF2. – lynks Nov 27 '12 at 11:17
  • Flagged in the hope that it won't just be closed but transported to crypto. I'll create a discussion on META about this. – Maarten Bodewes Nov 27 '12 at 15:13
  • @owlstead I'm pretty sure we have plenty of duplicates all over the place. Here, on crypto.SE and on security.SE. I don't think migrating is useful here. – CodesInChaos Nov 27 '12 at 16:18
  • @CodesInChaos hmm, all too true. The method of checking for dupes on the other site and the transfer of questions is a bit inconvenient though, hence the upcoming post on META. – Maarten Bodewes Nov 27 '12 at 16:25

3 Answers3

2

Double hashing does not really help. Salting does.

mvp
  • 111,019
  • 13
  • 122
  • 148
2

To make your password storage safe, you should not use sha1 or any other fast hash algorithm, instead use a key derivation function like BCrypt.

The problem with fast algorithms is, that you can calculate 3 Giga sha1-hashes per second with common hardware (in 2012). That makes it possible to brute-force a whole english dictionary with about 500000 words, in less than a millisecond!

The second problem in your example is the missing salt. If you do not use a unique salt for every password, an attacker can build a single rainbow-table to get all passwords.

BCrypt was especially designed to hash passwords, and is therefore slow (needs some computing time). With a cost factor you can adapt the needed time to future (and therefore faster) hardware. Internally it does something similar as you suggested, it repeats hashing a lot of times, but in a safe manner.

Using BCrypt can be as easy, as using the sha1 hash. PHP 5.5 will have it's own functions password_hash() and password_verify() ready, to simplify this task. There is also a compatibility pack for PHP 5.3/5.4 available, downloadable at password_compat.

martinstoeckli
  • 23,430
  • 6
  • 56
  • 87
-1

First off, as weak as sha1 alone is its better than plaintext stored passwords. ANY encryption, hashing or other obfuscation is far better than plaintext!

The problem with sha1 is that its fast, so its fast to generate hashes to crack against. Salting helps a lot, but if your server is compromised and you have your salt hash stored as a string somewhere, there goes that advantage...

If you don't want to use mcrypt or another encryption method, you can mixup your sha1 hash a bit like this:

$my_super_sha1_hash = 
sha1(
    sha1(
        substr(
            sha1($username)
            , 0
            , strlen($password) 
        )
    )
    .sha1(
        substr(
            sha1($password)
            , 0
            , 40-strlen($password)
        )
    )
);

By mixing together the username and password, and using the length of the (unknown) password to determine what bits of each are used in the sting that then gets hashed again, each salt is unique but not random, so the result is consistent across all users and A LOT more difficult to crack since have to factor in the string length of the password and the username.

WebChemist
  • 4,393
  • 6
  • 28
  • 37
  • This is *less* secure than just hashing the concatenation of username and password. – Lie Ryan Nov 27 '12 at 14:23
  • You missed the point of a salt. It's not secret, it different for each hash to block multi-target attacks. It's still beneficial if an attacker knows the salt. (Though using an unknown value in addition to the unique per user value is an additional advantage). You also forgot to mention key strengthening, i.e. using a hash function that's expensive to calculate for the attacker. – CodesInChaos Nov 27 '12 at 16:12
  • Your mixing scheme is stupid too. For short passwords the salt space becomes very small, for a long password the password's contribution disappears, and for a really long password the code doesn't even work correctly. Your scheme is clearly inferior to a simple `sha1(sha1(username).sha1(password))` or even just `sha1(username."|".password)` – CodesInChaos Nov 27 '12 at 16:13
  • This post isn't meant to say "here's a super safe function, use this and you're good", its about sha1 alone being far too weak and any self-made sha1 hashing solutions needing to greatly increase complexity. The way I see it, a function along these lines has the advantage over storing a randomly generated salt alongside the hash in that if the db user table is stolen, the salt is still unknown and gives no hints at all to the attacker about the calculation method, while still giving each password a unique salt. – WebChemist Nov 27 '12 at 21:37
  • 1
    And I fail to see how this is less secure than a simple concat of username & password. If the stolen db hash did manage to be reversed and they saw the 80 char double sha1 concat string, a substr of a straight sha1 of the full username or password would be a lot more obvious than a hashes of a partial user|password hashes. If the php hashing code was compromised, its all pointless since the attacker could just run the hashing function, in which case at least it would be a bit more computationally expensive than simple concat you suggest. – WebChemist Nov 27 '12 at 21:40