import hashlib
import math

from django.contrib.auth import hashers
from django.utils.crypto import constant_time_compare
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext_noop as _

class Drupal7PasswordHasher(hashers.BasePasswordHasher):
    """
    Secure password hashing using the algorithm used by Drupal 7 (recommended)
    """
    algorithm = "drupal7_sha512"
    iterations = 10000
    digest = hashlib.sha512
    alphabet = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'

    def itoa64(self, v):
        return self.alphabet.find(v)

    def a64toi(self, v):
        return self.alphabet[v]

    def from_drupal(self, encoded):
        ident, log_count, salt, h = encoded[:3], encoded[3], encoded[4:12], encoded[12:]
        if ident != '$S$':
            raise ValueError('Not a Drupal7 SHA-512 hashed password')
        count = 1 << self.itoa64(log_count)
        return '%s$%s$%s$%s' % (self.algorithm, count, salt, h)

    def to_drupal(self, encoded):
        algo, count, salt, h = encoded.split('$', 3)
        count = self.a64toi(math.ceil(math.log(count, 2)))
        return '$S$%s%s%s' % (count, salt, h)

    def encode(self, password, salt, iterations):
        assert password
        assert salt and '$' not in salt
        h = password
        for i in xrange(iterations):
            h = self.digest(salt + h).digest()
        return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, h)

    def verify(self, password, encoded):
        algorithm, iterations, salt, hash = encoded.split('$', 3)
        assert algorithm == self.algorithm
        encoded_2 = self.encode(password, salt, int(iterations))
        return constant_time_compare(encoded, encoded_2)

    def safe_summary(self, encoded):
        algorithm, iterations, salt, hash = encoded.split('$', 3)
        assert algorithm == self.algorithm
        return SortedDict([
            (_('algorithm'), algorithm),
            (_('iterations'), iterations),
            (_('salt'), hashers.mask_hash(salt)),
            (_('hash'), hashers.mask_hash(hash)),
        ])

@@ -8,16 +8,30 @@
 hashlib%0A
+import base64%0A
 import m
@@ -34,16 +34,16 @@
 rt math%0A
-
 %0Afrom dj
@@ -564,20 +564,20 @@
     def 
-itoa
+atoi
 64(self,
@@ -627,22 +627,22 @@
     def 
-a
+i
 64to
-i
+a
 (self, v
@@ -677,16 +677,664 @@
 bet%5Bv%5D%0A%0A
+    def b64encode(self, v):%0A        out = ''%0A        count = len(v)%0A        i = 0%0A        while i %3C count:%0A            value = ord(v%5Bi%5D)%0A            i += 1%0A            out += self.i64toa(value & 0x3f)%0A            if i %3C count:%0A                value %7C= ord(v%5Bi%5D) %3C%3C 8%0A            out += self.i64toa((value %3E%3E 6) & 0x3f)%0A            if i == count:%0A                break%0A            i += 1%0A            if i %3C count:%0A                value %7C= ord(v%5Bi%5D) %3C%3C 16%0A            out += self.i64toa((value %3E%3E 12) & 0x3f)%0A            if i == count:%0A                break%0A            i += 1%0A            out += self.i64toa((value %3E%3E 18) & 0x3f)%0A        return out%0A%0A
     def 
@@ -1577,12 +1577,12 @@
 elf.
-itoa
+atoi
 64(l
@@ -1769,13 +1769,13 @@
 lf.a
-64
 toi
+64
 (mat
@@ -1975,24 +1975,20 @@
     h = 
-password
+salt
 %0A       
@@ -2006,32 +2006,34 @@
 range(iterations
++1
 ):%0A            h
@@ -2051,16 +2051,20 @@
 est(
-salt + h
+h + password
 ).di
@@ -2128,33 +2128,54 @@
 erations, salt, 
-h
+self.b64encode(h)%5B:43%5D
 )%0A%0A    def verif

fix Drupal7PasswordHasher