xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/hmac.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
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