summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Apolloner <florian@apolloner.eu>2020-06-17 07:46:45 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-06-17 08:10:41 +0200
commitfaad809e09af5617f1cda579f5b031233be21cb3 (patch)
tree1521a32f772e8457c803585537a8793b4256603c
parentee49cf4f35a3850ef0ef51077fd5e468d30b76b3 (diff)
Refs #30472 -- Simplified Argon2PasswordHasher with argon2-cffi 19.1+ API.
-rw-r--r--django/contrib/auth/hashers.py68
-rw-r--r--docs/internals/contributing/writing-code/unit-tests.txt2
-rw-r--r--docs/releases/3.2.txt2
-rw-r--r--setup.cfg2
4 files changed, 37 insertions, 37 deletions
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index 29cba3fd5c..344176be69 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -307,14 +307,15 @@ class Argon2PasswordHasher(BasePasswordHasher):
def encode(self, password, salt):
argon2 = self._load_library()
+ params = self.params()
data = argon2.low_level.hash_secret(
password.encode(),
salt.encode(),
- time_cost=self.time_cost,
- memory_cost=self.memory_cost,
- parallelism=self.parallelism,
- hash_len=argon2.DEFAULT_HASH_LENGTH,
- type=argon2.low_level.Type.I,
+ time_cost=params.time_cost,
+ memory_cost=params.memory_cost,
+ parallelism=params.parallelism,
+ hash_len=params.hash_len,
+ type=params.type,
)
return self.algorithm + data.decode('ascii')
@@ -323,11 +324,7 @@ class Argon2PasswordHasher(BasePasswordHasher):
algorithm, rest = encoded.split('$', 1)
assert algorithm == self.algorithm
try:
- return argon2.low_level.verify_secret(
- ('$' + rest).encode('ascii'),
- password.encode(),
- type=argon2.low_level.Type.I,
- )
+ return argon2.PasswordHasher().verify('$' + rest, password)
except argon2.exceptions.VerificationError:
return False
@@ -347,22 +344,34 @@ class Argon2PasswordHasher(BasePasswordHasher):
}
def must_update(self, encoded):
- (algorithm, variety, version, time_cost, memory_cost, parallelism,
- salt, data) = self._decode(encoded)
+ algorithm, rest = encoded.split('$', 1)
assert algorithm == self.algorithm
argon2 = self._load_library()
- return (
- argon2.low_level.ARGON2_VERSION != version or
- self.time_cost != time_cost or
- self.memory_cost != memory_cost or
- self.parallelism != parallelism
- )
+ current_params = argon2.extract_parameters('$' + rest)
+ new_params = self.params()
+ # Set salt_len to the salt_len of the current parameters because salt
+ # is explicitly passed to argon2.
+ new_params.salt_len = current_params.salt_len
+ return current_params != new_params
def harden_runtime(self, password, encoded):
# The runtime for Argon2 is too complicated to implement a sensible
# hardening algorithm.
pass
+ def params(self):
+ argon2 = self._load_library()
+ # salt_len is a noop, because we provide our own salt.
+ return argon2.Parameters(
+ type=argon2.low_level.Type.I,
+ version=argon2.low_level.ARGON2_VERSION,
+ salt_len=argon2.DEFAULT_RANDOM_SALT_LENGTH,
+ hash_len=argon2.DEFAULT_HASH_LENGTH,
+ time_cost=self.time_cost,
+ memory_cost=self.memory_cost,
+ parallelism=self.parallelism,
+ )
+
def _decode(self, encoded):
"""
Split an encoded hash and return: (
@@ -370,24 +379,13 @@ class Argon2PasswordHasher(BasePasswordHasher):
parallelism, salt, data,
).
"""
- bits = encoded.split('$')
- if len(bits) == 5:
- # Argon2 < 1.3
- algorithm, variety, raw_params, salt, data = bits
- version = 0x10
- else:
- assert len(bits) == 6
- algorithm, variety, raw_version, raw_params, salt, data = bits
- assert raw_version.startswith('v=')
- version = int(raw_version[len('v='):])
- params = dict(bit.split('=', 1) for bit in raw_params.split(','))
- assert len(params) == 3 and all(x in params for x in ('t', 'm', 'p'))
- time_cost = int(params['t'])
- memory_cost = int(params['m'])
- parallelism = int(params['p'])
+ argon2 = self._load_library()
+ algorithm, rest = encoded.split('$', 1)
+ params = argon2.extract_parameters('$' + rest)
+ variety, *_, salt, data = rest.split('$')
return (
- algorithm, variety, version, time_cost, memory_cost, parallelism,
- salt, data,
+ algorithm, variety, params.version, params.time_cost,
+ params.memory_cost, params.parallelism, salt, data,
)
diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt
index deaa5a0b19..f8c1347abc 100644
--- a/docs/internals/contributing/writing-code/unit-tests.txt
+++ b/docs/internals/contributing/writing-code/unit-tests.txt
@@ -270,7 +270,7 @@ Running all the tests
If you want to run the full suite of tests, you'll need to install a number of
dependencies:
-* argon2-cffi_ 16.1.0+
+* argon2-cffi_ 19.1.0+
* asgiref_ 3.2+ (required)
* bcrypt_
* docutils_
diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt
index 1bb4dbed1e..11da13daba 100644
--- a/docs/releases/3.2.txt
+++ b/docs/releases/3.2.txt
@@ -324,6 +324,8 @@ Miscellaneous
* The :tfilter:`intcomma` and :tfilter:`intword` template filters no longer
depend on the :setting:`USE_L10N` setting.
+* Support for ``argon2-cffi`` < 19.1.0 is removed.
+
.. _deprecated-features-3.2:
Features deprecated in 3.2
diff --git a/setup.cfg b/setup.cfg
index 6ce81ec081..0c1ff825fb 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -49,7 +49,7 @@ console_scripts =
django-admin = django.core.management:execute_from_command_line
[options.extras_require]
-argon2 = argon2-cffi >= 16.1.0
+argon2 = argon2-cffi >= 19.1.0
bcrypt = bcrypt
[bdist_rpm]