Refs #31358 -- Fixed decoding salt in Argon2PasswordHasher.

Argon2 encodes the salt as base64 for representation in the final hash
output. To be able to accurately return the used salt from decode(),
add padding, b64decode, and decode from latin1 (for the remote
possibility that someone supplied a custom hash consisting solely of
bytes -- this would require a manual construction of the hash though,
Django's interface does not allow for that).
This commit is contained in:
Florian Apolloner 2020-12-27 17:25:22 +01:00 committed by Mariusz Felisiak
parent 1b7086b2ea
commit c76d51b3ad
2 changed files with 14 additions and 1 deletions

View File

@ -344,7 +344,10 @@ class Argon2PasswordHasher(BasePasswordHasher):
algorithm, rest = encoded.split('$', 1)
assert algorithm == self.algorithm
params = argon2.extract_parameters('$' + rest)
variety, *_, salt, hash = rest.split('$')
variety, *_, b64salt, hash = rest.split('$')
# Add padding.
b64salt += '=' * (-len(b64salt) % 4)
salt = base64.b64decode(b64salt).decode('latin1')
return {
'algorithm': algorithm,
'hash': hash,

View File

@ -526,6 +526,16 @@ class TestUtilsHashPassArgon2(SimpleTestCase):
self.assertIs(check_password('secret', encoded), True)
self.assertIs(check_password('wrong', encoded), False)
def test_argon2_decode(self):
salt = 'abcdefghijk'
encoded = make_password('lètmein', salt=salt, hasher='argon2')
hasher = get_hasher('argon2')
decoded = hasher.decode(encoded)
self.assertEqual(decoded['memory_cost'], hasher.memory_cost)
self.assertEqual(decoded['parallelism'], hasher.parallelism)
self.assertEqual(decoded['salt'], salt)
self.assertEqual(decoded['time_cost'], hasher.time_cost)
def test_argon2_upgrade(self):
self._test_argon2_upgrade('time_cost', 'time cost', 1)
self._test_argon2_upgrade('memory_cost', 'memory cost', 64)