hmac keyedhashing for message authentication module implements the hmac algorithm as described by rfc 2104 the size of the digests returned by hmac depends on the underlying hashing module used use digestsize from the instance of hmac instead rfc 2104 hmac class also complies with rfc 4231 this supports the api for cryptographic hash functions pep 247 create a new hmac object key bytes or buffer key for the keyed hash object msg bytes or buffer initial input for the hash or none digestmod a hash name suitable for hashlib new or a hashlib constructor returning a new hash object or a module supporting pep 247 required as of 3 8 despite its position after the optional msg argument passing it as a keyword argument is recommended though not required for legacy api reasons self blocksize is the default blocksize self blocksize is effective block size as well as the public api attribute feed data from msg into this hashing object inst self hmac or self inner inst updatemsg def copyself call new directly to avoid the expensive init other self class newself class other digestsize self digestsize if self hmac other hmac self hmac copy other inner other outer none else other hmac none other inner self inner copy other outer self outer copy return other def currentself if self hmac return self hmac else h self outer copy h updateself inner digest return h def digestself h self current return h digest def hexdigestself h self current return h hexdigest def newkey msgnone digestmod return hmackey msg digestmod def digestkey msg digest if hashopenssl is not none and isinstancedigest str functype try return hashopenssl hmacdigestkey msg digest except hashopenssl unsupporteddigestmoderror pass if callabledigest digestcons digest elif isinstancedigest str digestcons lambda db hashlib newdigest d else digestcons lambda db digest newd inner digestcons outer digestcons blocksize getattrinner blocksize 64 if lenkey blocksize key digestconskey digest key key b x00 blocksize lenkey inner updatekey translatetrans36 outer updatekey translatetrans5c inner updatemsg outer updateinner digest return outer digest builtin type the size of the digests returned by hmac depends on the underlying hashing module used use digest_size from the instance of hmac instead rfc 2104 hmac class also complies with rfc 4231 this supports the api for cryptographic hash functions pep 247 512 bit hmac can be changed in subclasses create a new hmac object key bytes or buffer key for the keyed hash object msg bytes or buffer initial input for the hash or none digestmod a hash name suitable for hashlib new or a hashlib constructor returning a new hash object or a module supporting pep 247 required as of 3 8 despite its position after the optional msg argument passing it as a keyword argument is recommended though not required for legacy api reasons self blocksize is the default blocksize self block_size is effective block size as well as the public api attribute feed data from msg into this hashing object return a separate copy of this hashing object an update to this copy won t affect the original object call __new__ directly to avoid the expensive __init__ return a hash object for the current state to be used only internally with digest and hexdigest return the hash value of this hashing object this returns the hmac value as bytes the object is not altered in any way by this function you can continue updating the object after calling this function like digest but returns a string of hexadecimal digits instead create a new hashing object and return it key bytes or buffer the starting key for the hash msg bytes or buffer initial input for the hash or none digestmod a hash name suitable for hashlib new or a hashlib constructor returning a new hash object or a module supporting pep 247 required as of 3 8 despite its position after the optional msg argument passing it as a keyword argument is recommended though not required for legacy api reasons you can now feed arbitrary bytes into the object using its update method and can ask for the hash value at any time by calling its digest or hexdigest methods fast inline implementation of hmac key bytes or buffer the key for the keyed hash object msg bytes or buffer input message digest a hash name suitable for hashlib new for best performance or a hashlib constructor returning a new hash object or a module supporting pep 247
import warnings as _warnings
try:
    import _hashlib as _hashopenssl
except ImportError:
    _hashopenssl = None
    _functype = None
    from _operator import _compare_digest as compare_digest
else:
    compare_digest = _hashopenssl.compare_digest
    _functype = type(_hashopenssl.openssl_sha256)  

import hashlib as _hashlib

trans_5C = bytes((x ^ 0x5C) for x in range(256))
trans_36 = bytes((x ^ 0x36) for x in range(256))



digest_size = None


class HMAC:
    
    blocksize = 64  

    __slots__ = (
        "_hmac", "_inner", "_outer", "block_size", "digest_size"
    )

    def __init__(self, key, msg=None, digestmod=''):
        

        if not isinstance(key, (bytes, bytearray)):
            raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)

        if not digestmod:
            raise TypeError("Missing required parameter 'digestmod'.")

        if _hashopenssl and isinstance(digestmod, (str, _functype)):
            try:
                self._init_hmac(key, msg, digestmod)
            except _hashopenssl.UnsupportedDigestmodError:
                self._init_old(key, msg, digestmod)
        else:
            self._init_old(key, msg, digestmod)

    def _init_hmac(self, key, msg, digestmod):
        self._hmac = _hashopenssl.hmac_new(key, msg, digestmod=digestmod)
        self.digest_size = self._hmac.digest_size
        self.block_size = self._hmac.block_size

    def _init_old(self, key, msg, digestmod):
        if callable(digestmod):
            digest_cons = digestmod
        elif isinstance(digestmod, str):
            digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
        else:
            digest_cons = lambda d=b'': digestmod.new(d)

        self._hmac = None
        self._outer = digest_cons()
        self._inner = digest_cons()
        self.digest_size = self._inner.digest_size

        if hasattr(self._inner, 'block_size'):
            blocksize = self._inner.block_size
            if blocksize < 16:
                _warnings.warn('block_size of %d seems too small; using our '
                               'default of %d.' % (blocksize, self.blocksize),
                               RuntimeWarning, 2)
                blocksize = self.blocksize
        else:
            _warnings.warn('No block_size attribute on given digest object; '
                           'Assuming %d.' % (self.blocksize),
                           RuntimeWarning, 2)
            blocksize = self.blocksize

        if len(key) > blocksize:
            key = digest_cons(key).digest()

        
        
        self.block_size = blocksize

        key = key.ljust(blocksize, b'\0')
        self._outer.update(key.translate(trans_5C))
        self._inner.update(key.translate(trans_36))
        if msg is not None:
            self.update(msg)

    @property
    def name(self):
        if self._hmac:
            return self._hmac.name
        else:
            return f"hmac-{self._inner.name}"

    def update(self, msg):
        
        inst = self._hmac or self._inner
        inst.update(msg)

    def copy(self):
        
        
        other = self.__class__.__new__(self.__class__)
        other.digest_size = self.digest_size
        if self._hmac:
            other._hmac = self._hmac.copy()
            other._inner = other._outer = None
        else:
            other._hmac = None
            other._inner = self._inner.copy()
            other._outer = self._outer.copy()
        return other

    def _current(self):
        
        if self._hmac:
            return self._hmac
        else:
            h = self._outer.copy()
            h.update(self._inner.digest())
            return h

    def digest(self):
        
        h = self._current()
        return h.digest()

    def hexdigest(self):
        
        h = self._current()
        return h.hexdigest()

def new(key, msg=None, digestmod=''):
    
    return HMAC(key, msg, digestmod)


def digest(key, msg, digest):
    
    if _hashopenssl is not None and isinstance(digest, (str, _functype)):
        try:
            return _hashopenssl.hmac_digest(key, msg, digest)
        except _hashopenssl.UnsupportedDigestmodError:
            pass

    if callable(digest):
        digest_cons = digest
    elif isinstance(digest, str):
        digest_cons = lambda d=b'': _hashlib.new(digest, d)
    else:
        digest_cons = lambda d=b'': digest.new(d)

    inner = digest_cons()
    outer = digest_cons()
    blocksize = getattr(inner, 'block_size', 64)
    if len(key) > blocksize:
        key = digest_cons(key).digest()
    key = key + b'\x00' * (blocksize - len(key))
    inner.update(key.translate(trans_36))
    outer.update(key.translate(trans_5C))
    inner.update(msg)
    outer.update(inner.digest())
    return outer.digest()