1"""HMAC (Keyed-Hashing for Message Authentication) Python module. 2 3Implements the HMAC algorithm as described by RFC 2104. 4""" 5 6import warnings as _warnings 7from _operator import _compare_digest as compare_digest 8import hashlib as _hashlib 9 10trans_5C = bytes((x ^ 0x5C) for x in range(256)) 11trans_36 = bytes((x ^ 0x36) for x in range(256)) 12 13# The size of the digests returned by HMAC depends on the underlying 14# hashing module used. Use digest_size from the instance of HMAC instead. 15digest_size = None 16 17 18 19class HMAC: 20 """RFC 2104 HMAC class. Also complies with RFC 4231. 21 22 This supports the API for Cryptographic Hash Functions (PEP 247). 23 """ 24 blocksize = 64 # 512-bit HMAC; can be changed in subclasses. 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. *OR* 33 A hash name suitable for hashlib.new(). 34 Defaults to hashlib.md5. 35 Implicit default to hashlib.md5 is deprecated and will be 36 removed in Python 3.6. 37 38 Note: key and msg must be a bytes or bytearray objects. 39 """ 40 41 if not isinstance(key, (bytes, bytearray)): 42 raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) 43 44 if digestmod is None: 45 _warnings.warn("HMAC() without an explicit digestmod argument " 46 "is deprecated.", PendingDeprecationWarning, 2) 47 digestmod = _hashlib.md5 48 49 if callable(digestmod): 50 self.digest_cons = digestmod 51 elif isinstance(digestmod, str): 52 self.digest_cons = lambda d=b'': _hashlib.new(digestmod, d) 53 else: 54 self.digest_cons = lambda d=b'': digestmod.new(d) 55 56 self.outer = self.digest_cons() 57 self.inner = self.digest_cons() 58 self.digest_size = self.inner.digest_size 59 60 if hasattr(self.inner, 'block_size'): 61 blocksize = self.inner.block_size 62 if blocksize < 16: 63 _warnings.warn('block_size of %d seems too small; using our ' 64 'default of %d.' % (blocksize, self.blocksize), 65 RuntimeWarning, 2) 66 blocksize = self.blocksize 67 else: 68 _warnings.warn('No block_size attribute on given digest object; ' 69 'Assuming %d.' % (self.blocksize), 70 RuntimeWarning, 2) 71 blocksize = self.blocksize 72 73 # self.blocksize is the default blocksize. self.block_size is 74 # effective block size as well as the public API attribute. 75 self.block_size = blocksize 76 77 if len(key) > blocksize: 78 key = self.digest_cons(key).digest() 79 80 key = key.ljust(blocksize, b'\0') 81 self.outer.update(key.translate(trans_5C)) 82 self.inner.update(key.translate(trans_36)) 83 if msg is not None: 84 self.update(msg) 85 86 @property 87 def name(self): 88 return "hmac-" + self.inner.name 89 90 def update(self, msg): 91 """Update this hashing object with the string msg. 92 """ 93 self.inner.update(msg) 94 95 def copy(self): 96 """Return a separate copy of this hashing object. 97 98 An update to this copy won't affect the original object. 99 """ 100 # Call __new__ directly to avoid the expensive __init__. 101 other = self.__class__.__new__(self.__class__) 102 other.digest_cons = self.digest_cons 103 other.digest_size = self.digest_size 104 other.inner = self.inner.copy() 105 other.outer = self.outer.copy() 106 return other 107 108 def _current(self): 109 """Return a hash object for the current state. 110 111 To be used only internally with digest() and hexdigest(). 112 """ 113 h = self.outer.copy() 114 h.update(self.inner.digest()) 115 return h 116 117 def digest(self): 118 """Return the hash value of this hashing object. 119 120 This returns a string containing 8-bit data. The object is 121 not altered in any way by this function; you can continue 122 updating the object after calling this function. 123 """ 124 h = self._current() 125 return h.digest() 126 127 def hexdigest(self): 128 """Like digest(), but returns a string of hexadecimal digits instead. 129 """ 130 h = self._current() 131 return h.hexdigest() 132 133def new(key, msg = None, digestmod = None): 134 """Create a new hashing object and return it. 135 136 key: The starting key for the hash. 137 msg: if available, will immediately be hashed into the object's starting 138 state. 139 140 You can now feed arbitrary strings into the object using its update() 141 method, and can ask for the hash value at any time by calling its digest() 142 method. 143 """ 144 return HMAC(key, msg, digestmod) 145