summaryrefslogtreecommitdiff
path: root/legacy_passwords.py
blob: 1191488af7ae375219a8e5a28e2ad6cb3bc910ef (plain)
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
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))

    @classmethod
    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):]
            else:
                raise exc.InvalidHashError(cls)

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

        return cls(checksum=hash, **context)

    @classmethod
    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.
        uh.validate_secret(secret)
        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)