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) $
secret
, they only knewhash_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. $\endgroup$