import hashlib import base64 from collections import OrderedDict from django.utils.crypto import constant_time_compare from django.utils.encoding import force_bytes from django.utils.translation import gettext_noop as _ from django.contrib.auth.hashers import mask_hash, BasePasswordHasher class SHA512PasswordHasher(BasePasswordHasher): """ The SHA512 password hashing algorithm It is used to migrate passwords from old Symfony2 photos server. https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Security/Core/Encoder/MessageDigestPasswordEncoder.php """ algorithm = "sha512" def encode(self, password, salt): assert password is not None assert salt and '$' not in salt hash = hashlib.sha512(force_bytes(password + "{" + salt + "}")) hash = base64.b64encode(hash) encoded = "%s$%s$%s" % (self.algorithm, salt, hash) encoded = encoded[:128] return encoded def verify(self, password, encoded): algorithm, salt, hash = encoded.split('$', 2) assert algorithm == self.algorithm encoded_2 = self.encode(password, salt) return constant_time_compare(encoded, encoded_2) def safe_summary(self, encoded): algorithm, salt, hash = encoded.split('$', 2) assert algorithm == self.algorithm return OrderedDict([ (_('algorithm'), algorithm), (_('salt'), mask_hash(salt, show=2)), (_('hash'), mask_hash(hash)), ]) def harden_runtime(self, password, encoded): pass