1. Donald Stufft
  2. pypi


pypi / legacy_passwords.py

import base64
import hashlib

import passlib.exc as exc
import passlib.utils.handlers as uh

from passlib.registry import get_crypt_handler
from passlib.utils import to_unicode
from passlib.utils.compat import uascii_to_str

passlib_bcrypt = get_crypt_handler("bcrypt")

class bcrypt_sha1(uh.StaticHandler):

    name = "bcrypt_sha1"
    _hash_prefix = u"$bcrypt_sha1$"

    def _calc_checksum(self, secret):
        # Hash the secret with sha1 first
        secret = hashlib.sha1(secret).hexdigest()

        # Hash it with bcrypt
        return passlib_bcrypt.encrypt(secret)

    def to_string(self):
        assert self.checksum is not None
        return uascii_to_str(self._hash_prefix + base64.b64encode(self.checksum))

    def from_string(cls, hash, **context):
        # default from_string() which strips optional prefix,
        # and passes rest unchanged as checksum value.
        hash = to_unicode(hash, "ascii", "hash")
        hash = cls._norm_hash(hash)
        # could enable this for extra strictness
        ##pat = cls._hash_regex
        ##if pat and pat.match(hash) is None:
        ##    raise ValueError("not a valid %s hash" % (cls.name,))
        prefix = cls._hash_prefix
        if prefix:
            if hash.startswith(prefix):
                hash = hash[len(prefix):]
                raise exc.InvalidHashError(cls)

        # Decode the base64 stored actual hash
        hash = unicode(base64.b64decode(hash))

        return cls(checksum=hash, **context)

    def verify(cls, secret, hash, **context):
        # NOTE: classes with multiple checksum encodings should either
        # override this method, or ensure that from_string() / _norm_checksum()
        # ensures .checksum always uses a single canonical representation.
        self = cls.from_string(hash, **context)
        chk = self.checksum
        if chk is None:
            raise exc.MissingDigestError(cls)

        # Actually use the verify from passlib_bcrypt after hashing the secret
        #   with sha1
        secret = hashlib.sha1(secret).hexdigest()
        return passlib_bcrypt.verify(secret, chk)