diff --git a/photo21/hashers.py b/photo21/hashers.py index e94397e..0c3305a 100644 --- a/photo21/hashers.py +++ b/photo21/hashers.py @@ -17,23 +17,26 @@ class SHA512PasswordHasher(BasePasswordHasher): """ algorithm = "sha512" - def encode(self, password, salt): + def encode(self, password, iteration, 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 + salted = force_bytes(password + "{" + salt + "}") + digest = hashlib.sha512(salted).digest() + # "stretch" hash + for _i in range(1, int(iteration)): + digest = hashlib.sha512(digest + salted).digest() + digest = base64.b64encode(digest).decode() + encoded = "%s$%s$%s$%s" % (self.algorithm, iteration, salt, digest) + return encoded[:128] def verify(self, password, encoded): - algorithm, salt, hash = encoded.split('$', 2) + algorithm, iteration, salt, hash = encoded.split('$', 3) assert algorithm == self.algorithm - encoded_2 = self.encode(password, salt) + encoded_2 = self.encode(password, iteration, salt) return constant_time_compare(encoded, encoded_2) def safe_summary(self, encoded): - algorithm, salt, hash = encoded.split('$', 2) + algorithm, iteration, salt, hash = encoded.split('$', 3) assert algorithm == self.algorithm return OrderedDict([ (_('algorithm'), algorithm),