The salt for PBKDF2 can be bytes or a string

This commit is contained in:
Helder Eijs 2018-02-24 22:12:29 +01:00
parent 25c6c1e6a0
commit 45ddf281d8
3 changed files with 18 additions and 6 deletions

View file

@ -12,6 +12,7 @@ New features
* Faster PBKDF2 for HMAC-based PRFs (at least 20x for short passwords, * Faster PBKDF2 for HMAC-based PRFs (at least 20x for short passwords,
more for longer passwords). Thanks to Christian Heimes for pointing more for longer passwords). Thanks to Christian Heimes for pointing
out the implementation was under-optimized. out the implementation was under-optimized.
* The salt for PBKDF2 can be either a string or bytes (GH#67).
3.4.12 (5 February 2018) 3.4.12 (5 February 2018)
++++++++++++++++++++++++ ++++++++++++++++++++++++

View file

@ -101,10 +101,10 @@ def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None
the PKCS#5 standard (v2.0). the PKCS#5 standard (v2.0).
Args: Args:
password (string): password (string or byte string):
The secret password to generate the key from. The secret password to generate the key from.
salt (string): salt (string or byte string):
A string to use for better protection from dictionary attacks. A (byte) string to use for better protection from dictionary attacks.
This value does not need to be kept secret, but it should be randomly This value does not need to be kept secret, but it should be randomly
chosen for each derivation. It is recommended to be at least 8 bytes long. chosen for each derivation. It is recommended to be at least 8 bytes long.
dkLen (integer): dkLen (integer):
@ -126,6 +126,7 @@ def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None
""" """
password = tobytes(password) password = tobytes(password)
salt = tobytes(salt)
if prf and hmac_hash_module: if prf and hmac_hash_module:
raise ValueError("'prf' and 'hmac_hash_module' are mutually exlusive") raise ValueError("'prf' and 'hmac_hash_module' are mutually exlusive")
@ -138,11 +139,11 @@ def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None
if prf is None: if prf is None:
prf = lambda p,s: HMAC.new(p, s, hmac_hash_module).digest() prf = lambda p,s: HMAC.new(p, s, hmac_hash_module).digest()
def link(s): def link(s):
s[0], s[1] = s[1], prf(password, s[1]) s[0], s[1] = s[1], prf(password, s[1])
return s[0] return s[0]
key = b('') key = b('')
i = 1 i = 1
while len(key)<dkLen: while len(key)<dkLen:
@ -159,7 +160,7 @@ def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None
first_digest = base.copy().update(salt + struct.pack(">I", i)).digest() first_digest = base.copy().update(salt + struct.pack(">I", i)).digest()
key += base._pbkdf2_hmac_assist(first_digest, count) key += base._pbkdf2_hmac_assist(first_digest, count)
i += 1 i += 1
return key[:dkLen] return key[:dkLen]

View file

@ -137,6 +137,16 @@ class PBKDF2_Tests(unittest.TestCase):
self.assertEqual(pr1, pr2) self.assertEqual(pr1, pr2)
def test4(self):
# Verify that PBKDF2 can take bytes or strings as password or salt
k1 = PBKDF2("xxx", b("yyy"), 16, 10)
k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10)
self.assertEqual(k1, k2)
k1 = PBKDF2(b("xxx"), "yyy", 16, 10)
k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10)
self.assertEqual(k1, k2)
class S2V_Tests(unittest.TestCase): class S2V_Tests(unittest.TestCase):