Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #21253 -- PBKDF2 with cached HMAC key

This gives a 2x speed increase compared to the existing implementation.

Thanks to Steve Thomas for the initial patch and Tim Graham for finishing it.
  • Loading branch information...
commit 1e4f53a6eb8d1816e51eb8bd8f95e704f6b89ead 1 parent 1e39982
Florian Apolloner authored September 17, 2013

Showing 1 changed file with 9 additions and 20 deletions. Show diff stats Hide diff stats

  1. 29  django/utils/crypto.py
29  django/utils/crypto.py
@@ -116,22 +116,6 @@ def _long_to_bin(x, hex_format_string):
116 116
     return binascii.unhexlify((hex_format_string % x).encode('ascii'))
117 117
 
118 118
 
119  
-def _fast_hmac(key, msg, digest):
120  
-    """
121  
-    A trimmed down version of Python's HMAC implementation.
122  
-
123  
-    This function operates on bytes.
124  
-    """
125  
-    dig1, dig2 = digest(), digest()
126  
-    if len(key) != dig1.block_size:
127  
-        raise ValueError('Key size needs to match the block_size of the digest.')
128  
-    dig1.update(key.translate(hmac.trans_36))
129  
-    dig1.update(msg)
130  
-    dig2.update(key.translate(hmac.trans_5C))
131  
-    dig2.update(dig1.digest())
132  
-    return dig2
133  
-
134  
-
135 119
 def pbkdf2(password, salt, iterations, dklen=0, digest=None):
136 120
     """
137 121
     Implements PBKDF2 as defined in RFC 2898, section 5.2
@@ -160,16 +144,21 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None):
160 144
 
161 145
     hex_format_string = "%%0%ix" % (hlen * 2)
162 146
 
163  
-    inner_digest_size = digest().block_size
164  
-    if len(password) > inner_digest_size:
  147
+    inner, outer = digest(), digest()
  148
+    if len(password) > inner.block_size:
165 149
         password = digest(password).digest()
166  
-    password += b'\x00' * (inner_digest_size - len(password))
  150
+    password += b'\x00' * (inner.block_size - len(password))
  151
+    inner.update(password.translate(hmac.trans_36))
  152
+    outer.update(password.translate(hmac.trans_5C))
167 153
 
168 154
     def F(i):
169 155
         def U():
170 156
             u = salt + struct.pack(b'>I', i)
171 157
             for j in xrange(int(iterations)):
172  
-                u = _fast_hmac(password, u, digest).digest()
  158
+                dig1, dig2 = inner.copy(), outer.copy()
  159
+                dig1.update(u)
  160
+                dig2.update(dig1.digest())
  161
+                u = dig2.digest()
173 162
                 yield _bin_to_long(u)
174 163
         return _long_to_bin(reduce(operator.xor, U()), hex_format_string)
175 164
 

0 notes on commit 1e4f53a

Please sign in to comment.
Something went wrong with that request. Please try again.