1*cda5da8dSAndroid Build Coastguard Worker"""HMAC (Keyed-Hashing for Message Authentication) module. 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard WorkerImplements the HMAC algorithm as described by RFC 2104. 4*cda5da8dSAndroid Build Coastguard Worker""" 5*cda5da8dSAndroid Build Coastguard Worker 6*cda5da8dSAndroid Build Coastguard Workerimport warnings as _warnings 7*cda5da8dSAndroid Build Coastguard Workertry: 8*cda5da8dSAndroid Build Coastguard Worker import _hashlib as _hashopenssl 9*cda5da8dSAndroid Build Coastguard Workerexcept ImportError: 10*cda5da8dSAndroid Build Coastguard Worker _hashopenssl = None 11*cda5da8dSAndroid Build Coastguard Worker _functype = None 12*cda5da8dSAndroid Build Coastguard Worker from _operator import _compare_digest as compare_digest 13*cda5da8dSAndroid Build Coastguard Workerelse: 14*cda5da8dSAndroid Build Coastguard Worker compare_digest = _hashopenssl.compare_digest 15*cda5da8dSAndroid Build Coastguard Worker _functype = type(_hashopenssl.openssl_sha256) # builtin type 16*cda5da8dSAndroid Build Coastguard Worker 17*cda5da8dSAndroid Build Coastguard Workerimport hashlib as _hashlib 18*cda5da8dSAndroid Build Coastguard Worker 19*cda5da8dSAndroid Build Coastguard Workertrans_5C = bytes((x ^ 0x5C) for x in range(256)) 20*cda5da8dSAndroid Build Coastguard Workertrans_36 = bytes((x ^ 0x36) for x in range(256)) 21*cda5da8dSAndroid Build Coastguard Worker 22*cda5da8dSAndroid Build Coastguard Worker# The size of the digests returned by HMAC depends on the underlying 23*cda5da8dSAndroid Build Coastguard Worker# hashing module used. Use digest_size from the instance of HMAC instead. 24*cda5da8dSAndroid Build Coastguard Workerdigest_size = None 25*cda5da8dSAndroid Build Coastguard Worker 26*cda5da8dSAndroid Build Coastguard Worker 27*cda5da8dSAndroid Build Coastguard Workerclass HMAC: 28*cda5da8dSAndroid Build Coastguard Worker """RFC 2104 HMAC class. Also complies with RFC 4231. 29*cda5da8dSAndroid Build Coastguard Worker 30*cda5da8dSAndroid Build Coastguard Worker This supports the API for Cryptographic Hash Functions (PEP 247). 31*cda5da8dSAndroid Build Coastguard Worker """ 32*cda5da8dSAndroid Build Coastguard Worker blocksize = 64 # 512-bit HMAC; can be changed in subclasses. 33*cda5da8dSAndroid Build Coastguard Worker 34*cda5da8dSAndroid Build Coastguard Worker __slots__ = ( 35*cda5da8dSAndroid Build Coastguard Worker "_hmac", "_inner", "_outer", "block_size", "digest_size" 36*cda5da8dSAndroid Build Coastguard Worker ) 37*cda5da8dSAndroid Build Coastguard Worker 38*cda5da8dSAndroid Build Coastguard Worker def __init__(self, key, msg=None, digestmod=''): 39*cda5da8dSAndroid Build Coastguard Worker """Create a new HMAC object. 40*cda5da8dSAndroid Build Coastguard Worker 41*cda5da8dSAndroid Build Coastguard Worker key: bytes or buffer, key for the keyed hash object. 42*cda5da8dSAndroid Build Coastguard Worker msg: bytes or buffer, Initial input for the hash or None. 43*cda5da8dSAndroid Build Coastguard Worker digestmod: A hash name suitable for hashlib.new(). *OR* 44*cda5da8dSAndroid Build Coastguard Worker A hashlib constructor returning a new hash object. *OR* 45*cda5da8dSAndroid Build Coastguard Worker A module supporting PEP 247. 46*cda5da8dSAndroid Build Coastguard Worker 47*cda5da8dSAndroid Build Coastguard Worker Required as of 3.8, despite its position after the optional 48*cda5da8dSAndroid Build Coastguard Worker msg argument. Passing it as a keyword argument is 49*cda5da8dSAndroid Build Coastguard Worker recommended, though not required for legacy API reasons. 50*cda5da8dSAndroid Build Coastguard Worker """ 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Worker if not isinstance(key, (bytes, bytearray)): 53*cda5da8dSAndroid Build Coastguard Worker raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) 54*cda5da8dSAndroid Build Coastguard Worker 55*cda5da8dSAndroid Build Coastguard Worker if not digestmod: 56*cda5da8dSAndroid Build Coastguard Worker raise TypeError("Missing required parameter 'digestmod'.") 57*cda5da8dSAndroid Build Coastguard Worker 58*cda5da8dSAndroid Build Coastguard Worker if _hashopenssl and isinstance(digestmod, (str, _functype)): 59*cda5da8dSAndroid Build Coastguard Worker try: 60*cda5da8dSAndroid Build Coastguard Worker self._init_hmac(key, msg, digestmod) 61*cda5da8dSAndroid Build Coastguard Worker except _hashopenssl.UnsupportedDigestmodError: 62*cda5da8dSAndroid Build Coastguard Worker self._init_old(key, msg, digestmod) 63*cda5da8dSAndroid Build Coastguard Worker else: 64*cda5da8dSAndroid Build Coastguard Worker self._init_old(key, msg, digestmod) 65*cda5da8dSAndroid Build Coastguard Worker 66*cda5da8dSAndroid Build Coastguard Worker def _init_hmac(self, key, msg, digestmod): 67*cda5da8dSAndroid Build Coastguard Worker self._hmac = _hashopenssl.hmac_new(key, msg, digestmod=digestmod) 68*cda5da8dSAndroid Build Coastguard Worker self.digest_size = self._hmac.digest_size 69*cda5da8dSAndroid Build Coastguard Worker self.block_size = self._hmac.block_size 70*cda5da8dSAndroid Build Coastguard Worker 71*cda5da8dSAndroid Build Coastguard Worker def _init_old(self, key, msg, digestmod): 72*cda5da8dSAndroid Build Coastguard Worker if callable(digestmod): 73*cda5da8dSAndroid Build Coastguard Worker digest_cons = digestmod 74*cda5da8dSAndroid Build Coastguard Worker elif isinstance(digestmod, str): 75*cda5da8dSAndroid Build Coastguard Worker digest_cons = lambda d=b'': _hashlib.new(digestmod, d) 76*cda5da8dSAndroid Build Coastguard Worker else: 77*cda5da8dSAndroid Build Coastguard Worker digest_cons = lambda d=b'': digestmod.new(d) 78*cda5da8dSAndroid Build Coastguard Worker 79*cda5da8dSAndroid Build Coastguard Worker self._hmac = None 80*cda5da8dSAndroid Build Coastguard Worker self._outer = digest_cons() 81*cda5da8dSAndroid Build Coastguard Worker self._inner = digest_cons() 82*cda5da8dSAndroid Build Coastguard Worker self.digest_size = self._inner.digest_size 83*cda5da8dSAndroid Build Coastguard Worker 84*cda5da8dSAndroid Build Coastguard Worker if hasattr(self._inner, 'block_size'): 85*cda5da8dSAndroid Build Coastguard Worker blocksize = self._inner.block_size 86*cda5da8dSAndroid Build Coastguard Worker if blocksize < 16: 87*cda5da8dSAndroid Build Coastguard Worker _warnings.warn('block_size of %d seems too small; using our ' 88*cda5da8dSAndroid Build Coastguard Worker 'default of %d.' % (blocksize, self.blocksize), 89*cda5da8dSAndroid Build Coastguard Worker RuntimeWarning, 2) 90*cda5da8dSAndroid Build Coastguard Worker blocksize = self.blocksize 91*cda5da8dSAndroid Build Coastguard Worker else: 92*cda5da8dSAndroid Build Coastguard Worker _warnings.warn('No block_size attribute on given digest object; ' 93*cda5da8dSAndroid Build Coastguard Worker 'Assuming %d.' % (self.blocksize), 94*cda5da8dSAndroid Build Coastguard Worker RuntimeWarning, 2) 95*cda5da8dSAndroid Build Coastguard Worker blocksize = self.blocksize 96*cda5da8dSAndroid Build Coastguard Worker 97*cda5da8dSAndroid Build Coastguard Worker if len(key) > blocksize: 98*cda5da8dSAndroid Build Coastguard Worker key = digest_cons(key).digest() 99*cda5da8dSAndroid Build Coastguard Worker 100*cda5da8dSAndroid Build Coastguard Worker # self.blocksize is the default blocksize. self.block_size is 101*cda5da8dSAndroid Build Coastguard Worker # effective block size as well as the public API attribute. 102*cda5da8dSAndroid Build Coastguard Worker self.block_size = blocksize 103*cda5da8dSAndroid Build Coastguard Worker 104*cda5da8dSAndroid Build Coastguard Worker key = key.ljust(blocksize, b'\0') 105*cda5da8dSAndroid Build Coastguard Worker self._outer.update(key.translate(trans_5C)) 106*cda5da8dSAndroid Build Coastguard Worker self._inner.update(key.translate(trans_36)) 107*cda5da8dSAndroid Build Coastguard Worker if msg is not None: 108*cda5da8dSAndroid Build Coastguard Worker self.update(msg) 109*cda5da8dSAndroid Build Coastguard Worker 110*cda5da8dSAndroid Build Coastguard Worker @property 111*cda5da8dSAndroid Build Coastguard Worker def name(self): 112*cda5da8dSAndroid Build Coastguard Worker if self._hmac: 113*cda5da8dSAndroid Build Coastguard Worker return self._hmac.name 114*cda5da8dSAndroid Build Coastguard Worker else: 115*cda5da8dSAndroid Build Coastguard Worker return f"hmac-{self._inner.name}" 116*cda5da8dSAndroid Build Coastguard Worker 117*cda5da8dSAndroid Build Coastguard Worker def update(self, msg): 118*cda5da8dSAndroid Build Coastguard Worker """Feed data from msg into this hashing object.""" 119*cda5da8dSAndroid Build Coastguard Worker inst = self._hmac or self._inner 120*cda5da8dSAndroid Build Coastguard Worker inst.update(msg) 121*cda5da8dSAndroid Build Coastguard Worker 122*cda5da8dSAndroid Build Coastguard Worker def copy(self): 123*cda5da8dSAndroid Build Coastguard Worker """Return a separate copy of this hashing object. 124*cda5da8dSAndroid Build Coastguard Worker 125*cda5da8dSAndroid Build Coastguard Worker An update to this copy won't affect the original object. 126*cda5da8dSAndroid Build Coastguard Worker """ 127*cda5da8dSAndroid Build Coastguard Worker # Call __new__ directly to avoid the expensive __init__. 128*cda5da8dSAndroid Build Coastguard Worker other = self.__class__.__new__(self.__class__) 129*cda5da8dSAndroid Build Coastguard Worker other.digest_size = self.digest_size 130*cda5da8dSAndroid Build Coastguard Worker if self._hmac: 131*cda5da8dSAndroid Build Coastguard Worker other._hmac = self._hmac.copy() 132*cda5da8dSAndroid Build Coastguard Worker other._inner = other._outer = None 133*cda5da8dSAndroid Build Coastguard Worker else: 134*cda5da8dSAndroid Build Coastguard Worker other._hmac = None 135*cda5da8dSAndroid Build Coastguard Worker other._inner = self._inner.copy() 136*cda5da8dSAndroid Build Coastguard Worker other._outer = self._outer.copy() 137*cda5da8dSAndroid Build Coastguard Worker return other 138*cda5da8dSAndroid Build Coastguard Worker 139*cda5da8dSAndroid Build Coastguard Worker def _current(self): 140*cda5da8dSAndroid Build Coastguard Worker """Return a hash object for the current state. 141*cda5da8dSAndroid Build Coastguard Worker 142*cda5da8dSAndroid Build Coastguard Worker To be used only internally with digest() and hexdigest(). 143*cda5da8dSAndroid Build Coastguard Worker """ 144*cda5da8dSAndroid Build Coastguard Worker if self._hmac: 145*cda5da8dSAndroid Build Coastguard Worker return self._hmac 146*cda5da8dSAndroid Build Coastguard Worker else: 147*cda5da8dSAndroid Build Coastguard Worker h = self._outer.copy() 148*cda5da8dSAndroid Build Coastguard Worker h.update(self._inner.digest()) 149*cda5da8dSAndroid Build Coastguard Worker return h 150*cda5da8dSAndroid Build Coastguard Worker 151*cda5da8dSAndroid Build Coastguard Worker def digest(self): 152*cda5da8dSAndroid Build Coastguard Worker """Return the hash value of this hashing object. 153*cda5da8dSAndroid Build Coastguard Worker 154*cda5da8dSAndroid Build Coastguard Worker This returns the hmac value as bytes. The object is 155*cda5da8dSAndroid Build Coastguard Worker not altered in any way by this function; you can continue 156*cda5da8dSAndroid Build Coastguard Worker updating the object after calling this function. 157*cda5da8dSAndroid Build Coastguard Worker """ 158*cda5da8dSAndroid Build Coastguard Worker h = self._current() 159*cda5da8dSAndroid Build Coastguard Worker return h.digest() 160*cda5da8dSAndroid Build Coastguard Worker 161*cda5da8dSAndroid Build Coastguard Worker def hexdigest(self): 162*cda5da8dSAndroid Build Coastguard Worker """Like digest(), but returns a string of hexadecimal digits instead. 163*cda5da8dSAndroid Build Coastguard Worker """ 164*cda5da8dSAndroid Build Coastguard Worker h = self._current() 165*cda5da8dSAndroid Build Coastguard Worker return h.hexdigest() 166*cda5da8dSAndroid Build Coastguard Worker 167*cda5da8dSAndroid Build Coastguard Workerdef new(key, msg=None, digestmod=''): 168*cda5da8dSAndroid Build Coastguard Worker """Create a new hashing object and return it. 169*cda5da8dSAndroid Build Coastguard Worker 170*cda5da8dSAndroid Build Coastguard Worker key: bytes or buffer, The starting key for the hash. 171*cda5da8dSAndroid Build Coastguard Worker msg: bytes or buffer, Initial input for the hash, or None. 172*cda5da8dSAndroid Build Coastguard Worker digestmod: A hash name suitable for hashlib.new(). *OR* 173*cda5da8dSAndroid Build Coastguard Worker A hashlib constructor returning a new hash object. *OR* 174*cda5da8dSAndroid Build Coastguard Worker A module supporting PEP 247. 175*cda5da8dSAndroid Build Coastguard Worker 176*cda5da8dSAndroid Build Coastguard Worker Required as of 3.8, despite its position after the optional 177*cda5da8dSAndroid Build Coastguard Worker msg argument. Passing it as a keyword argument is 178*cda5da8dSAndroid Build Coastguard Worker recommended, though not required for legacy API reasons. 179*cda5da8dSAndroid Build Coastguard Worker 180*cda5da8dSAndroid Build Coastguard Worker You can now feed arbitrary bytes into the object using its update() 181*cda5da8dSAndroid Build Coastguard Worker method, and can ask for the hash value at any time by calling its digest() 182*cda5da8dSAndroid Build Coastguard Worker or hexdigest() methods. 183*cda5da8dSAndroid Build Coastguard Worker """ 184*cda5da8dSAndroid Build Coastguard Worker return HMAC(key, msg, digestmod) 185*cda5da8dSAndroid Build Coastguard Worker 186*cda5da8dSAndroid Build Coastguard Worker 187*cda5da8dSAndroid Build Coastguard Workerdef digest(key, msg, digest): 188*cda5da8dSAndroid Build Coastguard Worker """Fast inline implementation of HMAC. 189*cda5da8dSAndroid Build Coastguard Worker 190*cda5da8dSAndroid Build Coastguard Worker key: bytes or buffer, The key for the keyed hash object. 191*cda5da8dSAndroid Build Coastguard Worker msg: bytes or buffer, Input message. 192*cda5da8dSAndroid Build Coastguard Worker digest: A hash name suitable for hashlib.new() for best performance. *OR* 193*cda5da8dSAndroid Build Coastguard Worker A hashlib constructor returning a new hash object. *OR* 194*cda5da8dSAndroid Build Coastguard Worker A module supporting PEP 247. 195*cda5da8dSAndroid Build Coastguard Worker """ 196*cda5da8dSAndroid Build Coastguard Worker if _hashopenssl is not None and isinstance(digest, (str, _functype)): 197*cda5da8dSAndroid Build Coastguard Worker try: 198*cda5da8dSAndroid Build Coastguard Worker return _hashopenssl.hmac_digest(key, msg, digest) 199*cda5da8dSAndroid Build Coastguard Worker except _hashopenssl.UnsupportedDigestmodError: 200*cda5da8dSAndroid Build Coastguard Worker pass 201*cda5da8dSAndroid Build Coastguard Worker 202*cda5da8dSAndroid Build Coastguard Worker if callable(digest): 203*cda5da8dSAndroid Build Coastguard Worker digest_cons = digest 204*cda5da8dSAndroid Build Coastguard Worker elif isinstance(digest, str): 205*cda5da8dSAndroid Build Coastguard Worker digest_cons = lambda d=b'': _hashlib.new(digest, d) 206*cda5da8dSAndroid Build Coastguard Worker else: 207*cda5da8dSAndroid Build Coastguard Worker digest_cons = lambda d=b'': digest.new(d) 208*cda5da8dSAndroid Build Coastguard Worker 209*cda5da8dSAndroid Build Coastguard Worker inner = digest_cons() 210*cda5da8dSAndroid Build Coastguard Worker outer = digest_cons() 211*cda5da8dSAndroid Build Coastguard Worker blocksize = getattr(inner, 'block_size', 64) 212*cda5da8dSAndroid Build Coastguard Worker if len(key) > blocksize: 213*cda5da8dSAndroid Build Coastguard Worker key = digest_cons(key).digest() 214*cda5da8dSAndroid Build Coastguard Worker key = key + b'\x00' * (blocksize - len(key)) 215*cda5da8dSAndroid Build Coastguard Worker inner.update(key.translate(trans_36)) 216*cda5da8dSAndroid Build Coastguard Worker outer.update(key.translate(trans_5C)) 217*cda5da8dSAndroid Build Coastguard Worker inner.update(msg) 218*cda5da8dSAndroid Build Coastguard Worker outer.update(inner.digest()) 219*cda5da8dSAndroid Build Coastguard Worker return outer.digest() 220