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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
"""passlib.hash.sha1_crypt
"""
#=========================================================
#imports
#=========================================================
from __future__ import with_statement, absolute_import
#core
from hmac import new as hmac
from hashlib import sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
from passlib.utils import autodocument, h64
from passlib.utils.handlers import ExtHandler
from passlib.utils.pbkdf2 import hmac_sha1
from passlib.base import register_crypt_handler
#pkg
#local
__all__ = [
]
#=========================================================
#sha1-crypt
#=========================================================
class SHA1Crypt(ExtHandler):
#=========================================================
#class attrs
#=========================================================
name = "sha1_crypt"
setting_kwds = ("salt", "rounds")
default_salt_chars = 8
min_salt_chars = 0
max_salt_chars = 64
default_rounds = 40000 #current passlib default
min_rounds = 1 #really, this should be higher.
max_rounds = 4294967295 # 32-bit integer limit
rounds_cost = "linear"
#=========================================================
#formatting
#=========================================================
@classmethod
def identify(cls, hash):
return bool(hash) and hash.startswith("$sha1$")
_pat = re.compile(r"""
^
\$sha1
\$(?P<rounds>\d+)
\$(?P<salt>[A-Za-z0-9./]{0,64})
(\$(?P<chk>[A-Za-z0-9./]{28})?)?
$
""", re.X)
@classmethod
def from_string(cls, hash):
if not hash:
raise ValueError, "no hash specified"
m = cls._pat.match(hash)
if not m:
raise ValueError, "invalid sha1_crypt hash"
rounds, salt, chk = m.group("rounds", "salt", "chk")
if rounds.startswith("0"):
raise ValueError, "invalid sha1-crypt hash (zero-padded rounds)"
return cls(
rounds=int(rounds),
salt=salt,
checksum=chk,
strict=bool(chk),
)
def to_string(self):
out = "$sha1$%d$%s" % (self.rounds, self.salt)
if self.checksum:
out += "$" + self.checksum
return out
#=========================================================
#backend
#=========================================================
def calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
rounds = self.rounds
result = "%s$sha1$%s" % (self.salt, rounds)
r = 0
while r < rounds:
result = hmac_sha1(secret, result)
r += 1
return h64.encode_transposed_bytes(result, self._chk_offsets)
_chk_offsets = [
2,1,0,
5,4,3,
8,7,6,
11,10,9,
14,13,12,
17,16,15,
0,19,18,
]
#=========================================================
#eoc
#=========================================================
autodocument(SHA1Crypt)
register_crypt_handler(SHA1Crypt)
#=========================================================
#eof
#=========================================================
|