|
1 """HMAC (Keyed-Hashing for Message Authentication) Python module. |
|
2 |
|
3 Implements the HMAC algorithm as described by RFC 2104. |
|
4 """ |
|
5 |
|
6 def _strxor(s1, s2): |
|
7 """Utility method. XOR the two strings s1 and s2 (must have same length). |
|
8 """ |
|
9 return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), s1, s2)) |
|
10 |
|
11 # The size of the digests returned by HMAC depends on the underlying |
|
12 # hashing module used. |
|
13 digest_size = None |
|
14 |
|
15 # A unique object passed by HMAC.copy() to the HMAC constructor, in order |
|
16 # that the latter return very quickly. HMAC("") in contrast is quite |
|
17 # expensive. |
|
18 _secret_backdoor_key = [] |
|
19 |
|
20 class HMAC: |
|
21 """RFC2104 HMAC class. |
|
22 |
|
23 This supports the API for Cryptographic Hash Functions (PEP 247). |
|
24 """ |
|
25 |
|
26 def __init__(self, key, msg = None, digestmod = None): |
|
27 """Create a new HMAC object. |
|
28 |
|
29 key: key for the keyed hash object. |
|
30 msg: Initial input for the hash, if provided. |
|
31 digestmod: A module supporting PEP 247. *OR* |
|
32 A hashlib constructor returning a new hash object. |
|
33 Defaults to hashlib.md5. |
|
34 """ |
|
35 |
|
36 if key is _secret_backdoor_key: # cheap |
|
37 return |
|
38 |
|
39 if digestmod is None: |
|
40 import hashlib |
|
41 digestmod = hashlib.md5 |
|
42 |
|
43 if callable(digestmod): |
|
44 self.digest_cons = digestmod |
|
45 else: |
|
46 self.digest_cons = lambda d='': digestmod.new(d) |
|
47 |
|
48 self.outer = self.digest_cons() |
|
49 self.inner = self.digest_cons() |
|
50 self.digest_size = self.inner.digest_size |
|
51 |
|
52 if hasattr(self.inner, 'block_size'): |
|
53 blocksize = self.inner.block_size |
|
54 if blocksize < 16: |
|
55 # Very low blocksize, most likely a legacy value like |
|
56 # Lib/sha.py and Lib/md5.py have. |
|
57 blocksize = 64 |
|
58 else: |
|
59 blocksize = 64 |
|
60 |
|
61 ipad = "\x36" * blocksize |
|
62 opad = "\x5C" * blocksize |
|
63 |
|
64 if len(key) > blocksize: |
|
65 key = self.digest_cons(key).digest() |
|
66 |
|
67 key = key + chr(0) * (blocksize - len(key)) |
|
68 self.outer.update(_strxor(key, opad)) |
|
69 self.inner.update(_strxor(key, ipad)) |
|
70 if msg is not None: |
|
71 self.update(msg) |
|
72 |
|
73 ## def clear(self): |
|
74 ## raise NotImplementedError, "clear() method not available in HMAC." |
|
75 |
|
76 def update(self, msg): |
|
77 """Update this hashing object with the string msg. |
|
78 """ |
|
79 self.inner.update(msg) |
|
80 |
|
81 def copy(self): |
|
82 """Return a separate copy of this hashing object. |
|
83 |
|
84 An update to this copy won't affect the original object. |
|
85 """ |
|
86 other = HMAC(_secret_backdoor_key) |
|
87 other.digest_cons = self.digest_cons |
|
88 other.digest_size = self.digest_size |
|
89 other.inner = self.inner.copy() |
|
90 other.outer = self.outer.copy() |
|
91 return other |
|
92 |
|
93 def digest(self): |
|
94 """Return the hash value of this hashing object. |
|
95 |
|
96 This returns a string containing 8-bit data. The object is |
|
97 not altered in any way by this function; you can continue |
|
98 updating the object after calling this function. |
|
99 """ |
|
100 h = self.outer.copy() |
|
101 h.update(self.inner.digest()) |
|
102 return h.digest() |
|
103 |
|
104 def hexdigest(self): |
|
105 """Like digest(), but returns a string of hexadecimal digits instead. |
|
106 """ |
|
107 return "".join([hex(ord(x))[2:].zfill(2) |
|
108 for x in tuple(self.digest())]) |
|
109 |
|
110 def new(key, msg = None, digestmod = None): |
|
111 """Create a new hashing object and return it. |
|
112 |
|
113 key: The starting key for the hash. |
|
114 msg: if available, will immediately be hashed into the object's starting |
|
115 state. |
|
116 |
|
117 You can now feed arbitrary strings into the object using its update() |
|
118 method, and can ask for the hash value at any time by calling its digest() |
|
119 method. |
|
120 """ |
|
121 return HMAC(key, msg, digestmod) |