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.
This commit is contained in:
parent
1e39982b6e
commit
1e4f53a6eb
|
@ -116,22 +116,6 @@ def _long_to_bin(x, hex_format_string):
|
||||||
return binascii.unhexlify((hex_format_string % x).encode('ascii'))
|
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):
|
def pbkdf2(password, salt, iterations, dklen=0, digest=None):
|
||||||
"""
|
"""
|
||||||
Implements PBKDF2 as defined in RFC 2898, section 5.2
|
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)
|
hex_format_string = "%%0%ix" % (hlen * 2)
|
||||||
|
|
||||||
inner_digest_size = digest().block_size
|
inner, outer = digest(), digest()
|
||||||
if len(password) > inner_digest_size:
|
if len(password) > inner.block_size:
|
||||||
password = digest(password).digest()
|
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 F(i):
|
||||||
def U():
|
def U():
|
||||||
u = salt + struct.pack(b'>I', i)
|
u = salt + struct.pack(b'>I', i)
|
||||||
for j in xrange(int(iterations)):
|
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)
|
yield _bin_to_long(u)
|
||||||
return _long_to_bin(reduce(operator.xor, U()), hex_format_string)
|
return _long_to_bin(reduce(operator.xor, U()), hex_format_string)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue