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
  • 409
  • 3
  • 9

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
  • 25,121
  • 2
  • 90
  • 129