import hashlib
from django.contrib.auth.hashers import BasePasswordHasher
class DrupalPasswordHasher(BasePasswordHasher):
"""
>>> h = DrupalPasswordHasher()
>>> h.verify("password1234", "$S$DeIZ1KTE.VzRvudZ5.xgOakipuMFrVyPmRdWTjAdYieWj27NMglI")
True
"""
DRUPAL_HASH_COUNT = 15
DRUPAL_MIN_HASH_COUNT = 7
DRUPAL_MAX_HASH_COUNT = 30
DRUPAL_HASH_LENGTH = 55
_ITOA64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
def verify(self, password, hashed_password):
setting = hashed_password[0:12]
if setting[0] != '$' or setting[2] != '$':
return False
count_log2 = self._ITOA64.index(setting[3])
if count_log2 < self.DRUPAL_MIN_HASH_COUNT or count_log2 > self.DRUPAL_MAX_HASH_COUNT:
return False
salt = setting[4:4+8]
if len(salt) != 8:
return False
count = 2 ** count_log2
pass_hash = hashlib.sha512(salt + password).digest()
for _ in range(count):
pass_hash = hashlib.sha512(pass_hash + password).digest()
hash_length = len(pass_hash)
output = setting + self._password_base64_encode(pass_hash, hash_length)
if len(output) != 98:
return False
return output[:self.DRUPAL_HASH_LENGTH] == hashed_password
def _password_base64_encode(self, to_encode, count):
output = ''
i = 0
while True:
value = ord(to_encode[i])
i += 1
output = output + self._ITOA64[value & 0x3f]
if i < count:
value |= ord(to_encode[i]) << 8
output = output + self._ITOA64[(value >> 6) & 0x3f]
if i >= count:
break
i += 1
if i < count:
value |= ord(to_encode[i]) << 16
output = output + self._ITOA64[(value >> 12) & 0x3f]
if i >= count:
break
i += 1
output = output + self._ITOA64[(value >> 18) & 0x3f]
if i >= count:
break
return output
if __name__ == "__main__":
import doctest
doctest.testmod()
Comments
awesome dude.. just tried your code and it works.. thanks
#
when i try to integrate it with django, i get a "hasher doesn't specify an algorithm name" any ideas why?
#