Skip to content

Commit

Permalink
Refs #30472 -- Simplified Argon2PasswordHasher with argon2-cffi 19.1+…
Browse files Browse the repository at this point in the history
… API.
  • Loading branch information
apollo13 authored and felixxm committed Jun 17, 2020
1 parent ee49cf4 commit faad809
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 37 deletions.
68 changes: 33 additions & 35 deletions django/contrib/auth/hashers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand All @@ -323,11 +324,7 @@ def verify(self, password, encoded):
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

Expand All @@ -347,47 +344,48 @@ def safe_summary(self, encoded):
}

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: (
algorithm, variety, version, time_cost, memory_cost,
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,
)


Expand Down
2 changes: 1 addition & 1 deletion docs/internals/contributing/writing-code/unit-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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_
Expand Down
2 changes: 2 additions & 0 deletions docs/releases/3.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down

0 comments on commit faad809

Please sign in to comment.