I would ask you some questions about users' password storage in a login system.

  1. What algorithm do you suggest me to use? bcrypt or PBKDF2?

I was looking for a way to implement them client-side and i thought this way:

The client computes 10.000 iteractions of user's password with PBKDF2 and username (or email) as SALT and the server will store in the DB the salted SHA-512 digest of the PBKDF2 result.

  1. Is it a good way?
  2. Is client-side key stretching good in general? Does it have some disadvantages compared to the server-side implementation?
  3. Is there a better way to implement PBKDF2 client-side?
  4. And what about bcrypt?

  5. If I use bcrypt server-side, what's the best way to add a pepper?

  6. Adding pepper has some disadvantage?
  • $\begingroup$ This question appears to be off-topic because it is about Implementation. Probable belongs on Security SE. $\endgroup$
    – minar
    Jul 18 '13 at 6:17

What's your motivation for slow-hashing on the client-side?

  • It may well be slower than if performed server side (if you're referring to a browser-based application, and the hashing is done with javascript, then it will certainly be slower, even more so if it's a mobile device)
  • it doesn't provide any extra security, the credential(s) (password, hash of the password, salt derived from password which will be used for hashing the password, whatever...) will still need to be transmitted to the server - there's no way to avoid that

Keep it simple - you're much less likely to introduce some sort of vulnerability into your system. The following protocol is pretty standard:

  • send the client's username/password to the server over TLS/SSL (it's worth the effort, really)
  • slow-hash the client's password with either Scrypt (preferable), or PBKDF2-SHA256 (at least 100'000 iterations) and a user-specific salt (stored in the DB with the hash)
  • for each login attempt, compare the output of the above with the hash you have stored in the DB

Note: Bcrypt is fine, some people fetishize it, others prefer PBKDF2 because it's more 'standard' (and it's output length is configurable). Scrypt is the state-of-the-art, although it's less widely used, and can be more complicated to implement.


After further consideration, and better understanding exactly what you're asking (I think), I'm going to say yes: what you're proposing is fine, provided certain conditions are met. The issue that @StephenTouset pointed out is valid, and has to be avoided. However, if I understand your question correctly, then you're already mitigating that weakness. Consider the following:

  1. Client slow-hashes password with PBKDF2 or Scrypt (use of email address or username as salt is questionable - email addresses change and usernames could be used in dictionary attacks). This initial slow-hashing mitigates dictionary attacks, and offloads the heavy work from the server to the client

  2. Client submits the output of the slow-hash (256 bits) to the server (over TLS/SSL), where it is then hashed once with SHA-256 (no salt necessary) and compared with the hash stored in the database.

Should the database be compromised, an attacker would still need to brute-force the hash of a 256-bit value (the client-side slow-hash output) to verify a correct guess at the password, pretty much rendering the hashes stored in the database useless to an attacker.

I think the theory is fine. In practise, I think it's a bit messy and maybe unwarranted (your comment mentioned up to 1000 login attempts per second, are you really anticipating up to 86 million logins per day??). Only you can decide whether you can justify it.

  • $\begingroup$ It's not that it provides no extra security. It actually removes security. Now the hash stored in the database is the user's exact login credentials. If someone gets the hash database, they can just submit the hashed password and be logged in. $\endgroup$ Jul 17 '13 at 0:19
  • $\begingroup$ @StephenTouset - agreed - assuming that's what the OP is proposing, which frankly, is a bit unclear... "10.000 iteractions of user's password with PBKDF2 and username (or email) as SALT and the server will store in the DB the salted SHA-512 digest of the PBKDF2 result". All the more reason to stick with a standard protocol. $\endgroup$
    – hunter
    Jul 17 '13 at 0:32
  • $\begingroup$ What's your motivation for slow-hashing on the client-side? I'm not going to use the client-side slow-hashing as a replace of SSL... All the communications will be over SSL anyway. I would do it simply because my system could receive even 1000 login requests per second in the moments of high-load, so with server-side slow-hashing, it could be a problem! It's not a web-server application but a Delphi Client/Server application. Does anyone know if there is a Scrypt implementation in Delphi? $\endgroup$
    – user28369
    Jul 17 '13 at 15:24
  • $\begingroup$ Ok maybe 1000 logins per second is a bit exaggerated but 100 yes, it's possible! Considering that the server has also to decrypt RSA-2048 for SSL handshake, with Bcrypt (cost 10) + RSA it takes around 300ms on the server (tested) so it could potentially be a self-DoSsing! I thought this is the better thing: client-sidePBKDF2-SHA256 (64,000 iteractions with UPPERCASE username as salt). The result is sent to the server; the server hashes the result once (SHA256 or SHA512) with salt + pepper: ToStoreInDB = HMAC-SHA256($pbkdf2_result.$salt, $pepper). Please tell me if i'm in the right way! $\endgroup$
    – user28369
    Jul 17 '13 at 21:24
  • $\begingroup$ I'm just confused about using UPPERCASE username as SALT for PBKFD2... Could it be a weakness? $\endgroup$
    – user28369
    Jul 17 '13 at 21:26

To answer the "pepper" part of the question:

  • Generate a cryptographically random secret key 256 bits in length.
  • Any time a user submits a password:

    1. compute hmac = HMAC-SHA-256(key, password)
    2. submit hmac to the slow-hash instead of the password

Bcrypt is slow, since it uses Blowfish (and insecure, due to the fact that it has 64-bit block, though it could be extended to 128-bit block [which I will call Blow128]) I would recommend PBKDF2. Taking the SHA-512 hash of the PBKDF2 result is bad, because chaining two hash functions (even though PBKDF2 is not a hash function) For the other questions, I would consider editing the question so I could answer it fully.

I recommend Bcrypt, even though PBKDF2 is another choice. Still SHA-512 of PBKDF2 would be bad, because $H_{1}(H_{2}(X))$ is bad (despite the fact that PBKDF2 is not a hash function). Besides, what I thought is slow hashing was nothing. The main goal of hash functions are they be fast but secure. So basically I was against the hash functions. By slow hashing you might mean moderate slow hashing, because you don't want a digital signature algorithm to take a week, to process a 1 MB PDF.

  • 2
    $\begingroup$ How does having a 64-bit block make bcrypt insecure? $\endgroup$
    – David
    Jul 17 '13 at 4:03
  • $\begingroup$ @GavrielFeria - BCrypt is slow by design, that's the point of a slow hash function... you talk about BCrypt being slow like it's an undesirable quality. Also, 64-bit block ciphers are not inherently insecure in all contexts, but aside from that - you certainly can't go around changing the block size of crypto algorithms and expect them to be as secure as the original design. $\endgroup$
    – hunter
    Jul 17 '13 at 11:19
  • $\begingroup$ Sometimes being slow is an undesirable quality, now I know you need a slow hash function. Still, I read from another article that PBKDF2 is slower; by a mere 5 ms. $\endgroup$ Jul 17 '13 at 22:23

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.