In SCRAM (RFC5802, page 8) the client generates ClientKey to server, which is a derivation of the original password. This is communicated to the server in a secure fashion, which then performs a single hash operation H(ClientKey) and check if that's equal to StoredKey. That is, the client proves knowledge of something which, when hashed, equals something stored on the server.

I understand that SCRAM puts a lot of steps in between to include a challenge-response mechanism and never actually sending the real key over the wire and such. However, I don't to see how this is conceptually different from sending PlaintextPassword and comparing it to the server's H(PlaintextPassword). Note that this is a single hash operation, not the original PBKDF2 used to derive ClientKey in the first place. In SCRAM wouldn't the ClientKey be just as sensitive as PlaintextPassword? If an attacker were to gain knowledge of ClientKey then PlaintextPassword is not needed anymore. Since it's only secured in storage using a single hash operation, doesn't this make SCRAM in it's defined implementation vulnerable to rainbow tables on a leaked database?

Bonus question: would there be any problem with taking that single hash operation and replacing it with something stronger, like another round of PBKDF2 or even scrypt?

  • $\begingroup$ I'm not sure you are describing the algorithm correctly (so I won't answer yet). Sending the PlaintextPassword directly would allow an attacker to bruteforce a stored H(PlaintextPassword) without going through all the iterations, and it would allow the server to impersonate the client, which go against goals 1 & 2 written in section 1 of the RFC. $\endgroup$ – Maarten Bodewes Nov 28 '15 at 13:38
  • $\begingroup$ (of course the above comment still doesn't explain that testing all possible values of the outcome of Hi(Normalize(password), salt, i) against the server is much harder than testing password. This should be included in any answer given I suspect). $\endgroup$ – Maarten Bodewes Nov 28 '15 at 13:42
  • $\begingroup$ @MaartenBodewes Sorry perhaps I wasn't clear, I know the stored key isn't H(PlaintextPassword), I was merely using it as a way of comparison. The relevant parts of the RFC are: SaltedPassword := Hi(Normalize(password), salt, i), ClientKey := HMAC(SaltedPassword, "Client Key"), StoredKey := H(ClientKey). Ultimately the step between ClientKey and StoredKey is a single hash operation. Perhaps there's something I'm missing that makes extra safety here unnecessary? $\endgroup$ – KennethJ Nov 28 '15 at 14:54
  • $\begingroup$ You'd still need the salt and password to generate the client key. The client key is big enough that it cannot be brute forced. Now if you steal the DB you still could not log in because you don't know the client key. You cannot brute force the password because you still need the PBKDF of SCRAM for that. You could put the PBKDF in the server, but that would mean that you put all the CPU requirements at the server as well. I'm a bit lost how I'm going to put this into an answer... Let me think about that. $\endgroup$ – Maarten Bodewes Nov 28 '15 at 16:51
  • $\begingroup$ So what you're saying is that the reason we need key stretching from PBKDF2 is because passwords generally have low entropy, but because we're hashing the output of PBKDF2, we don't have to worry about brute forcing and rainbow tables and the like in this case? $\endgroup$ – KennethJ Nov 29 '15 at 12:18

Your Answer

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

Browse other questions tagged or ask your own question.