diff options
| author | Florian Apolloner <florian@apolloner.eu> | 2013-09-17 18:14:38 -0500 |
|---|---|---|
| committer | Florian Apolloner <florian@apolloner.eu> | 2013-10-21 19:54:47 +0200 |
| commit | 1e4f53a6eb8d1816e51eb8bd8f95e704f6b89ead (patch) | |
| tree | 1476ee7a013519fdb646b0f43fc61c50337f25cc /django/utils/crypto.py | |
| parent | 1e39982b6ef1fd10e53392f4cb52bea3805d186f (diff) | |
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.
Diffstat (limited to 'django/utils/crypto.py')
| -rw-r--r-- | django/utils/crypto.py | 29 |
1 files changed, 9 insertions, 20 deletions
diff --git a/django/utils/crypto.py b/django/utils/crypto.py index cb5e06efd2..14c1df82f2 100644 --- a/django/utils/crypto.py +++ b/django/utils/crypto.py @@ -116,22 +116,6 @@ def _long_to_bin(x, hex_format_string): return binascii.unhexlify((hex_format_string % x).encode('ascii')) -def _fast_hmac(key, msg, digest): - """ - A trimmed down version of Python's HMAC implementation. - - This function operates on bytes. - """ - dig1, dig2 = digest(), digest() - if len(key) != dig1.block_size: - raise ValueError('Key size needs to match the block_size of the digest.') - dig1.update(key.translate(hmac.trans_36)) - dig1.update(msg) - dig2.update(key.translate(hmac.trans_5C)) - 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,16 +144,21 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None): hex_format_string = "%%0%ix" % (hlen * 2) - inner_digest_size = digest().block_size - if len(password) > inner_digest_size: + inner, outer = digest(), digest() + if len(password) > inner.block_size: password = digest(password).digest() - password += b'\x00' * (inner_digest_size - len(password)) + 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() + dig1, dig2 = inner.copy(), outer.copy() + dig1.update(u) + dig2.update(dig1.digest()) + u = dig2.digest() yield _bin_to_long(u) return _long_to_bin(reduce(operator.xor, U()), hex_format_string) |
