Permalink
Browse files

PBKDF2 with cached HMAC key

This gives a 2x speed increase and removes the ability to DoS with large passwords.

Sorry this is my hello world for Python, and I don't even know how to run it. It probably works but you should test it.
  • Loading branch information...
1 parent 5be56d0 commit 2d2c6c2cad68603cb179f0c22183bb08ad8171ed @Sc00bz committed Sep 17, 2013
Showing with 20 additions and 1 deletion.
  1. +20 −1 django/utils/crypto.py
@@ -133,6 +133,18 @@ def _fast_hmac(key, msg, digest):
return dig2
+def _cached_hmac(msg, inner, outer):
+ """
+ A trimmed down version of Python's HMAC implementation.
+
+ This function operates on bytes.
+ """
+ dig1, dig2 = inner.copy(), outer.copy()
+ dig1.update(msg)
+ dig2.update(dig1.digest())
+ return dig2
+
+
def pbkdf2(password, salt, iterations, dklen=0, digest=None):
"""
Implements PBKDF2 as defined in RFC 2898, section 5.2
@@ -160,11 +172,18 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None):
hex_format_string = "%%0%ix" % (hlen * 2)
+ inner, outer = digest(), digest()
+ if len(password) > inner.block_size:
+ password = digest(password).digest()
+ password += b'\x00' * (inner.block_size - len(password))
+ inner.update(password.translate(hmac.trans_36))
+ outer.update(password.translate(hmac.trans_5C))
+
def F(i):
def U():
u = salt + struct.pack(b'>I', i)
for j in xrange(int(iterations)):
- u = _fast_hmac(password, u, digest).digest()
+ u = _cached_hmac(u, inner, outer).digest()
yield _bin_to_long(u)
return _long_to_bin(reduce(operator.xor, U()), hex_format_string)

0 comments on commit 2d2c6c2

Please sign in to comment.