Loading django/conf/global_settings.py +1 −0 Original line number Diff line number Diff line Loading @@ -500,6 +500,7 @@ PASSWORD_RESET_TIMEOUT_DAYS = 3 PASSWORD_HASHERS = [ 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ] Loading django/contrib/auth/hashers.py +73 −0 Original line number Diff line number Diff line Loading @@ -297,6 +297,79 @@ class PBKDF2SHA1PasswordHasher(PBKDF2PasswordHasher): digest = hashlib.sha1 class Argon2PasswordHasher(BasePasswordHasher): """ Secure password hashing using the argon2 algorithm. This is the winner of the Password Hashing Competition 2013-2015 (https://password-hashing.net). It requires the argon2-cffi library which depends on native C code and might cause portability issues. """ algorithm = 'argon2' library = 'argon2' time_cost = 2 memory_cost = 512 parallelism = 2 def encode(self, password, salt): argon2 = self._load_library() data = argon2.low_level.hash_secret( force_bytes(password), force_bytes(salt), 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, ) return self.algorithm + data.decode('utf-8') def verify(self, password, encoded): argon2 = self._load_library() algorithm, data = encoded.split('$', 1) assert algorithm == self.algorithm try: return argon2.low_level.verify_secret( force_bytes('$' + data), force_bytes(password), type=argon2.low_level.Type.I, ) except argon2.exceptions.VerificationError: return False def safe_summary(self, encoded): algorithm, variety, raw_pars, salt, data = encoded.split('$', 5) pars = dict(bit.split('=', 1) for bit in raw_pars.split(',')) assert algorithm == self.algorithm assert len(pars) == 3 and 't' in pars and 'm' in pars and 'p' in pars return OrderedDict([ (_('algorithm'), algorithm), (_('variety'), variety), (_('memory cost'), int(pars['m'])), (_('time cost'), int(pars['t'])), (_('parallelism'), int(pars['p'])), (_('salt'), mask_hash(salt)), (_('hash'), mask_hash(data)), ]) def must_update(self, encoded): algorithm, variety, raw_pars, salt, data = encoded.split('$', 5) pars = dict([bit.split('=', 1) for bit in raw_pars.split(',')]) assert algorithm == self.algorithm assert len(pars) == 3 and 't' in pars and 'm' in pars and 'p' in pars return ( self.time_cost != int(pars['t']) or self.memory_cost != int(pars['m']) or self.parallelism != int(pars['p']) ) def harden_runtime(self, password, encoded): # The runtime for Argon2 is too complicated to implement a sensible # hardening algorithm. pass class BCryptSHA256PasswordHasher(BasePasswordHasher): """ Secure password hashing using the bcrypt algorithm (recommended) Loading docs/internals/contributing/writing-code/unit-tests.txt +2 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,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.0.0+ * bcrypt_ * docutils_ * enum34_ (Python 2 only) Loading Loading @@ -171,6 +172,7 @@ and install the Geospatial libraries</ref/contrib/gis/install/index>`. Each of these dependencies is optional. If you're missing any of them, the associated tests will be skipped. .. _argon2-cffi: https://pypi.python.org/pypi/argon2_cffi .. _bcrypt: https://pypi.python.org/pypi/bcrypt .. _docutils: https://pypi.python.org/pypi/docutils .. _enum34: https://pypi.python.org/pypi/enum34 Loading docs/ref/settings.txt +3 −0 Original line number Diff line number Diff line Loading @@ -2684,6 +2684,7 @@ Default:: [ 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ] Loading @@ -2702,6 +2703,8 @@ Default:: to strengthen the hashes in your database. If that's not feasible, add this setting to your project and add back any hashers that you need. Also, the ``Argon2PasswordHasher`` was added. .. setting:: AUTH_PASSWORD_VALIDATORS ``AUTH_PASSWORD_VALIDATORS`` Loading docs/releases/1.10.txt +4 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,10 @@ Minor features :mod:`django.contrib.auth` ~~~~~~~~~~~~~~~~~~~~~~~~~~ * Added support for the :ref:`Argon2 password hash <argon2_usage>`. It's recommended over PBKDF2, however, it's not the default as it requires a third-party library. * The default iteration count for the PBKDF2 password hasher has been increased by 25%. This backwards compatible change will not affect users who have subclassed ``django.contrib.auth.hashers.PBKDF2PasswordHasher`` to change the Loading Loading
django/conf/global_settings.py +1 −0 Original line number Diff line number Diff line Loading @@ -500,6 +500,7 @@ PASSWORD_RESET_TIMEOUT_DAYS = 3 PASSWORD_HASHERS = [ 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ] Loading
django/contrib/auth/hashers.py +73 −0 Original line number Diff line number Diff line Loading @@ -297,6 +297,79 @@ class PBKDF2SHA1PasswordHasher(PBKDF2PasswordHasher): digest = hashlib.sha1 class Argon2PasswordHasher(BasePasswordHasher): """ Secure password hashing using the argon2 algorithm. This is the winner of the Password Hashing Competition 2013-2015 (https://password-hashing.net). It requires the argon2-cffi library which depends on native C code and might cause portability issues. """ algorithm = 'argon2' library = 'argon2' time_cost = 2 memory_cost = 512 parallelism = 2 def encode(self, password, salt): argon2 = self._load_library() data = argon2.low_level.hash_secret( force_bytes(password), force_bytes(salt), 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, ) return self.algorithm + data.decode('utf-8') def verify(self, password, encoded): argon2 = self._load_library() algorithm, data = encoded.split('$', 1) assert algorithm == self.algorithm try: return argon2.low_level.verify_secret( force_bytes('$' + data), force_bytes(password), type=argon2.low_level.Type.I, ) except argon2.exceptions.VerificationError: return False def safe_summary(self, encoded): algorithm, variety, raw_pars, salt, data = encoded.split('$', 5) pars = dict(bit.split('=', 1) for bit in raw_pars.split(',')) assert algorithm == self.algorithm assert len(pars) == 3 and 't' in pars and 'm' in pars and 'p' in pars return OrderedDict([ (_('algorithm'), algorithm), (_('variety'), variety), (_('memory cost'), int(pars['m'])), (_('time cost'), int(pars['t'])), (_('parallelism'), int(pars['p'])), (_('salt'), mask_hash(salt)), (_('hash'), mask_hash(data)), ]) def must_update(self, encoded): algorithm, variety, raw_pars, salt, data = encoded.split('$', 5) pars = dict([bit.split('=', 1) for bit in raw_pars.split(',')]) assert algorithm == self.algorithm assert len(pars) == 3 and 't' in pars and 'm' in pars and 'p' in pars return ( self.time_cost != int(pars['t']) or self.memory_cost != int(pars['m']) or self.parallelism != int(pars['p']) ) def harden_runtime(self, password, encoded): # The runtime for Argon2 is too complicated to implement a sensible # hardening algorithm. pass class BCryptSHA256PasswordHasher(BasePasswordHasher): """ Secure password hashing using the bcrypt algorithm (recommended) Loading
docs/internals/contributing/writing-code/unit-tests.txt +2 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,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.0.0+ * bcrypt_ * docutils_ * enum34_ (Python 2 only) Loading Loading @@ -171,6 +172,7 @@ and install the Geospatial libraries</ref/contrib/gis/install/index>`. Each of these dependencies is optional. If you're missing any of them, the associated tests will be skipped. .. _argon2-cffi: https://pypi.python.org/pypi/argon2_cffi .. _bcrypt: https://pypi.python.org/pypi/bcrypt .. _docutils: https://pypi.python.org/pypi/docutils .. _enum34: https://pypi.python.org/pypi/enum34 Loading
docs/ref/settings.txt +3 −0 Original line number Diff line number Diff line Loading @@ -2684,6 +2684,7 @@ Default:: [ 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ] Loading @@ -2702,6 +2703,8 @@ Default:: to strengthen the hashes in your database. If that's not feasible, add this setting to your project and add back any hashers that you need. Also, the ``Argon2PasswordHasher`` was added. .. setting:: AUTH_PASSWORD_VALIDATORS ``AUTH_PASSWORD_VALIDATORS`` Loading
docs/releases/1.10.txt +4 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,10 @@ Minor features :mod:`django.contrib.auth` ~~~~~~~~~~~~~~~~~~~~~~~~~~ * Added support for the :ref:`Argon2 password hash <argon2_usage>`. It's recommended over PBKDF2, however, it's not the default as it requires a third-party library. * The default iteration count for the PBKDF2 password hasher has been increased by 25%. This backwards compatible change will not affect users who have subclassed ``django.contrib.auth.hashers.PBKDF2PasswordHasher`` to change the Loading