Completely based on snippet 2729 (see that snippet for useful comments!). The above snippet did not work for me (something with MemoryError), so I looked at the Drula source code and reimplemented...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 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()
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 8 months, 3 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 9 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 3 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 4 months ago
- Help text hyperlinks by sa2812 1 year, 5 months ago
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?
#
Please login first before commenting.