xref: /third_party/python/Lib/hmac.py (revision 7db96d56)
17db96d56Sopenharmony_ci"""HMAC (Keyed-Hashing for Message Authentication) module.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciImplements the HMAC algorithm as described by RFC 2104.
47db96d56Sopenharmony_ci"""
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ciimport warnings as _warnings
77db96d56Sopenharmony_citry:
87db96d56Sopenharmony_ci    import _hashlib as _hashopenssl
97db96d56Sopenharmony_ciexcept ImportError:
107db96d56Sopenharmony_ci    _hashopenssl = None
117db96d56Sopenharmony_ci    _functype = None
127db96d56Sopenharmony_ci    from _operator import _compare_digest as compare_digest
137db96d56Sopenharmony_cielse:
147db96d56Sopenharmony_ci    compare_digest = _hashopenssl.compare_digest
157db96d56Sopenharmony_ci    _functype = type(_hashopenssl.openssl_sha256)  # builtin type
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ciimport hashlib as _hashlib
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_citrans_5C = bytes((x ^ 0x5C) for x in range(256))
207db96d56Sopenharmony_citrans_36 = bytes((x ^ 0x36) for x in range(256))
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ci# The size of the digests returned by HMAC depends on the underlying
237db96d56Sopenharmony_ci# hashing module used.  Use digest_size from the instance of HMAC instead.
247db96d56Sopenharmony_cidigest_size = None
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ciclass HMAC:
287db96d56Sopenharmony_ci    """RFC 2104 HMAC class.  Also complies with RFC 4231.
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci    This supports the API for Cryptographic Hash Functions (PEP 247).
317db96d56Sopenharmony_ci    """
327db96d56Sopenharmony_ci    blocksize = 64  # 512-bit HMAC; can be changed in subclasses.
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ci    __slots__ = (
357db96d56Sopenharmony_ci        "_hmac", "_inner", "_outer", "block_size", "digest_size"
367db96d56Sopenharmony_ci    )
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ci    def __init__(self, key, msg=None, digestmod=''):
397db96d56Sopenharmony_ci        """Create a new HMAC object.
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci        key: bytes or buffer, key for the keyed hash object.
427db96d56Sopenharmony_ci        msg: bytes or buffer, Initial input for the hash or None.
437db96d56Sopenharmony_ci        digestmod: A hash name suitable for hashlib.new(). *OR*
447db96d56Sopenharmony_ci                   A hashlib constructor returning a new hash object. *OR*
457db96d56Sopenharmony_ci                   A module supporting PEP 247.
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci                   Required as of 3.8, despite its position after the optional
487db96d56Sopenharmony_ci                   msg argument.  Passing it as a keyword argument is
497db96d56Sopenharmony_ci                   recommended, though not required for legacy API reasons.
507db96d56Sopenharmony_ci        """
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ci        if not isinstance(key, (bytes, bytearray)):
537db96d56Sopenharmony_ci            raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci        if not digestmod:
567db96d56Sopenharmony_ci            raise TypeError("Missing required parameter 'digestmod'.")
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci        if _hashopenssl and isinstance(digestmod, (str, _functype)):
597db96d56Sopenharmony_ci            try:
607db96d56Sopenharmony_ci                self._init_hmac(key, msg, digestmod)
617db96d56Sopenharmony_ci            except _hashopenssl.UnsupportedDigestmodError:
627db96d56Sopenharmony_ci                self._init_old(key, msg, digestmod)
637db96d56Sopenharmony_ci        else:
647db96d56Sopenharmony_ci            self._init_old(key, msg, digestmod)
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ci    def _init_hmac(self, key, msg, digestmod):
677db96d56Sopenharmony_ci        self._hmac = _hashopenssl.hmac_new(key, msg, digestmod=digestmod)
687db96d56Sopenharmony_ci        self.digest_size = self._hmac.digest_size
697db96d56Sopenharmony_ci        self.block_size = self._hmac.block_size
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci    def _init_old(self, key, msg, digestmod):
727db96d56Sopenharmony_ci        if callable(digestmod):
737db96d56Sopenharmony_ci            digest_cons = digestmod
747db96d56Sopenharmony_ci        elif isinstance(digestmod, str):
757db96d56Sopenharmony_ci            digest_cons = lambda d=b'': _hashlib.new(digestmod, d)
767db96d56Sopenharmony_ci        else:
777db96d56Sopenharmony_ci            digest_cons = lambda d=b'': digestmod.new(d)
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci        self._hmac = None
807db96d56Sopenharmony_ci        self._outer = digest_cons()
817db96d56Sopenharmony_ci        self._inner = digest_cons()
827db96d56Sopenharmony_ci        self.digest_size = self._inner.digest_size
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci        if hasattr(self._inner, 'block_size'):
857db96d56Sopenharmony_ci            blocksize = self._inner.block_size
867db96d56Sopenharmony_ci            if blocksize < 16:
877db96d56Sopenharmony_ci                _warnings.warn('block_size of %d seems too small; using our '
887db96d56Sopenharmony_ci                               'default of %d.' % (blocksize, self.blocksize),
897db96d56Sopenharmony_ci                               RuntimeWarning, 2)
907db96d56Sopenharmony_ci                blocksize = self.blocksize
917db96d56Sopenharmony_ci        else:
927db96d56Sopenharmony_ci            _warnings.warn('No block_size attribute on given digest object; '
937db96d56Sopenharmony_ci                           'Assuming %d.' % (self.blocksize),
947db96d56Sopenharmony_ci                           RuntimeWarning, 2)
957db96d56Sopenharmony_ci            blocksize = self.blocksize
967db96d56Sopenharmony_ci
977db96d56Sopenharmony_ci        if len(key) > blocksize:
987db96d56Sopenharmony_ci            key = digest_cons(key).digest()
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_ci        # self.blocksize is the default blocksize. self.block_size is
1017db96d56Sopenharmony_ci        # effective block size as well as the public API attribute.
1027db96d56Sopenharmony_ci        self.block_size = blocksize
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_ci        key = key.ljust(blocksize, b'\0')
1057db96d56Sopenharmony_ci        self._outer.update(key.translate(trans_5C))
1067db96d56Sopenharmony_ci        self._inner.update(key.translate(trans_36))
1077db96d56Sopenharmony_ci        if msg is not None:
1087db96d56Sopenharmony_ci            self.update(msg)
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_ci    @property
1117db96d56Sopenharmony_ci    def name(self):
1127db96d56Sopenharmony_ci        if self._hmac:
1137db96d56Sopenharmony_ci            return self._hmac.name
1147db96d56Sopenharmony_ci        else:
1157db96d56Sopenharmony_ci            return f"hmac-{self._inner.name}"
1167db96d56Sopenharmony_ci
1177db96d56Sopenharmony_ci    def update(self, msg):
1187db96d56Sopenharmony_ci        """Feed data from msg into this hashing object."""
1197db96d56Sopenharmony_ci        inst = self._hmac or self._inner
1207db96d56Sopenharmony_ci        inst.update(msg)
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci    def copy(self):
1237db96d56Sopenharmony_ci        """Return a separate copy of this hashing object.
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ci        An update to this copy won't affect the original object.
1267db96d56Sopenharmony_ci        """
1277db96d56Sopenharmony_ci        # Call __new__ directly to avoid the expensive __init__.
1287db96d56Sopenharmony_ci        other = self.__class__.__new__(self.__class__)
1297db96d56Sopenharmony_ci        other.digest_size = self.digest_size
1307db96d56Sopenharmony_ci        if self._hmac:
1317db96d56Sopenharmony_ci            other._hmac = self._hmac.copy()
1327db96d56Sopenharmony_ci            other._inner = other._outer = None
1337db96d56Sopenharmony_ci        else:
1347db96d56Sopenharmony_ci            other._hmac = None
1357db96d56Sopenharmony_ci            other._inner = self._inner.copy()
1367db96d56Sopenharmony_ci            other._outer = self._outer.copy()
1377db96d56Sopenharmony_ci        return other
1387db96d56Sopenharmony_ci
1397db96d56Sopenharmony_ci    def _current(self):
1407db96d56Sopenharmony_ci        """Return a hash object for the current state.
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_ci        To be used only internally with digest() and hexdigest().
1437db96d56Sopenharmony_ci        """
1447db96d56Sopenharmony_ci        if self._hmac:
1457db96d56Sopenharmony_ci            return self._hmac
1467db96d56Sopenharmony_ci        else:
1477db96d56Sopenharmony_ci            h = self._outer.copy()
1487db96d56Sopenharmony_ci            h.update(self._inner.digest())
1497db96d56Sopenharmony_ci            return h
1507db96d56Sopenharmony_ci
1517db96d56Sopenharmony_ci    def digest(self):
1527db96d56Sopenharmony_ci        """Return the hash value of this hashing object.
1537db96d56Sopenharmony_ci
1547db96d56Sopenharmony_ci        This returns the hmac value as bytes.  The object is
1557db96d56Sopenharmony_ci        not altered in any way by this function; you can continue
1567db96d56Sopenharmony_ci        updating the object after calling this function.
1577db96d56Sopenharmony_ci        """
1587db96d56Sopenharmony_ci        h = self._current()
1597db96d56Sopenharmony_ci        return h.digest()
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_ci    def hexdigest(self):
1627db96d56Sopenharmony_ci        """Like digest(), but returns a string of hexadecimal digits instead.
1637db96d56Sopenharmony_ci        """
1647db96d56Sopenharmony_ci        h = self._current()
1657db96d56Sopenharmony_ci        return h.hexdigest()
1667db96d56Sopenharmony_ci
1677db96d56Sopenharmony_cidef new(key, msg=None, digestmod=''):
1687db96d56Sopenharmony_ci    """Create a new hashing object and return it.
1697db96d56Sopenharmony_ci
1707db96d56Sopenharmony_ci    key: bytes or buffer, The starting key for the hash.
1717db96d56Sopenharmony_ci    msg: bytes or buffer, Initial input for the hash, or None.
1727db96d56Sopenharmony_ci    digestmod: A hash name suitable for hashlib.new(). *OR*
1737db96d56Sopenharmony_ci               A hashlib constructor returning a new hash object. *OR*
1747db96d56Sopenharmony_ci               A module supporting PEP 247.
1757db96d56Sopenharmony_ci
1767db96d56Sopenharmony_ci               Required as of 3.8, despite its position after the optional
1777db96d56Sopenharmony_ci               msg argument.  Passing it as a keyword argument is
1787db96d56Sopenharmony_ci               recommended, though not required for legacy API reasons.
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci    You can now feed arbitrary bytes into the object using its update()
1817db96d56Sopenharmony_ci    method, and can ask for the hash value at any time by calling its digest()
1827db96d56Sopenharmony_ci    or hexdigest() methods.
1837db96d56Sopenharmony_ci    """
1847db96d56Sopenharmony_ci    return HMAC(key, msg, digestmod)
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci
1877db96d56Sopenharmony_cidef digest(key, msg, digest):
1887db96d56Sopenharmony_ci    """Fast inline implementation of HMAC.
1897db96d56Sopenharmony_ci
1907db96d56Sopenharmony_ci    key: bytes or buffer, The key for the keyed hash object.
1917db96d56Sopenharmony_ci    msg: bytes or buffer, Input message.
1927db96d56Sopenharmony_ci    digest: A hash name suitable for hashlib.new() for best performance. *OR*
1937db96d56Sopenharmony_ci            A hashlib constructor returning a new hash object. *OR*
1947db96d56Sopenharmony_ci            A module supporting PEP 247.
1957db96d56Sopenharmony_ci    """
1967db96d56Sopenharmony_ci    if _hashopenssl is not None and isinstance(digest, (str, _functype)):
1977db96d56Sopenharmony_ci        try:
1987db96d56Sopenharmony_ci            return _hashopenssl.hmac_digest(key, msg, digest)
1997db96d56Sopenharmony_ci        except _hashopenssl.UnsupportedDigestmodError:
2007db96d56Sopenharmony_ci            pass
2017db96d56Sopenharmony_ci
2027db96d56Sopenharmony_ci    if callable(digest):
2037db96d56Sopenharmony_ci        digest_cons = digest
2047db96d56Sopenharmony_ci    elif isinstance(digest, str):
2057db96d56Sopenharmony_ci        digest_cons = lambda d=b'': _hashlib.new(digest, d)
2067db96d56Sopenharmony_ci    else:
2077db96d56Sopenharmony_ci        digest_cons = lambda d=b'': digest.new(d)
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci    inner = digest_cons()
2107db96d56Sopenharmony_ci    outer = digest_cons()
2117db96d56Sopenharmony_ci    blocksize = getattr(inner, 'block_size', 64)
2127db96d56Sopenharmony_ci    if len(key) > blocksize:
2137db96d56Sopenharmony_ci        key = digest_cons(key).digest()
2147db96d56Sopenharmony_ci    key = key + b'\x00' * (blocksize - len(key))
2157db96d56Sopenharmony_ci    inner.update(key.translate(trans_36))
2167db96d56Sopenharmony_ci    outer.update(key.translate(trans_5C))
2177db96d56Sopenharmony_ci    inner.update(msg)
2187db96d56Sopenharmony_ci    outer.update(inner.digest())
2197db96d56Sopenharmony_ci    return outer.digest()
220