1
0
mirror of https://github.com/django/django.git synced 2025-10-26 07:06:08 +00:00

Fixed #32275 -- Added scrypt password hasher.

Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
This commit is contained in:
ryowright
2020-12-26 18:54:47 -08:00
committed by Mariusz Felisiak
parent 65b880b726
commit 1783b3cb24
6 changed files with 231 additions and 2 deletions

View File

@@ -520,6 +520,7 @@ PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.ScryptPasswordHasher',
]
AUTH_PASSWORD_VALIDATORS = []

View File

@@ -517,6 +517,81 @@ class BCryptPasswordHasher(BCryptSHA256PasswordHasher):
digest = None
class ScryptPasswordHasher(BasePasswordHasher):
"""
Secure password hashing using the Scrypt algorithm.
"""
algorithm = 'scrypt'
block_size = 8
maxmem = 0
parallelism = 1
work_factor = 2 ** 14
def encode(self, password, salt, n=None, r=None, p=None):
self._check_encode_args(password, salt)
n = n or self.work_factor
r = r or self.block_size
p = p or self.parallelism
hash_ = hashlib.scrypt(
password.encode(),
salt=salt.encode(),
n=n,
r=r,
p=p,
maxmem=self.maxmem,
dklen=64,
)
hash_ = base64.b64encode(hash_).decode('ascii').strip()
return '%s$%d$%s$%d$%d$%s' % (self.algorithm, n, salt, r, p, hash_)
def decode(self, encoded):
algorithm, work_factor, salt, block_size, parallelism, hash_ = encoded.split('$', 6)
assert algorithm == self.algorithm
return {
'algorithm': algorithm,
'work_factor': int(work_factor),
'salt': salt,
'block_size': int(block_size),
'parallelism': int(parallelism),
'hash': hash_,
}
def verify(self, password, encoded):
decoded = self.decode(encoded)
encoded_2 = self.encode(
password,
decoded['salt'],
decoded['work_factor'],
decoded['block_size'],
decoded['parallelism'],
)
return constant_time_compare(encoded, encoded_2)
def safe_summary(self, encoded):
decoded = self.decode(encoded)
return {
_('algorithm'): decoded['algorithm'],
_('work factor'): decoded['work_factor'],
_('block size'): decoded['block_size'],
_('parallelism'): decoded['parallelism'],
_('salt'): mask_hash(decoded['salt']),
_('hash'): mask_hash(decoded['hash']),
}
def must_update(self, encoded):
decoded = self.decode(encoded)
return (
decoded['work_factor'] != self.work_factor or
decoded['block_size'] != self.block_size or
decoded['parallelism'] != self.parallelism
)
def harden_runtime(self, password, encoded):
# The runtime for Scrypt is too complicated to implement a sensible
# hardening algorithm.
pass
class SHA1PasswordHasher(BasePasswordHasher):
"""
The SHA1 password hashing algorithm (not recommended)