4
\$\begingroup\$

I'm implementing a login system on app engine (I have to, so please don't tell me to use the User service, or an other way to delegate authentication), and I'm wondering whether this setup is secure.

from pbkdf2 import PBKDF2
import os

salt = os.urandom(8)    
password = PBKDF2(passphrase, salt).read(32).encode("hex")

Would this be a secure way to store passwords?

\$\endgroup\$
  • 2
    \$\begingroup\$ If you're building something to last, it's also worth asking: what do I do if this ceases to be secure? PBKDF2, like bcrypt etc., has a difficulty parameter; it would be advisable to pass an explicit parameter (even if it is the same as the default values), and to store that parameter in the database. E.g. password = '1000:' + PBKDF2(passphrase, salt, 1000).read(32).encode('hex'). That way you can increase the difficulty parameter as computers get faster and upgrade old users' hashes when they log in. \$\endgroup\$ – Peter Taylor Apr 4 '13 at 9:17
  • \$\begingroup\$ THX, I ADDED THAT \$\endgroup\$ – bigblind Oct 7 '13 at 12:22
5
\$\begingroup\$

Pretty much, yes. PBKDF2 is a well-established algorithm, and os.urandom is a suitable CSPRNG that can be used in salt generation on all major platforms (patched, of course).

Your implementation is also brutally simple. The simpler a system, the more secure it can be. Needless complexity leads to insecurities.

So yes, the system is secure, but it is also subject to Moore's law, just like every other computer system or piece of software. To get around this, the number of rounds (iterations) in strong encryption algorithms is a variable taken into account.

In bcrypt, for example, the number of rounds is 2^workload (default 12), and in PBKDF2 the number of rounds is an int passed to the function. Beware that if you need to use a Cython interface, your password hashing is a strongly blocking call (this has bitten me before)

\$\endgroup\$
2
\$\begingroup\$

Another consideration is that it is becoming better practice to iteratively generate the hash. (Of course, this is only useful if the hashing algorithm isn't a set, but they tend not to be.)

The purpose of this is to hash the hash multiple (say 100) times. This can dramatically increase the amount of time required to break the hashes should they be compromised. Additionally, a precomputed table of hashes becomes really prohibitive since you are no longer dealing simply with a salted hash of a known algorithm.

\$\endgroup\$
0
\$\begingroup\$
  1. The salt should be the same size as the hash.
  2. As noted by the other answers, always pass in the work units parameter so that you can upgrade the strength of the key stretching over time.
  3. When you compare hashes during authentication, use a constant time algorithm.
\$\endgroup\$
  • \$\begingroup\$ Why was this downvoted? If something is wrong with the answer, say so in a comment so it can be corrected. \$\endgroup\$ – Eric Elliott May 7 '14 at 17:08

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.