Refs #30472 -- Simplified Argon2PasswordHasher with argon2-cffi 19.1+ API.
This commit is contained in:
parent
ee49cf4f35
commit
faad809e09
|
@ -307,14 +307,15 @@ class Argon2PasswordHasher(BasePasswordHasher):
|
||||||
|
|
||||||
def encode(self, password, salt):
|
def encode(self, password, salt):
|
||||||
argon2 = self._load_library()
|
argon2 = self._load_library()
|
||||||
|
params = self.params()
|
||||||
data = argon2.low_level.hash_secret(
|
data = argon2.low_level.hash_secret(
|
||||||
password.encode(),
|
password.encode(),
|
||||||
salt.encode(),
|
salt.encode(),
|
||||||
time_cost=self.time_cost,
|
time_cost=params.time_cost,
|
||||||
memory_cost=self.memory_cost,
|
memory_cost=params.memory_cost,
|
||||||
parallelism=self.parallelism,
|
parallelism=params.parallelism,
|
||||||
hash_len=argon2.DEFAULT_HASH_LENGTH,
|
hash_len=params.hash_len,
|
||||||
type=argon2.low_level.Type.I,
|
type=params.type,
|
||||||
)
|
)
|
||||||
return self.algorithm + data.decode('ascii')
|
return self.algorithm + data.decode('ascii')
|
||||||
|
|
||||||
|
@ -323,11 +324,7 @@ class Argon2PasswordHasher(BasePasswordHasher):
|
||||||
algorithm, rest = encoded.split('$', 1)
|
algorithm, rest = encoded.split('$', 1)
|
||||||
assert algorithm == self.algorithm
|
assert algorithm == self.algorithm
|
||||||
try:
|
try:
|
||||||
return argon2.low_level.verify_secret(
|
return argon2.PasswordHasher().verify('$' + rest, password)
|
||||||
('$' + rest).encode('ascii'),
|
|
||||||
password.encode(),
|
|
||||||
type=argon2.low_level.Type.I,
|
|
||||||
)
|
|
||||||
except argon2.exceptions.VerificationError:
|
except argon2.exceptions.VerificationError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -347,22 +344,34 @@ class Argon2PasswordHasher(BasePasswordHasher):
|
||||||
}
|
}
|
||||||
|
|
||||||
def must_update(self, encoded):
|
def must_update(self, encoded):
|
||||||
(algorithm, variety, version, time_cost, memory_cost, parallelism,
|
algorithm, rest = encoded.split('$', 1)
|
||||||
salt, data) = self._decode(encoded)
|
|
||||||
assert algorithm == self.algorithm
|
assert algorithm == self.algorithm
|
||||||
argon2 = self._load_library()
|
argon2 = self._load_library()
|
||||||
return (
|
current_params = argon2.extract_parameters('$' + rest)
|
||||||
argon2.low_level.ARGON2_VERSION != version or
|
new_params = self.params()
|
||||||
self.time_cost != time_cost or
|
# Set salt_len to the salt_len of the current parameters because salt
|
||||||
self.memory_cost != memory_cost or
|
# is explicitly passed to argon2.
|
||||||
self.parallelism != parallelism
|
new_params.salt_len = current_params.salt_len
|
||||||
)
|
return current_params != new_params
|
||||||
|
|
||||||
def harden_runtime(self, password, encoded):
|
def harden_runtime(self, password, encoded):
|
||||||
# The runtime for Argon2 is too complicated to implement a sensible
|
# The runtime for Argon2 is too complicated to implement a sensible
|
||||||
# hardening algorithm.
|
# hardening algorithm.
|
||||||
pass
|
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):
|
def _decode(self, encoded):
|
||||||
"""
|
"""
|
||||||
Split an encoded hash and return: (
|
Split an encoded hash and return: (
|
||||||
|
@ -370,24 +379,13 @@ class Argon2PasswordHasher(BasePasswordHasher):
|
||||||
parallelism, salt, data,
|
parallelism, salt, data,
|
||||||
).
|
).
|
||||||
"""
|
"""
|
||||||
bits = encoded.split('$')
|
argon2 = self._load_library()
|
||||||
if len(bits) == 5:
|
algorithm, rest = encoded.split('$', 1)
|
||||||
# Argon2 < 1.3
|
params = argon2.extract_parameters('$' + rest)
|
||||||
algorithm, variety, raw_params, salt, data = bits
|
variety, *_, salt, data = rest.split('$')
|
||||||
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'])
|
|
||||||
return (
|
return (
|
||||||
algorithm, variety, version, time_cost, memory_cost, parallelism,
|
algorithm, variety, params.version, params.time_cost,
|
||||||
salt, data,
|
params.memory_cost, params.parallelism, salt, data,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
If you want to run the full suite of tests, you'll need to install a number of
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
||||||
* argon2-cffi_ 16.1.0+
|
* argon2-cffi_ 19.1.0+
|
||||||
* asgiref_ 3.2+ (required)
|
* asgiref_ 3.2+ (required)
|
||||||
* bcrypt_
|
* bcrypt_
|
||||||
* docutils_
|
* docutils_
|
||||||
|
|
|
@ -324,6 +324,8 @@ Miscellaneous
|
||||||
* The :tfilter:`intcomma` and :tfilter:`intword` template filters no longer
|
* The :tfilter:`intcomma` and :tfilter:`intword` template filters no longer
|
||||||
depend on the :setting:`USE_L10N` setting.
|
depend on the :setting:`USE_L10N` setting.
|
||||||
|
|
||||||
|
* Support for ``argon2-cffi`` < 19.1.0 is removed.
|
||||||
|
|
||||||
.. _deprecated-features-3.2:
|
.. _deprecated-features-3.2:
|
||||||
|
|
||||||
Features deprecated in 3.2
|
Features deprecated in 3.2
|
||||||
|
|
|
@ -49,7 +49,7 @@ console_scripts =
|
||||||
django-admin = django.core.management:execute_from_command_line
|
django-admin = django.core.management:execute_from_command_line
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
argon2 = argon2-cffi >= 16.1.0
|
argon2 = argon2-cffi >= 19.1.0
|
||||||
bcrypt = bcrypt
|
bcrypt = bcrypt
|
||||||
|
|
||||||
[bdist_rpm]
|
[bdist_rpm]
|
||||||
|
|
Loading…
Reference in New Issue