|
1 """HMAC (Keyed-Hashing for Message Authentication) Python module. |
|
2 |
|
3 Implements the HMAC algorithm as described by RFC 2104. |
|
4 """ |
|
5 |
|
6 import warnings as _warnings |
|
7 |
|
8 trans_5C = "".join ([chr (x ^ 0x5C) for x in xrange(256)]) |
|
9 trans_36 = "".join ([chr (x ^ 0x36) for x in xrange(256)]) |
|
10 |
|
11 # The size of the digests returned by HMAC depends on the underlying |
|
12 # hashing module used. Use digest_size from the instance of HMAC instead. |
|
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 """RFC 2104 HMAC class. Also complies with RFC 4231. |
|
22 |
|
23 This supports the API for Cryptographic Hash Functions (PEP 247). |
|
24 """ |
|
25 blocksize = 64 # 512-bit HMAC; can be changed in subclasses. |
|
26 |
|
27 def __init__(self, key, msg = None, digestmod = None): |
|
28 """Create a new HMAC object. |
|
29 |
|
30 key: key for the keyed hash object. |
|
31 msg: Initial input for the hash, if provided. |
|
32 digestmod: A module supporting PEP 247. *OR* |
|
33 A hashlib constructor returning a new hash object. |
|
34 Defaults to hashlib.md5. |
|
35 """ |
|
36 |
|
37 if key is _secret_backdoor_key: # cheap |
|
38 return |
|
39 |
|
40 if digestmod is None: |
|
41 import hashlib |
|
42 digestmod = hashlib.md5 |
|
43 |
|
44 if hasattr(digestmod, '__call__'): |
|
45 self.digest_cons = digestmod |
|
46 else: |
|
47 self.digest_cons = lambda d='': digestmod.new(d) |
|
48 |
|
49 self.outer = self.digest_cons() |
|
50 self.inner = self.digest_cons() |
|
51 self.digest_size = self.inner.digest_size |
|
52 |
|
53 if hasattr(self.inner, 'block_size'): |
|
54 blocksize = self.inner.block_size |
|
55 if blocksize < 16: |
|
56 # Very low blocksize, most likely a legacy value like |
|
57 # Lib/sha.py and Lib/md5.py have. |
|
58 _warnings.warn('block_size of %d seems too small; using our ' |
|
59 'default of %d.' % (blocksize, self.blocksize), |
|
60 RuntimeWarning, 2) |
|
61 blocksize = self.blocksize |
|
62 else: |
|
63 _warnings.warn('No block_size attribute on given digest object; ' |
|
64 'Assuming %d.' % (self.blocksize), |
|
65 RuntimeWarning, 2) |
|
66 blocksize = self.blocksize |
|
67 |
|
68 if len(key) > blocksize: |
|
69 key = self.digest_cons(key).digest() |
|
70 |
|
71 key = key + chr(0) * (blocksize - len(key)) |
|
72 self.outer.update(key.translate(trans_5C)) |
|
73 self.inner.update(key.translate(trans_36)) |
|
74 if msg is not None: |
|
75 self.update(msg) |
|
76 |
|
77 ## def clear(self): |
|
78 ## raise NotImplementedError, "clear() method not available in HMAC." |
|
79 |
|
80 def update(self, msg): |
|
81 """Update this hashing object with the string msg. |
|
82 """ |
|
83 self.inner.update(msg) |
|
84 |
|
85 def copy(self): |
|
86 """Return a separate copy of this hashing object. |
|
87 |
|
88 An update to this copy won't affect the original object. |
|
89 """ |
|
90 other = self.__class__(_secret_backdoor_key) |
|
91 other.digest_cons = self.digest_cons |
|
92 other.digest_size = self.digest_size |
|
93 other.inner = self.inner.copy() |
|
94 other.outer = self.outer.copy() |
|
95 return other |
|
96 |
|
97 def _current(self): |
|
98 """Return a hash object for the current state. |
|
99 |
|
100 To be used only internally with digest() and hexdigest(). |
|
101 """ |
|
102 h = self.outer.copy() |
|
103 h.update(self.inner.digest()) |
|
104 return h |
|
105 |
|
106 def digest(self): |
|
107 """Return the hash value of this hashing object. |
|
108 |
|
109 This returns a string containing 8-bit data. The object is |
|
110 not altered in any way by this function; you can continue |
|
111 updating the object after calling this function. |
|
112 """ |
|
113 h = self._current() |
|
114 return h.digest() |
|
115 |
|
116 def hexdigest(self): |
|
117 """Like digest(), but returns a string of hexadecimal digits instead. |
|
118 """ |
|
119 h = self._current() |
|
120 return h.hexdigest() |
|
121 |
|
122 def new(key, msg = None, digestmod = None): |
|
123 """Create a new hashing object and return it. |
|
124 |
|
125 key: The starting key for the hash. |
|
126 msg: if available, will immediately be hashed into the object's starting |
|
127 state. |
|
128 |
|
129 You can now feed arbitrary strings into the object using its update() |
|
130 method, and can ask for the hash value at any time by calling its digest() |
|
131 method. |
|
132 """ |
|
133 return HMAC(key, msg, digestmod) |