summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Apolloner <florian@apolloner.eu>2020-12-27 17:25:22 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-12-28 11:02:08 +0100
commitc76d51b3ad34bc2ed2155054bfb283ef53beb26a (patch)
treeb2f03a405dec74ef8a39d559d3c17862648d2ed4
parent1b7086b2ea4c06d9c4b9233c166a16fe4390c877 (diff)
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).
-rw-r--r--django/contrib/auth/hashers.py5
-rw-r--r--tests/auth_tests/test_hashers.py10
2 files changed, 14 insertions, 1 deletions
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index 99d3d5ff6a..0e44614fcb 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -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,
diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py
index ec056660b7..55c436b993 100644
--- a/tests/auth_tests/test_hashers.py
+++ b/tests/auth_tests/test_hashers.py
@@ -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)