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