8

One of the typical approaches to computing a salted hash is this:

hash(salt+hash(secret))

where hash is something like SHA-256 hash function - taking any size input and returning fixed size output. What's the need for the hash(secret)?

Why can't I just do this:

hash(salt + secret)

where + is simply concatenating two byte arrays?

sharptooth
  • 399
  • 2
  • 9
  • 1
    I don't see any reason here. Do you have some examples where it is used this way? – Paŭlo Ebermann Jun 09 '12 at 12:44
  • @Paŭlo Ebermann: I've seen in multiple times in comments to a post about recent LinkedIn passwords leakage. – sharptooth Jun 09 '12 at 12:46
  • 4
    The only reason I can think of is for hiding the clear text password on the network.

    Consider that with $H(salt || pwd)$, in a very simple system, the user would send $pwd$ and the server would compute the hash to check. Anybody who can sniff the password from the network now cannot only log in, but also knows the password.

    With $H(salt || H(pwd))$ he can only sniff the hash. He can now log in, but would still need a preimage attack to find out the actual password.

    – Maeher Jun 09 '12 at 12:56
  • LinkedIn did not know the secret, they only knew hash_without_salt(secret). That's what they stored in their database. So unless they waited for every person to login, the only way to add a salt, is to take the stored unsalted hash as input. – Hendrik Brummermann Jun 11 '12 at 14:30

1 Answers1

8

This construction has two advantages over a plain hash of param1||param2:

  • It's immune to length-extensions
  • You can't get collisions of the form param1=A||B param2=C vs. param1=A param2=B||C.

But neither of those is relevant to password hashing, so it doesn't offer any advantage there.

The construction looks like it's inspired by HMAC:

$$ HMAC(K,m) = H((K ⊕ opad) ∥ H((K ⊕ ipad) ∥ m)) $$


But of course for password hashing one would not use such fast hashing constructions. Correct choices are scrypt, bcrypt, and PBKDF2. These have a designated salt parameter, so they don't need such an ad-hoc construction to mix salt and password.


This system has one big advantage though: You can upgrade existing hashes to it, without knowing the plaintext password. Essentially you treat $ hash(pass) $ as the new password. When upgrading an old system from a plain, unsalted hash, I'd use something like:

$ PBKDF2(LegacyHash(password), salt) $

CodesInChaos
  • 24,841
  • 2
  • 89
  • 128