mirror of
				https://github.com/python/cpython.git
				synced 2025-11-02 22:51:25 +00:00 
			
		
		
		
	gh-132388: test HACL* and OpenSSL hash functions in pure Python HMAC (GH-134051)
(cherry picked from commit 73d71a416f)
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
		
	
			
		
			
				
	
	
		
			1536 lines
		
	
	
	
		
			56 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1536 lines
		
	
	
	
		
			56 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Test suite for HMAC.
 | 
						|
 | 
						|
Python provides three different implementations of HMAC:
 | 
						|
 | 
						|
- OpenSSL HMAC using OpenSSL hash functions.
 | 
						|
- HACL* HMAC using HACL* hash functions.
 | 
						|
- Generic Python HMAC using user-defined hash functions.
 | 
						|
 | 
						|
The generic Python HMAC implementation is able to use OpenSSL
 | 
						|
callables or names, HACL* named hash functions or arbitrary
 | 
						|
objects implementing PEP 247 interface.
 | 
						|
 | 
						|
In the two first cases, Python HMAC wraps a C HMAC object (either OpenSSL
 | 
						|
or HACL*-based). As a last resort, HMAC is re-implemented in pure Python.
 | 
						|
It is however interesting to test the pure Python implementation against
 | 
						|
the OpenSSL and HACL* hash functions.
 | 
						|
"""
 | 
						|
 | 
						|
import binascii
 | 
						|
import functools
 | 
						|
import hmac
 | 
						|
import hashlib
 | 
						|
import random
 | 
						|
import test.support
 | 
						|
import test.support.hashlib_helper as hashlib_helper
 | 
						|
import types
 | 
						|
import unittest
 | 
						|
import unittest.mock as mock
 | 
						|
import warnings
 | 
						|
from _operator import _compare_digest as operator_compare_digest
 | 
						|
from test.support import check_disallow_instantiation
 | 
						|
from test.support.hashlib_helper import (
 | 
						|
    BuiltinHashFunctionsTrait,
 | 
						|
    HashFunctionsTrait,
 | 
						|
    NamedHashFunctionsTrait,
 | 
						|
    OpenSSLHashFunctionsTrait,
 | 
						|
)
 | 
						|
from test.support.import_helper import import_fresh_module, import_module
 | 
						|
 | 
						|
try:
 | 
						|
    import _hashlib
 | 
						|
    from _hashlib import compare_digest as openssl_compare_digest
 | 
						|
except ImportError:
 | 
						|
    _hashlib = None
 | 
						|
    openssl_compare_digest = None
 | 
						|
 | 
						|
try:
 | 
						|
    import _sha2 as sha2
 | 
						|
except ImportError:
 | 
						|
    sha2 = None
 | 
						|
 | 
						|
 | 
						|
def requires_builtin_sha2():
 | 
						|
    return unittest.skipIf(sha2 is None, "requires _sha2")
 | 
						|
 | 
						|
 | 
						|
class ModuleMixin:
 | 
						|
    """Mixin with a HMAC module implementation."""
 | 
						|
 | 
						|
    hmac = None
 | 
						|
 | 
						|
 | 
						|
class PyModuleMixin(ModuleMixin):
 | 
						|
    """Pure Python implementation of HMAC.
 | 
						|
 | 
						|
    The underlying hash functions may be OpenSSL-based or HACL* based,
 | 
						|
    depending on whether OpenSSL is present or not.
 | 
						|
    """
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        super().setUpClass()
 | 
						|
        cls.hmac = import_fresh_module('hmac', blocked=['_hashlib', '_hmac'])
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_builtin_hmac()
 | 
						|
class BuiltinModuleMixin(ModuleMixin):
 | 
						|
    """Built-in HACL* implementation of HMAC."""
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        super().setUpClass()
 | 
						|
        cls.hmac = import_fresh_module('_hmac')
 | 
						|
 | 
						|
 | 
						|
# Sentinel object used to detect whether a digestmod is given or not.
 | 
						|
DIGESTMOD_SENTINEL = object()
 | 
						|
 | 
						|
 | 
						|
class CreatorMixin:
 | 
						|
    """Mixin exposing a method creating a HMAC object."""
 | 
						|
 | 
						|
    def hmac_new(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        """Create a new HMAC object.
 | 
						|
 | 
						|
        Implementations should accept arbitrary 'digestmod' as this
 | 
						|
        method can be used to test which exceptions are being raised.
 | 
						|
        """
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def bind_hmac_new(self, digestmod):
 | 
						|
        """Return a specialization of hmac_new() with a bound digestmod."""
 | 
						|
        return functools.partial(self.hmac_new, digestmod=digestmod)
 | 
						|
 | 
						|
 | 
						|
class DigestMixin:
 | 
						|
    """Mixin exposing a method computing a HMAC digest."""
 | 
						|
 | 
						|
    def hmac_digest(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        """Compute a HMAC digest.
 | 
						|
 | 
						|
        Implementations should accept arbitrary 'digestmod' as this
 | 
						|
        method can be used to test which exceptions are being raised.
 | 
						|
        """
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def bind_hmac_digest(self, digestmod):
 | 
						|
        """Return a specialization of hmac_digest() with a bound digestmod."""
 | 
						|
        return functools.partial(self.hmac_digest, digestmod=digestmod)
 | 
						|
 | 
						|
 | 
						|
def _call_newobj_func(new_func, key, msg, digestmod):
 | 
						|
    if digestmod is DIGESTMOD_SENTINEL:  # to test when digestmod is missing
 | 
						|
        return new_func(key, msg)  # expected to raise
 | 
						|
    # functions creating HMAC objects take a 'digestmod' keyword argument
 | 
						|
    return new_func(key, msg, digestmod=digestmod)
 | 
						|
 | 
						|
 | 
						|
def _call_digest_func(digest_func, key, msg, digestmod):
 | 
						|
    if digestmod is DIGESTMOD_SENTINEL:  # to test when digestmod is missing
 | 
						|
        return digest_func(key, msg)  # expected to raise
 | 
						|
    # functions directly computing digests take a 'digest' keyword argument
 | 
						|
    return digest_func(key, msg, digest=digestmod)
 | 
						|
 | 
						|
 | 
						|
class ThroughObjectMixin(ModuleMixin, CreatorMixin, DigestMixin):
 | 
						|
    """Mixin delegating to <module>.HMAC() and <module>.HMAC(...).digest().
 | 
						|
 | 
						|
    Both the C implementation and the Python implementation of HMAC should
 | 
						|
    expose a HMAC class with the same functionalities.
 | 
						|
    """
 | 
						|
 | 
						|
    def hmac_new(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        """Create a HMAC object via a module-level class constructor."""
 | 
						|
        return _call_newobj_func(self.hmac.HMAC, key, msg, digestmod)
 | 
						|
 | 
						|
    def hmac_digest(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        """Call the digest() method on a HMAC object obtained by hmac_new()."""
 | 
						|
        return _call_newobj_func(self.hmac_new, key, msg, digestmod).digest()
 | 
						|
 | 
						|
 | 
						|
class ThroughModuleAPIMixin(ModuleMixin, CreatorMixin, DigestMixin):
 | 
						|
    """Mixin delegating to <module>.new() and <module>.digest()."""
 | 
						|
 | 
						|
    def hmac_new(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        """Create a HMAC object via a module-level function."""
 | 
						|
        return _call_newobj_func(self.hmac.new, key, msg, digestmod)
 | 
						|
 | 
						|
    def hmac_digest(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        """One-shot HMAC digest computation."""
 | 
						|
        return _call_digest_func(self.hmac.digest, key, msg, digestmod)
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_hashlib()
 | 
						|
class ThroughOpenSSLAPIMixin(CreatorMixin, DigestMixin):
 | 
						|
    """Mixin delegating to _hashlib.hmac_new() and _hashlib.hmac_digest()."""
 | 
						|
 | 
						|
    def hmac_new(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        return _call_newobj_func(_hashlib.hmac_new, key, msg, digestmod)
 | 
						|
 | 
						|
    def hmac_digest(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        return _call_digest_func(_hashlib.hmac_digest, key, msg, digestmod)
 | 
						|
 | 
						|
 | 
						|
class ThroughBuiltinAPIMixin(BuiltinModuleMixin, CreatorMixin, DigestMixin):
 | 
						|
    """Mixin delegating to _hmac.new() and _hmac.compute_digest()."""
 | 
						|
 | 
						|
    def hmac_new(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        return _call_newobj_func(self.hmac.new, key, msg, digestmod)
 | 
						|
 | 
						|
    def hmac_digest(self, key, msg=None, digestmod=DIGESTMOD_SENTINEL):
 | 
						|
        return _call_digest_func(self.hmac.compute_digest, key, msg, digestmod)
 | 
						|
 | 
						|
 | 
						|
class ObjectCheckerMixin:
 | 
						|
    """Mixin for checking HMAC objects (pure Python, OpenSSL or built-in)."""
 | 
						|
 | 
						|
    def check_object(self, h, hexdigest, hashname, digest_size, block_size):
 | 
						|
        """Check a HMAC object 'h' against the given values."""
 | 
						|
        self.check_internals(h, hashname, digest_size, block_size)
 | 
						|
        self.check_hexdigest(h, hexdigest, digest_size)
 | 
						|
 | 
						|
    def check_internals(self, h, hashname, digest_size, block_size):
 | 
						|
        """Check the constant attributes of a HMAC object."""
 | 
						|
        self.assertEqual(h.name, f"hmac-{hashname}")
 | 
						|
        self.assertEqual(h.digest_size, digest_size)
 | 
						|
        self.assertEqual(h.block_size, block_size)
 | 
						|
 | 
						|
    def check_hexdigest(self, h, hexdigest, digest_size):
 | 
						|
        """Check the HMAC digest of 'h' and its size."""
 | 
						|
        self.assertEqual(len(h.digest()), digest_size)
 | 
						|
        self.assertEqual(h.digest(), binascii.unhexlify(hexdigest))
 | 
						|
        self.assertEqual(h.hexdigest().upper(), hexdigest.upper())
 | 
						|
 | 
						|
 | 
						|
class AssertersMixin(CreatorMixin, DigestMixin, ObjectCheckerMixin):
 | 
						|
    """Mixin class for common tests."""
 | 
						|
 | 
						|
    def hmac_new_by_name(self, key, msg=None, *, hashname):
 | 
						|
        """Alternative implementation of hmac_new().
 | 
						|
 | 
						|
        This is typically useful when one needs to test against an HMAC
 | 
						|
        implementation which only recognizes underlying hash functions
 | 
						|
        by their name (all HMAC implementations must at least recognize
 | 
						|
        hash functions by their names but some may use aliases such as
 | 
						|
        `hashlib.sha1` instead of "sha1").
 | 
						|
 | 
						|
        Unlike hmac_new(), this method may assert the type of 'hashname'
 | 
						|
        as it should only be used in tests that are expected to create
 | 
						|
        a HMAC object.
 | 
						|
        """
 | 
						|
        self.assertIsInstance(hashname, str)
 | 
						|
        return self.hmac_new(key, msg, digestmod=hashname)
 | 
						|
 | 
						|
    def hmac_digest_by_name(self, key, msg=None, *, hashname):
 | 
						|
        """Alternative implementation of hmac_digest().
 | 
						|
 | 
						|
        Unlike hmac_digest(), this method may assert the type of 'hashname'
 | 
						|
        as it should only be used in tests that are expected to compute a
 | 
						|
        HMAC digest.
 | 
						|
        """
 | 
						|
        self.assertIsInstance(hashname, str)
 | 
						|
        return self.hmac_digest(key, msg, digestmod=hashname)
 | 
						|
 | 
						|
    def assert_hmac(
 | 
						|
        self, key, msg, hexdigest, hashfunc, hashname, digest_size, block_size
 | 
						|
    ):
 | 
						|
        """Check that HMAC(key, msg) == digest.
 | 
						|
 | 
						|
        The 'hashfunc' and 'hashname' are used as 'digestmod' values,
 | 
						|
        thereby allowing to test the underlying dispatching mechanism.
 | 
						|
 | 
						|
        Note that 'hashfunc' may be a string, a callable, or a PEP-257
 | 
						|
        module. Note that not all HMAC implementations may recognize the
 | 
						|
        same set of types for 'hashfunc', but they should always accept
 | 
						|
        a hash function by its name.
 | 
						|
        """
 | 
						|
        if hashfunc == hashname:
 | 
						|
            choices = [hashname]
 | 
						|
        else:
 | 
						|
            choices = [hashfunc, hashname]
 | 
						|
 | 
						|
        for digestmod in choices:
 | 
						|
            with self.subTest(digestmod=digestmod):
 | 
						|
                self.assert_hmac_new(
 | 
						|
                    key, msg, hexdigest, digestmod,
 | 
						|
                    hashname, digest_size, block_size
 | 
						|
                )
 | 
						|
                self.assert_hmac_hexdigest(
 | 
						|
                    key, msg, hexdigest, digestmod, digest_size
 | 
						|
                )
 | 
						|
                self.assert_hmac_common_cases(
 | 
						|
                    key, msg, hexdigest, digestmod,
 | 
						|
                    hashname, digest_size, block_size
 | 
						|
                )
 | 
						|
                self.assert_hmac_extra_cases(
 | 
						|
                    key, msg, hexdigest, digestmod,
 | 
						|
                    hashname, digest_size, block_size
 | 
						|
                )
 | 
						|
 | 
						|
        self.assert_hmac_new_by_name(
 | 
						|
            key, msg, hexdigest, hashname, digest_size, block_size
 | 
						|
        )
 | 
						|
        self.assert_hmac_hexdigest_by_name(
 | 
						|
            key, msg, hexdigest, hashname, digest_size
 | 
						|
        )
 | 
						|
 | 
						|
    def assert_hmac_new(
 | 
						|
        self, key, msg, hexdigest, digestmod, hashname, digest_size, block_size
 | 
						|
    ):
 | 
						|
        """Check that HMAC(key, msg) == digest.
 | 
						|
 | 
						|
        This test uses the `hmac_new()` method to create HMAC objects.
 | 
						|
        """
 | 
						|
        self.check_hmac_new(
 | 
						|
            key, msg, hexdigest, hashname, digest_size, block_size,
 | 
						|
            hmac_new_func=self.hmac_new,
 | 
						|
            hmac_new_kwds={'digestmod': digestmod},
 | 
						|
        )
 | 
						|
 | 
						|
    def assert_hmac_new_by_name(
 | 
						|
        self, key, msg, hexdigest, hashname, digest_size, block_size
 | 
						|
    ):
 | 
						|
        """Check that HMAC(key, msg) == digest.
 | 
						|
 | 
						|
        This test uses the `hmac_new_by_name()` method to create HMAC objects.
 | 
						|
        """
 | 
						|
        self.check_hmac_new(
 | 
						|
            key, msg, hexdigest, hashname, digest_size, block_size,
 | 
						|
            hmac_new_func=self.hmac_new_by_name,
 | 
						|
            hmac_new_kwds={'hashname': hashname},
 | 
						|
        )
 | 
						|
 | 
						|
    def check_hmac_new(
 | 
						|
        self, key, msg, hexdigest, hashname, digest_size, block_size,
 | 
						|
        hmac_new_func, hmac_new_kwds=types.MappingProxyType({}),
 | 
						|
    ):
 | 
						|
        """Check that HMAC(key, msg) == digest.
 | 
						|
 | 
						|
        This also tests that using an empty/None initial message and
 | 
						|
        then calling `h.update(msg)` produces the same result, namely
 | 
						|
        that HMAC(key, msg) is equivalent to HMAC(key).update(msg).
 | 
						|
        """
 | 
						|
        h = hmac_new_func(key, msg, **hmac_new_kwds)
 | 
						|
        self.check_object(h, hexdigest, hashname, digest_size, block_size)
 | 
						|
 | 
						|
        def hmac_new_feed(*args):
 | 
						|
            h = hmac_new_func(key, *args, **hmac_new_kwds)
 | 
						|
            h.update(msg)
 | 
						|
            self.check_hexdigest(h, hexdigest, digest_size)
 | 
						|
 | 
						|
        with self.subTest('no initial message'):
 | 
						|
            hmac_new_feed()
 | 
						|
        with self.subTest('initial message is empty'):
 | 
						|
            hmac_new_feed(b'')
 | 
						|
        with self.subTest('initial message is None'):
 | 
						|
            hmac_new_feed(None)
 | 
						|
 | 
						|
    def assert_hmac_hexdigest(
 | 
						|
        self, key, msg, hexdigest, digestmod, digest_size,
 | 
						|
    ):
 | 
						|
        """Check a HMAC digest computed by hmac_digest()."""
 | 
						|
        self.check_hmac_hexdigest(
 | 
						|
            key, msg, hexdigest, digest_size,
 | 
						|
            hmac_digest_func=self.hmac_digest,
 | 
						|
            hmac_digest_kwds={'digestmod': digestmod},
 | 
						|
        )
 | 
						|
 | 
						|
    def assert_hmac_hexdigest_by_name(
 | 
						|
        self, key, msg, hexdigest, hashname, digest_size
 | 
						|
    ):
 | 
						|
        """Check a HMAC digest computed by hmac_digest_by_name()."""
 | 
						|
        self.assertIsInstance(hashname, str)
 | 
						|
        self.check_hmac_hexdigest(
 | 
						|
            key, msg, hexdigest, digest_size,
 | 
						|
            hmac_digest_func=self.hmac_digest_by_name,
 | 
						|
            hmac_digest_kwds={'hashname': hashname},
 | 
						|
        )
 | 
						|
 | 
						|
    def check_hmac_hexdigest(
 | 
						|
        self, key, msg, hexdigest, digest_size,
 | 
						|
        hmac_digest_func, hmac_digest_kwds=types.MappingProxyType({}),
 | 
						|
    ):
 | 
						|
        """Check and return a HMAC digest computed by hmac_digest_func().
 | 
						|
 | 
						|
        This HMAC digest is computed by:
 | 
						|
 | 
						|
            hmac_digest_func(key, msg, **hmac_digest_kwds)
 | 
						|
 | 
						|
        This is typically useful for checking one-shot HMAC functions.
 | 
						|
        """
 | 
						|
        d = hmac_digest_func(key, msg, **hmac_digest_kwds)
 | 
						|
        self.assertEqual(len(d), digest_size)
 | 
						|
        self.assertEqual(d, binascii.unhexlify(hexdigest))
 | 
						|
        return d
 | 
						|
 | 
						|
    def assert_hmac_common_cases(
 | 
						|
        self, key, msg, hexdigest, digestmod, hashname, digest_size, block_size
 | 
						|
    ):
 | 
						|
        """Common tests executed by all subclasses."""
 | 
						|
        h1 = self.hmac_new_by_name(key, hashname=hashname)
 | 
						|
        h2 = h1.copy()
 | 
						|
        h2.update(b"test update should not affect original")
 | 
						|
        h1.update(msg)
 | 
						|
        self.check_object(h1, hexdigest, hashname, digest_size, block_size)
 | 
						|
 | 
						|
    def assert_hmac_extra_cases(
 | 
						|
        self, key, msg, hexdigest, digestmod, hashname, digest_size, block_size
 | 
						|
    ):
 | 
						|
        """Extra tests that can be added in subclasses."""
 | 
						|
 | 
						|
 | 
						|
class PyAssertersMixin(PyModuleMixin, AssertersMixin):
 | 
						|
 | 
						|
    def assert_hmac_extra_cases(
 | 
						|
        self, key, msg, hexdigest, digestmod, hashname, digest_size, block_size
 | 
						|
    ):
 | 
						|
        h = self.hmac.HMAC.__new__(self.hmac.HMAC)
 | 
						|
        h._init_old(key, msg, digestmod=digestmod)
 | 
						|
        self.check_object(h, hexdigest, hashname, digest_size, block_size)
 | 
						|
 | 
						|
 | 
						|
class OpenSSLAssertersMixin(ThroughOpenSSLAPIMixin, AssertersMixin):
 | 
						|
 | 
						|
    def hmac_new_by_name(self, key, msg=None, *, hashname):
 | 
						|
        self.assertIsInstance(hashname, str)
 | 
						|
        openssl_func = getattr(_hashlib, f"openssl_{hashname}")
 | 
						|
        return self.hmac_new(key, msg, digestmod=openssl_func)
 | 
						|
 | 
						|
    def hmac_digest_by_name(self, key, msg=None, *, hashname):
 | 
						|
        self.assertIsInstance(hashname, str)
 | 
						|
        openssl_func = getattr(_hashlib, f"openssl_{hashname}")
 | 
						|
        return self.hmac_digest(key, msg, digestmod=openssl_func)
 | 
						|
 | 
						|
 | 
						|
class BuiltinAssertersMixin(ThroughBuiltinAPIMixin, AssertersMixin):
 | 
						|
    pass
 | 
						|
 | 
						|
 | 
						|
class RFCTestCaseMixin(HashFunctionsTrait, AssertersMixin):
 | 
						|
    """Test HMAC implementations against RFC 2202/4231 and NIST test vectors.
 | 
						|
 | 
						|
    - Test vectors for MD5 and SHA-1 are taken from RFC 2202.
 | 
						|
    - Test vectors for SHA-2 are taken from RFC 4231.
 | 
						|
    - Test vectors for SHA-3 are NIST's test vectors [1].
 | 
						|
 | 
						|
    [1] https://csrc.nist.gov/projects/message-authentication-codes
 | 
						|
    """
 | 
						|
 | 
						|
    def test_md5_rfc2202(self):
 | 
						|
        def md5test(key, msg, hexdigest):
 | 
						|
            self.assert_hmac(key, msg, hexdigest, self.md5, "md5", 16, 64)
 | 
						|
 | 
						|
        md5test(b"\x0b" * 16,
 | 
						|
                b"Hi There",
 | 
						|
                "9294727a3638bb1c13f48ef8158bfc9d")
 | 
						|
 | 
						|
        md5test(b"Jefe",
 | 
						|
                b"what do ya want for nothing?",
 | 
						|
                "750c783e6ab0b503eaa86e310a5db738")
 | 
						|
 | 
						|
        md5test(b"\xaa" * 16,
 | 
						|
                b"\xdd" * 50,
 | 
						|
                "56be34521d144c88dbb8c733f0e8b3f6")
 | 
						|
 | 
						|
        md5test(bytes(range(1, 26)),
 | 
						|
                b"\xcd" * 50,
 | 
						|
                "697eaf0aca3a3aea3a75164746ffaa79")
 | 
						|
 | 
						|
        md5test(b"\x0C" * 16,
 | 
						|
                b"Test With Truncation",
 | 
						|
                "56461ef2342edc00f9bab995690efd4c")
 | 
						|
 | 
						|
        md5test(b"\xaa" * 80,
 | 
						|
                b"Test Using Larger Than Block-Size Key - Hash Key First",
 | 
						|
                "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd")
 | 
						|
 | 
						|
        md5test(b"\xaa" * 80,
 | 
						|
                (b"Test Using Larger Than Block-Size Key "
 | 
						|
                 b"and Larger Than One Block-Size Data"),
 | 
						|
                "6f630fad67cda0ee1fb1f562db3aa53e")
 | 
						|
 | 
						|
    def test_sha1_rfc2202(self):
 | 
						|
        def shatest(key, msg, hexdigest):
 | 
						|
            self.assert_hmac(key, msg, hexdigest, self.sha1, "sha1", 20, 64)
 | 
						|
 | 
						|
        shatest(b"\x0b" * 20,
 | 
						|
                b"Hi There",
 | 
						|
                "b617318655057264e28bc0b6fb378c8ef146be00")
 | 
						|
 | 
						|
        shatest(b"Jefe",
 | 
						|
                b"what do ya want for nothing?",
 | 
						|
                "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")
 | 
						|
 | 
						|
        shatest(b"\xAA" * 20,
 | 
						|
                b"\xDD" * 50,
 | 
						|
                "125d7342b9ac11cd91a39af48aa17b4f63f175d3")
 | 
						|
 | 
						|
        shatest(bytes(range(1, 26)),
 | 
						|
                b"\xCD" * 50,
 | 
						|
                "4c9007f4026250c6bc8414f9bf50c86c2d7235da")
 | 
						|
 | 
						|
        shatest(b"\x0C" * 20,
 | 
						|
                b"Test With Truncation",
 | 
						|
                "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04")
 | 
						|
 | 
						|
        shatest(b"\xAA" * 80,
 | 
						|
                b"Test Using Larger Than Block-Size Key - Hash Key First",
 | 
						|
                "aa4ae5e15272d00e95705637ce8a3b55ed402112")
 | 
						|
 | 
						|
        shatest(b"\xAA" * 80,
 | 
						|
                (b"Test Using Larger Than Block-Size Key "
 | 
						|
                 b"and Larger Than One Block-Size Data"),
 | 
						|
                "e8e99d0f45237d786d6bbaa7965c7808bbff1a91")
 | 
						|
 | 
						|
    def test_sha2_224_rfc4231(self):
 | 
						|
        self._test_sha2_rfc4231(self.sha224, 'sha224', 28, 64)
 | 
						|
 | 
						|
    def test_sha2_256_rfc4231(self):
 | 
						|
        self._test_sha2_rfc4231(self.sha256, 'sha256', 32, 64)
 | 
						|
 | 
						|
    def test_sha2_384_rfc4231(self):
 | 
						|
        self._test_sha2_rfc4231(self.sha384, 'sha384', 48, 128)
 | 
						|
 | 
						|
    def test_sha2_512_rfc4231(self):
 | 
						|
        self._test_sha2_rfc4231(self.sha512, 'sha512', 64, 128)
 | 
						|
 | 
						|
    def _test_sha2_rfc4231(self, hashfunc, hashname, digest_size, block_size):
 | 
						|
        def hmactest(key, msg, hexdigests):
 | 
						|
            hexdigest = hexdigests[hashname]
 | 
						|
 | 
						|
            self.assert_hmac(
 | 
						|
                key, msg, hexdigest,
 | 
						|
                hashfunc=hashfunc,
 | 
						|
                hashname=hashname,
 | 
						|
                digest_size=digest_size,
 | 
						|
                block_size=block_size
 | 
						|
            )
 | 
						|
 | 
						|
        # 4.2.  Test Case 1
 | 
						|
        hmactest(key=b'\x0b' * 20,
 | 
						|
                 msg=b'Hi There',
 | 
						|
                 hexdigests={
 | 
						|
                     'sha224': '896fb1128abbdf196832107cd49df33f'
 | 
						|
                               '47b4b1169912ba4f53684b22',
 | 
						|
                     'sha256': 'b0344c61d8db38535ca8afceaf0bf12b'
 | 
						|
                               '881dc200c9833da726e9376c2e32cff7',
 | 
						|
                     'sha384': 'afd03944d84895626b0825f4ab46907f'
 | 
						|
                               '15f9dadbe4101ec682aa034c7cebc59c'
 | 
						|
                               'faea9ea9076ede7f4af152e8b2fa9cb6',
 | 
						|
                     'sha512': '87aa7cdea5ef619d4ff0b4241a1d6cb0'
 | 
						|
                               '2379f4e2ce4ec2787ad0b30545e17cde'
 | 
						|
                               'daa833b7d6b8a702038b274eaea3f4e4'
 | 
						|
                               'be9d914eeb61f1702e696c203a126854',
 | 
						|
                 })
 | 
						|
 | 
						|
        # 4.3.  Test Case 2
 | 
						|
        hmactest(key=b'Jefe',
 | 
						|
                 msg=b'what do ya want for nothing?',
 | 
						|
                 hexdigests={
 | 
						|
                     'sha224': 'a30e01098bc6dbbf45690f3a7e9e6d0f'
 | 
						|
                               '8bbea2a39e6148008fd05e44',
 | 
						|
                     'sha256': '5bdcc146bf60754e6a042426089575c7'
 | 
						|
                               '5a003f089d2739839dec58b964ec3843',
 | 
						|
                     'sha384': 'af45d2e376484031617f78d2b58a6b1b'
 | 
						|
                               '9c7ef464f5a01b47e42ec3736322445e'
 | 
						|
                               '8e2240ca5e69e2c78b3239ecfab21649',
 | 
						|
                     'sha512': '164b7a7bfcf819e2e395fbe73b56e0a3'
 | 
						|
                               '87bd64222e831fd610270cd7ea250554'
 | 
						|
                               '9758bf75c05a994a6d034f65f8f0e6fd'
 | 
						|
                               'caeab1a34d4a6b4b636e070a38bce737',
 | 
						|
                 })
 | 
						|
 | 
						|
        # 4.4.  Test Case 3
 | 
						|
        hmactest(key=b'\xaa' * 20,
 | 
						|
                 msg=b'\xdd' * 50,
 | 
						|
                 hexdigests={
 | 
						|
                     'sha224': '7fb3cb3588c6c1f6ffa9694d7d6ad264'
 | 
						|
                               '9365b0c1f65d69d1ec8333ea',
 | 
						|
                     'sha256': '773ea91e36800e46854db8ebd09181a7'
 | 
						|
                               '2959098b3ef8c122d9635514ced565fe',
 | 
						|
                     'sha384': '88062608d3e6ad8a0aa2ace014c8a86f'
 | 
						|
                               '0aa635d947ac9febe83ef4e55966144b'
 | 
						|
                               '2a5ab39dc13814b94e3ab6e101a34f27',
 | 
						|
                     'sha512': 'fa73b0089d56a284efb0f0756c890be9'
 | 
						|
                               'b1b5dbdd8ee81a3655f83e33b2279d39'
 | 
						|
                               'bf3e848279a722c806b485a47e67c807'
 | 
						|
                               'b946a337bee8942674278859e13292fb',
 | 
						|
                 })
 | 
						|
 | 
						|
        # 4.5.  Test Case 4
 | 
						|
        hmactest(key=bytes(x for x in range(0x01, 0x19 + 1)),
 | 
						|
                 msg=b'\xcd' * 50,
 | 
						|
                 hexdigests={
 | 
						|
                     'sha224': '6c11506874013cac6a2abc1bb382627c'
 | 
						|
                               'ec6a90d86efc012de7afec5a',
 | 
						|
                     'sha256': '82558a389a443c0ea4cc819899f2083a'
 | 
						|
                               '85f0faa3e578f8077a2e3ff46729665b',
 | 
						|
                     'sha384': '3e8a69b7783c25851933ab6290af6ca7'
 | 
						|
                               '7a9981480850009cc5577c6e1f573b4e'
 | 
						|
                               '6801dd23c4a7d679ccf8a386c674cffb',
 | 
						|
                     'sha512': 'b0ba465637458c6990e5a8c5f61d4af7'
 | 
						|
                               'e576d97ff94b872de76f8050361ee3db'
 | 
						|
                               'a91ca5c11aa25eb4d679275cc5788063'
 | 
						|
                               'a5f19741120c4f2de2adebeb10a298dd',
 | 
						|
                 })
 | 
						|
 | 
						|
        # 4.7.  Test Case 6
 | 
						|
        hmactest(key=b'\xaa' * 131,
 | 
						|
                 msg=b'Test Using Larger Than Block-Siz'
 | 
						|
                     b'e Key - Hash Key First',
 | 
						|
                 hexdigests={
 | 
						|
                     'sha224': '95e9a0db962095adaebe9b2d6f0dbce2'
 | 
						|
                               'd499f112f2d2b7273fa6870e',
 | 
						|
                     'sha256': '60e431591ee0b67f0d8a26aacbf5b77f'
 | 
						|
                               '8e0bc6213728c5140546040f0ee37f54',
 | 
						|
                     'sha384': '4ece084485813e9088d2c63a041bc5b4'
 | 
						|
                               '4f9ef1012a2b588f3cd11f05033ac4c6'
 | 
						|
                               '0c2ef6ab4030fe8296248df163f44952',
 | 
						|
                     'sha512': '80b24263c7c1a3ebb71493c1dd7be8b4'
 | 
						|
                               '9b46d1f41b4aeec1121b013783f8f352'
 | 
						|
                               '6b56d037e05f2598bd0fd2215d6a1e52'
 | 
						|
                               '95e64f73f63f0aec8b915a985d786598',
 | 
						|
                 })
 | 
						|
 | 
						|
        # 4.8.  Test Case 7
 | 
						|
        hmactest(key=b'\xaa' * 131,
 | 
						|
                 msg=b'This is a test using a larger th'
 | 
						|
                     b'an block-size key and a larger t'
 | 
						|
                     b'han block-size data. The key nee'
 | 
						|
                     b'ds to be hashed before being use'
 | 
						|
                     b'd by the HMAC algorithm.',
 | 
						|
                 hexdigests={
 | 
						|
                     'sha224': '3a854166ac5d9f023f54d517d0b39dbd'
 | 
						|
                               '946770db9c2b95c9f6f565d1',
 | 
						|
                     'sha256': '9b09ffa71b942fcb27635fbcd5b0e944'
 | 
						|
                               'bfdc63644f0713938a7f51535c3a35e2',
 | 
						|
                     'sha384': '6617178e941f020d351e2f254e8fd32c'
 | 
						|
                               '602420feb0b8fb9adccebb82461e99c5'
 | 
						|
                               'a678cc31e799176d3860e6110c46523e',
 | 
						|
                     'sha512': 'e37b6a775dc87dbaa4dfa9f96e5e3ffd'
 | 
						|
                               'debd71f8867289865df5a32d20cdc944'
 | 
						|
                               'b6022cac3c4982b10d5eeb55c3e4de15'
 | 
						|
                               '134676fb6de0446065c97440fa8c6a58',
 | 
						|
                 })
 | 
						|
 | 
						|
    def test_sha3_224_nist(self):
 | 
						|
        for key, msg, hexdigest in [
 | 
						|
            (
 | 
						|
                bytes(range(28)),
 | 
						|
                b'Sample message for keylen<blocklen',
 | 
						|
                '332cfd59347fdb8e576e77260be4aba2d6dc53117b3bfb52c6d18c04'
 | 
						|
            ), (
 | 
						|
                bytes(range(144)),
 | 
						|
                b'Sample message for keylen=blocklen',
 | 
						|
                'd8b733bcf66c644a12323d564e24dcf3fc75f231f3b67968359100c7'
 | 
						|
            ), (
 | 
						|
                bytes(range(172)),
 | 
						|
                b'Sample message for keylen>blocklen',
 | 
						|
                '078695eecc227c636ad31d063a15dd05a7e819a66ec6d8de1e193e59'
 | 
						|
            )
 | 
						|
        ]:
 | 
						|
            self.assert_hmac(
 | 
						|
                key, msg, hexdigest,
 | 
						|
                hashfunc=self.sha3_224, hashname='sha3_224',
 | 
						|
                digest_size=28, block_size=144
 | 
						|
            )
 | 
						|
 | 
						|
    def test_sha3_256_nist(self):
 | 
						|
        for key, msg, hexdigest in [
 | 
						|
            (
 | 
						|
                bytes(range(32)),
 | 
						|
                b'Sample message for keylen<blocklen',
 | 
						|
                '4fe8e202c4f058e8dddc23d8c34e4673'
 | 
						|
                '43e23555e24fc2f025d598f558f67205'
 | 
						|
            ), (
 | 
						|
                bytes(range(136)),
 | 
						|
                b'Sample message for keylen=blocklen',
 | 
						|
                '68b94e2e538a9be4103bebb5aa016d47'
 | 
						|
                '961d4d1aa906061313b557f8af2c3faa'
 | 
						|
            ), (
 | 
						|
                bytes(range(168)),
 | 
						|
                b'Sample message for keylen>blocklen',
 | 
						|
                '9bcf2c238e235c3ce88404e813bd2f3a'
 | 
						|
                '97185ac6f238c63d6229a00b07974258'
 | 
						|
            )
 | 
						|
        ]:
 | 
						|
            self.assert_hmac(
 | 
						|
                key, msg, hexdigest,
 | 
						|
                hashfunc=self.sha3_256, hashname='sha3_256',
 | 
						|
                digest_size=32, block_size=136
 | 
						|
            )
 | 
						|
 | 
						|
    def test_sha3_384_nist(self):
 | 
						|
        for key, msg, hexdigest in [
 | 
						|
            (
 | 
						|
                bytes(range(48)),
 | 
						|
                b'Sample message for keylen<blocklen',
 | 
						|
                'd588a3c51f3f2d906e8298c1199aa8ff'
 | 
						|
                '6296218127f6b38a90b6afe2c5617725'
 | 
						|
                'bc99987f79b22a557b6520db710b7f42'
 | 
						|
            ), (
 | 
						|
                bytes(range(104)),
 | 
						|
                b'Sample message for keylen=blocklen',
 | 
						|
                'a27d24b592e8c8cbf6d4ce6fc5bf62d8'
 | 
						|
                'fc98bf2d486640d9eb8099e24047837f'
 | 
						|
                '5f3bffbe92dcce90b4ed5b1e7e44fa90'
 | 
						|
            ), (
 | 
						|
                bytes(range(152)),
 | 
						|
                b'Sample message for keylen>blocklen',
 | 
						|
                'e5ae4c739f455279368ebf36d4f5354c'
 | 
						|
                '95aa184c899d3870e460ebc288ef1f94'
 | 
						|
                '70053f73f7c6da2a71bcaec38ce7d6ac'
 | 
						|
            )
 | 
						|
        ]:
 | 
						|
            self.assert_hmac(
 | 
						|
                key, msg, hexdigest,
 | 
						|
                hashfunc=self.sha3_384, hashname='sha3_384',
 | 
						|
                digest_size=48, block_size=104
 | 
						|
            )
 | 
						|
 | 
						|
    def test_sha3_512_nist(self):
 | 
						|
        for key, msg, hexdigest in [
 | 
						|
            (
 | 
						|
                bytes(range(64)),
 | 
						|
                b'Sample message for keylen<blocklen',
 | 
						|
                '4efd629d6c71bf86162658f29943b1c3'
 | 
						|
                '08ce27cdfa6db0d9c3ce81763f9cbce5'
 | 
						|
                'f7ebe9868031db1a8f8eb7b6b95e5c5e'
 | 
						|
                '3f657a8996c86a2f6527e307f0213196'
 | 
						|
            ), (
 | 
						|
                bytes(range(72)),
 | 
						|
                b'Sample message for keylen=blocklen',
 | 
						|
                '544e257ea2a3e5ea19a590e6a24b724c'
 | 
						|
                'e6327757723fe2751b75bf007d80f6b3'
 | 
						|
                '60744bf1b7a88ea585f9765b47911976'
 | 
						|
                'd3191cf83c039f5ffab0d29cc9d9b6da'
 | 
						|
            ), (
 | 
						|
                bytes(range(136)),
 | 
						|
                b'Sample message for keylen>blocklen',
 | 
						|
                '5f464f5e5b7848e3885e49b2c385f069'
 | 
						|
                '4985d0e38966242dc4a5fe3fea4b37d4'
 | 
						|
                '6b65ceced5dcf59438dd840bab22269f'
 | 
						|
                '0ba7febdb9fcf74602a35666b2a32915'
 | 
						|
            )
 | 
						|
        ]:
 | 
						|
            self.assert_hmac(
 | 
						|
                key, msg, hexdigest,
 | 
						|
                hashfunc=self.sha3_512, hashname='sha3_512',
 | 
						|
                digest_size=64, block_size=72
 | 
						|
            )
 | 
						|
 | 
						|
 | 
						|
class PurePythonInitHMAC(PyModuleMixin, HashFunctionsTrait):
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        super().setUpClass()
 | 
						|
        for meth in ['_init_openssl_hmac', '_init_builtin_hmac']:
 | 
						|
            fn = getattr(cls.hmac.HMAC, meth)
 | 
						|
            cm = mock.patch.object(cls.hmac.HMAC, meth, autospec=True, wraps=fn)
 | 
						|
            cls.enterClassContext(cm)
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def tearDownClass(cls):
 | 
						|
        cls.hmac.HMAC._init_openssl_hmac.assert_not_called()
 | 
						|
        cls.hmac.HMAC._init_builtin_hmac.assert_not_called()
 | 
						|
        # Do not assert that HMAC._init_old() has been called as it's tricky
 | 
						|
        # to determine whether a test for a specific hash function has been
 | 
						|
        # executed or not. On regular builds, it will be called but if a
 | 
						|
        # hash function is not available, it's hard to detect for which
 | 
						|
        # test we should checj HMAC._init_old() or not.
 | 
						|
        super().tearDownClass()
 | 
						|
 | 
						|
 | 
						|
class PyRFCOpenSSLTestCase(ThroughObjectMixin,
 | 
						|
                           PyAssertersMixin,
 | 
						|
                           OpenSSLHashFunctionsTrait,
 | 
						|
                           RFCTestCaseMixin,
 | 
						|
                           PurePythonInitHMAC,
 | 
						|
                           unittest.TestCase):
 | 
						|
    """Python implementation of HMAC using hmac.HMAC().
 | 
						|
 | 
						|
    The underlying hash functions are OpenSSL-based but
 | 
						|
    _init_old() is used instead of _init_openssl_hmac().
 | 
						|
    """
 | 
						|
 | 
						|
 | 
						|
class PyRFCBuiltinTestCase(ThroughObjectMixin,
 | 
						|
                           PyAssertersMixin,
 | 
						|
                           BuiltinHashFunctionsTrait,
 | 
						|
                           RFCTestCaseMixin,
 | 
						|
                           PurePythonInitHMAC,
 | 
						|
                           unittest.TestCase):
 | 
						|
    """Python implementation of HMAC using hmac.HMAC().
 | 
						|
 | 
						|
    The underlying hash functions are HACL*-based but
 | 
						|
    _init_old() is used instead of _init_builtin_hmac().
 | 
						|
    """
 | 
						|
 | 
						|
 | 
						|
class PyDotNewOpenSSLRFCTestCase(ThroughModuleAPIMixin,
 | 
						|
                                 PyAssertersMixin,
 | 
						|
                                 OpenSSLHashFunctionsTrait,
 | 
						|
                                 RFCTestCaseMixin,
 | 
						|
                                 PurePythonInitHMAC,
 | 
						|
                                 unittest.TestCase):
 | 
						|
    """Python implementation of HMAC using hmac.new().
 | 
						|
 | 
						|
    The underlying hash functions are OpenSSL-based but
 | 
						|
    _init_old() is used instead of _init_openssl_hmac().
 | 
						|
    """
 | 
						|
 | 
						|
 | 
						|
class PyDotNewBuiltinRFCTestCase(ThroughModuleAPIMixin,
 | 
						|
                                 PyAssertersMixin,
 | 
						|
                                 BuiltinHashFunctionsTrait,
 | 
						|
                                 RFCTestCaseMixin,
 | 
						|
                                 PurePythonInitHMAC,
 | 
						|
                                 unittest.TestCase):
 | 
						|
    """Python implementation of HMAC using hmac.new().
 | 
						|
 | 
						|
    The underlying hash functions are HACL-based but
 | 
						|
    _init_old() is used instead of _init_openssl_hmac().
 | 
						|
    """
 | 
						|
 | 
						|
 | 
						|
class OpenSSLRFCTestCase(OpenSSLAssertersMixin,
 | 
						|
                         OpenSSLHashFunctionsTrait,
 | 
						|
                         RFCTestCaseMixin,
 | 
						|
                         unittest.TestCase):
 | 
						|
    """OpenSSL implementation of HMAC.
 | 
						|
 | 
						|
    The underlying hash functions are also OpenSSL-based.
 | 
						|
    """
 | 
						|
 | 
						|
 | 
						|
class BuiltinRFCTestCase(BuiltinAssertersMixin,
 | 
						|
                         NamedHashFunctionsTrait,
 | 
						|
                         RFCTestCaseMixin,
 | 
						|
                         unittest.TestCase):
 | 
						|
    """Built-in HACL* implementation of HMAC.
 | 
						|
 | 
						|
    The underlying hash functions are also HACL*-based.
 | 
						|
    """
 | 
						|
 | 
						|
    def assert_hmac_extra_cases(
 | 
						|
        self, key, msg, hexdigest, digestmod, hashname, digest_size, block_size
 | 
						|
    ):
 | 
						|
        # assert one-shot HMAC at the same time
 | 
						|
        with self.subTest(key=key, msg=msg, hashname=hashname):
 | 
						|
            func = getattr(self.hmac, f'compute_{hashname}')
 | 
						|
            self.assertTrue(callable(func))
 | 
						|
            self.check_hmac_hexdigest(key, msg, hexdigest, digest_size, func)
 | 
						|
 | 
						|
 | 
						|
class DigestModTestCaseMixin(CreatorMixin, DigestMixin):
 | 
						|
    """Tests for the 'digestmod' parameter for hmac_new() and hmac_digest()."""
 | 
						|
 | 
						|
    def assert_raises_missing_digestmod(self):
 | 
						|
        """A context manager catching errors when a digestmod is missing."""
 | 
						|
        return self.assertRaisesRegex(TypeError,
 | 
						|
                                      "[M|m]issing.*required.*digestmod")
 | 
						|
 | 
						|
    def assert_raises_unknown_digestmod(self):
 | 
						|
        """A context manager catching errors when a digestmod is unknown."""
 | 
						|
        return self.assertRaisesRegex(ValueError, "[Uu]nsupported.*")
 | 
						|
 | 
						|
    def test_constructor_missing_digestmod(self):
 | 
						|
        catcher = self.assert_raises_missing_digestmod
 | 
						|
        self.do_test_constructor_missing_digestmod(catcher)
 | 
						|
 | 
						|
    def test_constructor_unknown_digestmod(self):
 | 
						|
        catcher = self.assert_raises_unknown_digestmod
 | 
						|
        self.do_test_constructor_unknown_digestmod(catcher)
 | 
						|
 | 
						|
    def do_test_constructor_missing_digestmod(self, catcher):
 | 
						|
        for func, args, kwds in self.cases_missing_digestmod_in_constructor():
 | 
						|
            with self.subTest(args=args, kwds=kwds), catcher():
 | 
						|
                func(*args, **kwds)
 | 
						|
 | 
						|
    def do_test_constructor_unknown_digestmod(self, catcher):
 | 
						|
        for func, args, kwds in self.cases_unknown_digestmod_in_constructor():
 | 
						|
            with self.subTest(args=args, kwds=kwds), catcher():
 | 
						|
                func(*args, **kwds)
 | 
						|
 | 
						|
    def cases_missing_digestmod_in_constructor(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def make_missing_digestmod_cases(self, func, missing_like=()):
 | 
						|
        """Generate cases for missing digestmod tests.
 | 
						|
 | 
						|
        Only the Python implementation should consider "falsey" 'digestmod'
 | 
						|
        values as being equivalent to a missing one.
 | 
						|
        """
 | 
						|
        key, msg = b'unused key', b'unused msg'
 | 
						|
        choices = [DIGESTMOD_SENTINEL, *missing_like]
 | 
						|
        return self._invalid_digestmod_cases(func, key, msg, choices)
 | 
						|
 | 
						|
    def cases_unknown_digestmod_in_constructor(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def make_unknown_digestmod_cases(self, func, bad_digestmods):
 | 
						|
        """Generate cases for unknown digestmod tests."""
 | 
						|
        key, msg = b'unused key', b'unused msg'
 | 
						|
        return self._invalid_digestmod_cases(func, key, msg, bad_digestmods)
 | 
						|
 | 
						|
    def _invalid_digestmod_cases(self, func, key, msg, choices):
 | 
						|
        cases = []
 | 
						|
        for digestmod in choices:
 | 
						|
            kwargs = {'digestmod': digestmod}
 | 
						|
            cases.append((func, (key,), kwargs))
 | 
						|
            cases.append((func, (key, msg), kwargs))
 | 
						|
            cases.append((func, (key,), kwargs | {'msg': msg}))
 | 
						|
        return cases
 | 
						|
 | 
						|
 | 
						|
class ConstructorTestCaseMixin(CreatorMixin, DigestMixin, ObjectCheckerMixin):
 | 
						|
    """HMAC constructor tests based on HMAC-SHA-2/256."""
 | 
						|
 | 
						|
    key = b"key"
 | 
						|
    msg = b"hash this!"
 | 
						|
    res = "6c845b47f52b3b47f6590c502db7825aad757bf4fadc8fa972f7cd2e76a5bdeb"
 | 
						|
 | 
						|
    def do_test_constructor(self, hmac_on_key_and_msg):
 | 
						|
        self.do_test_constructor_invalid_types(hmac_on_key_and_msg)
 | 
						|
        self.do_test_constructor_supported_types(hmac_on_key_and_msg)
 | 
						|
 | 
						|
    def do_test_constructor_invalid_types(self, hmac_on_key_and_msg):
 | 
						|
        self.assertRaises(TypeError, hmac_on_key_and_msg, 1)
 | 
						|
        self.assertRaises(TypeError, hmac_on_key_and_msg, "key")
 | 
						|
 | 
						|
        self.assertRaises(TypeError, hmac_on_key_and_msg, b"key", 1)
 | 
						|
        self.assertRaises(TypeError, hmac_on_key_and_msg, b"key", "msg")
 | 
						|
 | 
						|
    def do_test_constructor_supported_types(self, hmac_on_key_and_msg):
 | 
						|
        for tp_key in [bytes, bytearray]:
 | 
						|
            for tp_msg in [bytes, bytearray, memoryview]:
 | 
						|
                with self.subTest(tp_key=tp_key, tp_msg=tp_msg):
 | 
						|
                    h = hmac_on_key_and_msg(tp_key(self.key), tp_msg(self.msg))
 | 
						|
                    self.assertEqual(h.name, "hmac-sha256")
 | 
						|
                    self.assertEqual(h.hexdigest(), self.res)
 | 
						|
 | 
						|
    @hashlib_helper.requires_hashdigest("sha256")
 | 
						|
    def test_constructor(self):
 | 
						|
        self.do_test_constructor(self.bind_hmac_new("sha256"))
 | 
						|
 | 
						|
    @hashlib_helper.requires_hashdigest("sha256")
 | 
						|
    def test_digest(self):
 | 
						|
        digest = self.hmac_digest(self.key, self.msg, "sha256")
 | 
						|
        self.assertEqual(digest, binascii.unhexlify(self.res))
 | 
						|
 | 
						|
 | 
						|
class PyConstructorBaseMixin(PyModuleMixin,
 | 
						|
                             DigestModTestCaseMixin,
 | 
						|
                             ConstructorTestCaseMixin):
 | 
						|
 | 
						|
    def cases_missing_digestmod_in_constructor(self):
 | 
						|
        func, choices = self.hmac_new, ['', None, False]
 | 
						|
        return self.make_missing_digestmod_cases(func, choices)
 | 
						|
 | 
						|
    def cases_unknown_digestmod_in_constructor(self):
 | 
						|
        func, choices = self.hmac_new, ['unknown']
 | 
						|
        return self.make_unknown_digestmod_cases(func, choices)
 | 
						|
 | 
						|
    @requires_builtin_sha2()
 | 
						|
    def test_constructor_with_module(self):
 | 
						|
        self.do_test_constructor(self.bind_hmac_new(sha2.sha256))
 | 
						|
 | 
						|
    @requires_builtin_sha2()
 | 
						|
    def test_digest_with_module(self):
 | 
						|
        digest = self.hmac_digest(self.key, self.msg, sha2.sha256)
 | 
						|
        self.assertEqual(digest, binascii.unhexlify(self.res))
 | 
						|
 | 
						|
 | 
						|
class PyConstructorTestCase(ThroughObjectMixin, PyConstructorBaseMixin,
 | 
						|
                            unittest.TestCase):
 | 
						|
    """Test the hmac.HMAC() pure Python constructor."""
 | 
						|
 | 
						|
 | 
						|
class PyModuleConstructorTestCase(ThroughModuleAPIMixin, PyConstructorBaseMixin,
 | 
						|
                                  unittest.TestCase):
 | 
						|
    """Test the hmac.new() and hmac.digest() functions."""
 | 
						|
 | 
						|
    def test_hmac_digest_digestmod_parameter(self):
 | 
						|
        func = self.hmac_digest
 | 
						|
 | 
						|
        def raiser():
 | 
						|
            raise RuntimeError("custom exception")
 | 
						|
 | 
						|
        with self.assertRaisesRegex(RuntimeError, "custom exception"):
 | 
						|
            func(b'key', b'msg', raiser)
 | 
						|
 | 
						|
        with self.assertRaisesRegex(ValueError, 'hash type'):
 | 
						|
            func(b'key', b'msg', 'unknown')
 | 
						|
 | 
						|
        with self.assertRaisesRegex(AttributeError, 'new'):
 | 
						|
            func(b'key', b'msg', 1234)
 | 
						|
        with self.assertRaisesRegex(AttributeError, 'new'):
 | 
						|
            func(b'key', b'msg', None)
 | 
						|
 | 
						|
 | 
						|
class ExtensionConstructorTestCaseMixin(DigestModTestCaseMixin,
 | 
						|
                                        ConstructorTestCaseMixin):
 | 
						|
 | 
						|
    @property
 | 
						|
    def obj_type(self):
 | 
						|
        """The underlying (non-instantiable) C class."""
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    @property
 | 
						|
    def exc_type(self):
 | 
						|
        """The exact exception class raised upon invalid 'digestmod' values."""
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def test_internal_types(self):
 | 
						|
        # internal C types are immutable and cannot be instantiated
 | 
						|
        check_disallow_instantiation(self, self.obj_type)
 | 
						|
        with self.assertRaisesRegex(TypeError, "immutable type"):
 | 
						|
            self.obj_type.value = None
 | 
						|
 | 
						|
    def assert_raises_unknown_digestmod(self):
 | 
						|
        self.assertIsSubclass(self.exc_type, ValueError)
 | 
						|
        return self.assertRaises(self.exc_type)
 | 
						|
 | 
						|
    def cases_missing_digestmod_in_constructor(self):
 | 
						|
        return self.make_missing_digestmod_cases(self.hmac_new)
 | 
						|
 | 
						|
    def cases_unknown_digestmod_in_constructor(self):
 | 
						|
        func, choices = self.hmac_new, ['unknown', 1234]
 | 
						|
        return self.make_unknown_digestmod_cases(func, choices)
 | 
						|
 | 
						|
 | 
						|
class OpenSSLConstructorTestCase(ThroughOpenSSLAPIMixin,
 | 
						|
                                 ExtensionConstructorTestCaseMixin,
 | 
						|
                                 unittest.TestCase):
 | 
						|
 | 
						|
    @property
 | 
						|
    def obj_type(self):
 | 
						|
        return _hashlib.HMAC
 | 
						|
 | 
						|
    @property
 | 
						|
    def exc_type(self):
 | 
						|
        return _hashlib.UnsupportedDigestmodError
 | 
						|
 | 
						|
    def test_hmac_digest_digestmod_parameter(self):
 | 
						|
        for value in [object, 'unknown', 1234, None]:
 | 
						|
            with (
 | 
						|
                self.subTest(value=value),
 | 
						|
                self.assert_raises_unknown_digestmod(),
 | 
						|
            ):
 | 
						|
                self.hmac_digest(b'key', b'msg', value)
 | 
						|
 | 
						|
 | 
						|
class BuiltinConstructorTestCase(ThroughBuiltinAPIMixin,
 | 
						|
                                 ExtensionConstructorTestCaseMixin,
 | 
						|
                                 unittest.TestCase):
 | 
						|
 | 
						|
    @property
 | 
						|
    def obj_type(self):
 | 
						|
        return self.hmac.HMAC
 | 
						|
 | 
						|
    @property
 | 
						|
    def exc_type(self):
 | 
						|
        return self.hmac.UnknownHashError
 | 
						|
 | 
						|
    def test_hmac_digest_digestmod_parameter(self):
 | 
						|
        for value in [object, 'unknown', 1234, None]:
 | 
						|
            with (
 | 
						|
                self.subTest(value=value),
 | 
						|
                self.assert_raises_unknown_digestmod(),
 | 
						|
            ):
 | 
						|
                self.hmac_digest(b'key', b'msg', value)
 | 
						|
 | 
						|
 | 
						|
class SanityTestCaseMixin(CreatorMixin):
 | 
						|
    """Sanity checks for HMAC objects and their object interface.
 | 
						|
 | 
						|
    The tests here use a common digestname and do not check all supported
 | 
						|
    hash functions.
 | 
						|
    """
 | 
						|
 | 
						|
    # The underlying HMAC class to test. May be in C or in Python.
 | 
						|
    hmac_class: type
 | 
						|
    # The underlying hash function name (should be accepted by the HMAC class).
 | 
						|
    digestname: str
 | 
						|
    # The expected digest and block sizes (must be hardcoded).
 | 
						|
    digest_size: int
 | 
						|
    block_size: int
 | 
						|
 | 
						|
    def test_methods(self):
 | 
						|
        h = self.hmac_new(b"my secret key", digestmod=self.digestname)
 | 
						|
        self.assertIsInstance(h, self.hmac_class)
 | 
						|
        self.assertIsNone(h.update(b"compute the hash of this text!"))
 | 
						|
        self.assertIsInstance(h.digest(), bytes)
 | 
						|
        self.assertIsInstance(h.hexdigest(), str)
 | 
						|
        self.assertIsInstance(h.copy(), self.hmac_class)
 | 
						|
 | 
						|
    def test_properties(self):
 | 
						|
        h = self.hmac_new(b"my secret key", digestmod=self.digestname)
 | 
						|
        self.assertEqual(h.name, f"hmac-{self.digestname}")
 | 
						|
        self.assertEqual(h.digest_size, self.digest_size)
 | 
						|
        self.assertEqual(h.block_size, self.block_size)
 | 
						|
 | 
						|
    def test_repr(self):
 | 
						|
        # HMAC object representation may differ across implementations
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_hashdigest('sha256')
 | 
						|
class PySanityTestCase(ThroughObjectMixin, PyModuleMixin, SanityTestCaseMixin,
 | 
						|
                       unittest.TestCase):
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        super().setUpClass()
 | 
						|
        cls.hmac_class = cls.hmac.HMAC
 | 
						|
        cls.digestname = 'sha256'
 | 
						|
        cls.digest_size = 32
 | 
						|
        cls.block_size = 64
 | 
						|
 | 
						|
    def test_repr(self):
 | 
						|
        h = self.hmac_new(b"my secret key", digestmod=self.digestname)
 | 
						|
        self.assertStartsWith(repr(h), "<hmac.HMAC object at")
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_openssl_hashdigest('sha256')
 | 
						|
class OpenSSLSanityTestCase(ThroughOpenSSLAPIMixin, SanityTestCaseMixin,
 | 
						|
                            unittest.TestCase):
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        super().setUpClass()
 | 
						|
        cls.hmac_class = _hashlib.HMAC
 | 
						|
        cls.digestname = 'sha256'
 | 
						|
        cls.digest_size = 32
 | 
						|
        cls.block_size = 64
 | 
						|
 | 
						|
    def test_repr(self):
 | 
						|
        h = self.hmac_new(b"my secret key", digestmod=self.digestname)
 | 
						|
        self.assertStartsWith(repr(h), f"<{self.digestname} HMAC object @")
 | 
						|
 | 
						|
 | 
						|
class BuiltinSanityTestCase(ThroughBuiltinAPIMixin, SanityTestCaseMixin,
 | 
						|
                            unittest.TestCase):
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        super().setUpClass()
 | 
						|
        cls.hmac_class = cls.hmac.HMAC
 | 
						|
        cls.digestname = 'sha256'
 | 
						|
        cls.digest_size = 32
 | 
						|
        cls.block_size = 64
 | 
						|
 | 
						|
    def test_repr(self):
 | 
						|
        h = self.hmac_new(b"my secret key", digestmod=self.digestname)
 | 
						|
        self.assertStartsWith(repr(h), f"<{self.digestname} HMAC object @")
 | 
						|
 | 
						|
 | 
						|
class UpdateTestCaseMixin:
 | 
						|
    """Tests for the update() method (streaming HMAC)."""
 | 
						|
 | 
						|
    def HMAC(self, key, msg=None):
 | 
						|
        """Create a HMAC object."""
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    @property
 | 
						|
    def gil_minsize(self):
 | 
						|
        """Get the maximal input length for the GIL to be held."""
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def check_update(self, key, chunks):
 | 
						|
        chunks = list(chunks)
 | 
						|
        msg = b''.join(chunks)
 | 
						|
        h1 = self.HMAC(key, msg)
 | 
						|
 | 
						|
        h2 = self.HMAC(key)
 | 
						|
        for chunk in chunks:
 | 
						|
            h2.update(chunk)
 | 
						|
 | 
						|
        self.assertEqual(h1.digest(), h2.digest())
 | 
						|
        self.assertEqual(h1.hexdigest(), h2.hexdigest())
 | 
						|
 | 
						|
    def test_update(self):
 | 
						|
        key, msg = random.randbytes(16), random.randbytes(16)
 | 
						|
        with self.subTest(key=key, msg=msg):
 | 
						|
            self.check_update(key, [msg])
 | 
						|
 | 
						|
    def test_update_large(self):
 | 
						|
        gil_minsize = self.gil_minsize
 | 
						|
        key = random.randbytes(16)
 | 
						|
        top = random.randbytes(gil_minsize + 1)
 | 
						|
        bot = random.randbytes(gil_minsize + 1)
 | 
						|
        self.check_update(key, [top, bot])
 | 
						|
 | 
						|
    def test_update_exceptions(self):
 | 
						|
        h = self.HMAC(b"key")
 | 
						|
        for msg in ['invalid msg', 123, (), []]:
 | 
						|
            with self.subTest(msg=msg):
 | 
						|
                self.assertRaises(TypeError, h.update, msg)
 | 
						|
 | 
						|
 | 
						|
@requires_builtin_sha2()
 | 
						|
class PyUpdateTestCase(PyModuleMixin, UpdateTestCaseMixin, unittest.TestCase):
 | 
						|
 | 
						|
    def HMAC(self, key, msg=None):
 | 
						|
        return self.hmac.HMAC(key, msg, digestmod='sha256')
 | 
						|
 | 
						|
    @property
 | 
						|
    def gil_minsize(self):
 | 
						|
        return sha2._GIL_MINSIZE
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_openssl_hashdigest('sha256')
 | 
						|
class OpenSSLUpdateTestCase(UpdateTestCaseMixin, unittest.TestCase):
 | 
						|
 | 
						|
    def HMAC(self, key, msg=None):
 | 
						|
        return _hashlib.hmac_new(key, msg, digestmod='sha256')
 | 
						|
 | 
						|
    @property
 | 
						|
    def gil_minsize(self):
 | 
						|
        return _hashlib._GIL_MINSIZE
 | 
						|
 | 
						|
 | 
						|
class BuiltinUpdateTestCase(BuiltinModuleMixin,
 | 
						|
                            UpdateTestCaseMixin, unittest.TestCase):
 | 
						|
 | 
						|
    def HMAC(self, key, msg=None):
 | 
						|
        # Even if Python does not build '_sha2', the HACL* sources
 | 
						|
        # are still built, making it possible to use SHA-2 hashes.
 | 
						|
        return self.hmac.new(key, msg, digestmod='sha256')
 | 
						|
 | 
						|
    @property
 | 
						|
    def gil_minsize(self):
 | 
						|
        return self.hmac._GIL_MINSIZE
 | 
						|
 | 
						|
 | 
						|
class CopyBaseTestCase:
 | 
						|
 | 
						|
    def test_attributes(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def test_realcopy(self):
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_hashdigest('sha256')
 | 
						|
class PythonCopyTestCase(CopyBaseTestCase, unittest.TestCase):
 | 
						|
 | 
						|
    def test_attributes(self):
 | 
						|
        # Testing if attributes are of same type.
 | 
						|
        h1 = hmac.HMAC.__new__(hmac.HMAC)
 | 
						|
        h1._init_old(b"key", b"msg", digestmod="sha256")
 | 
						|
        self.assertIsNone(h1._hmac)
 | 
						|
        self.assertIsNotNone(h1._inner)
 | 
						|
        self.assertIsNotNone(h1._outer)
 | 
						|
 | 
						|
        h2 = h1.copy()
 | 
						|
        self.assertIsNone(h2._hmac)
 | 
						|
        self.assertIsNotNone(h2._inner)
 | 
						|
        self.assertIsNotNone(h2._outer)
 | 
						|
        self.assertEqual(type(h1._inner), type(h2._inner))
 | 
						|
        self.assertEqual(type(h1._outer), type(h2._outer))
 | 
						|
 | 
						|
    def test_realcopy(self):
 | 
						|
        # Testing if the copy method created a real copy.
 | 
						|
        h1 = hmac.HMAC.__new__(hmac.HMAC)
 | 
						|
        h1._init_old(b"key", b"msg", digestmod="sha256")
 | 
						|
        h2 = h1.copy()
 | 
						|
        # Using id() in case somebody has overridden __eq__/__ne__.
 | 
						|
        self.assertNotEqual(id(h1), id(h2))
 | 
						|
        self.assertNotEqual(id(h1._inner), id(h2._inner))
 | 
						|
        self.assertNotEqual(id(h1._outer), id(h2._outer))
 | 
						|
 | 
						|
    def test_equality(self):
 | 
						|
        # Testing if the copy has the same digests.
 | 
						|
        h1 = hmac.HMAC(b"key", digestmod="sha256")
 | 
						|
        h1.update(b"some random text")
 | 
						|
        h2 = h1.copy()
 | 
						|
        self.assertEqual(h1.digest(), h2.digest())
 | 
						|
        self.assertEqual(h1.hexdigest(), h2.hexdigest())
 | 
						|
 | 
						|
    def test_equality_new(self):
 | 
						|
        # Testing if the copy has the same digests with hmac.new().
 | 
						|
        h1 = hmac.new(b"key", digestmod="sha256")
 | 
						|
        h1.update(b"some random text")
 | 
						|
        h2 = h1.copy()
 | 
						|
        # Using id() in case somebody has overridden __eq__/__ne__.
 | 
						|
        self.assertNotEqual(id(h1), id(h2))
 | 
						|
        self.assertEqual(h1.digest(), h2.digest())
 | 
						|
        self.assertEqual(h1.hexdigest(), h2.hexdigest())
 | 
						|
 | 
						|
 | 
						|
class ExtensionCopyTestCase(CopyBaseTestCase):
 | 
						|
 | 
						|
    def init(self, h):
 | 
						|
        """Call the dedicate init() method to test."""
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def test_attributes(self):
 | 
						|
        # Testing if attributes are of same type.
 | 
						|
        h1 = hmac.HMAC.__new__(hmac.HMAC)
 | 
						|
 | 
						|
        self.init(h1)
 | 
						|
        self.assertIsNotNone(h1._hmac)
 | 
						|
        self.assertIsNone(h1._inner)
 | 
						|
        self.assertIsNone(h1._outer)
 | 
						|
 | 
						|
        h2 = h1.copy()
 | 
						|
        self.assertIsNotNone(h2._hmac)
 | 
						|
        self.assertIsNone(h2._inner)
 | 
						|
        self.assertIsNone(h2._outer)
 | 
						|
 | 
						|
    def test_realcopy(self):
 | 
						|
        h1 = hmac.HMAC.__new__(hmac.HMAC)
 | 
						|
        self.init(h1)
 | 
						|
        h2 = h1.copy()
 | 
						|
        # Using id() in case somebody has overridden __eq__/__ne__.
 | 
						|
        self.assertNotEqual(id(h1._hmac), id(h2._hmac))
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_openssl_hashdigest('sha256')
 | 
						|
class OpenSSLCopyTestCase(ExtensionCopyTestCase, unittest.TestCase):
 | 
						|
 | 
						|
    def init(self, h):
 | 
						|
        h._init_openssl_hmac(b"key", b"msg", digestmod="sha256")
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_builtin_hmac()
 | 
						|
class BuiltinCopyTestCase(ExtensionCopyTestCase, unittest.TestCase):
 | 
						|
 | 
						|
    def init(self, h):
 | 
						|
        # Even if Python does not build '_sha2', the HACL* sources
 | 
						|
        # are still built, making it possible to use SHA-2 hashes.
 | 
						|
        h._init_builtin_hmac(b"key", b"msg", digestmod="sha256")
 | 
						|
 | 
						|
 | 
						|
class CompareDigestMixin:
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def compare_digest(a, b):
 | 
						|
        """Implementation of 'a == b' to test."""
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    def assert_digest_equal(self, a, b):
 | 
						|
        with self.subTest(a=a, b=b):
 | 
						|
            self.assertTrue(self.compare_digest(a, b))
 | 
						|
        with self.subTest(a=b, b=a):
 | 
						|
            self.assertTrue(self.compare_digest(b, a))
 | 
						|
 | 
						|
    def assert_digest_not_equal(self, a, b):
 | 
						|
        with self.subTest(a=a, b=b):
 | 
						|
            self.assertFalse(self.compare_digest(a, b))
 | 
						|
        with self.subTest(a=b, b=a):
 | 
						|
            self.assertFalse(self.compare_digest(b, a))
 | 
						|
 | 
						|
    def test_exceptions(self):
 | 
						|
        for a, b in [
 | 
						|
            # Testing input type exception handling
 | 
						|
            (100, 200), (100, b"foobar"), ("foobar", b"foobar"),
 | 
						|
            # non-ASCII strings
 | 
						|
            ("fooä", "fooä")
 | 
						|
        ]:
 | 
						|
            self.assertRaises(TypeError, self.compare_digest, a, b)
 | 
						|
            self.assertRaises(TypeError, self.compare_digest, b, a)
 | 
						|
 | 
						|
    def test_bytes(self):
 | 
						|
        # Testing bytes of different lengths
 | 
						|
        a, b = b"foobar", b"foo"
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
        a, b = b"\xde\xad\xbe\xef", b"\xde\xad"
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
        # Testing bytes of same lengths, different values
 | 
						|
        a, b = b"foobar", b"foobaz"
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
        a, b = b"\xde\xad\xbe\xef", b"\xab\xad\x1d\xea"
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
        # Testing bytes of same lengths, same values
 | 
						|
        a, b = b"foobar", b"foobar"
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
        a, b = b"\xde\xad\xbe\xef", b"\xde\xad\xbe\xef"
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
 | 
						|
    def test_bytearray(self):
 | 
						|
        # Testing bytearrays of same lengths, same values
 | 
						|
        a, b = bytearray(b"foobar"), bytearray(b"foobar")
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
 | 
						|
        # Testing bytearrays of different lengths
 | 
						|
        a, b = bytearray(b"foobar"), bytearray(b"foo")
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
        # Testing bytearrays of same lengths, different values
 | 
						|
        a, b = bytearray(b"foobar"), bytearray(b"foobaz")
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
    def test_mixed_types(self):
 | 
						|
        # Testing byte and bytearray of same lengths, same values
 | 
						|
        a, b = bytearray(b"foobar"), b"foobar"
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
 | 
						|
        # Testing byte bytearray of different lengths
 | 
						|
        a, b = bytearray(b"foobar"), b"foo"
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
        # Testing byte and bytearray of same lengths, different values
 | 
						|
        a, b = bytearray(b"foobar"), b"foobaz"
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
    def test_string(self):
 | 
						|
        # Testing str of same lengths
 | 
						|
        a, b = "foobar", "foobar"
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
 | 
						|
        # Testing str of different lengths
 | 
						|
        a, b = "foo", "foobar"
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
        # Testing str of same lengths, different values
 | 
						|
        a, b = "foobar", "foobaz"
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
    def test_string_subclass(self):
 | 
						|
        class S(str):
 | 
						|
            def __eq__(self, other):
 | 
						|
                raise ValueError("should not be called")
 | 
						|
 | 
						|
        a, b = S("foobar"), S("foobar")
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
        a, b = S("foobar"), "foobar"
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
        a, b = S("foobar"), S("foobaz")
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
    def test_bytes_subclass(self):
 | 
						|
        class B(bytes):
 | 
						|
            def __eq__(self, other):
 | 
						|
                raise ValueError("should not be called")
 | 
						|
 | 
						|
        a, b = B(b"foobar"), B(b"foobar")
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
        a, b = B(b"foobar"), b"foobar"
 | 
						|
        self.assert_digest_equal(a, b)
 | 
						|
        a, b = B(b"foobar"), B(b"foobaz")
 | 
						|
        self.assert_digest_not_equal(a, b)
 | 
						|
 | 
						|
 | 
						|
class HMACCompareDigestTestCase(CompareDigestMixin, unittest.TestCase):
 | 
						|
    compare_digest = hmac.compare_digest
 | 
						|
 | 
						|
    def test_compare_digest_func(self):
 | 
						|
        if openssl_compare_digest is not None:
 | 
						|
            self.assertIs(self.compare_digest, openssl_compare_digest)
 | 
						|
        else:
 | 
						|
            self.assertIs(self.compare_digest, operator_compare_digest)
 | 
						|
 | 
						|
 | 
						|
@hashlib_helper.requires_hashlib()
 | 
						|
class OpenSSLCompareDigestTestCase(CompareDigestMixin, unittest.TestCase):
 | 
						|
    compare_digest = openssl_compare_digest
 | 
						|
 | 
						|
 | 
						|
class OperatorCompareDigestTestCase(CompareDigestMixin, unittest.TestCase):
 | 
						|
    compare_digest = operator_compare_digest
 | 
						|
 | 
						|
 | 
						|
class PyMiscellaneousTests(unittest.TestCase):
 | 
						|
    """Miscellaneous tests for the pure Python HMAC module."""
 | 
						|
 | 
						|
    @hashlib_helper.requires_builtin_hmac()
 | 
						|
    def test_hmac_constructor_uses_builtin(self):
 | 
						|
        # Block the OpenSSL implementation and check that
 | 
						|
        # HMAC() uses the built-in implementation instead.
 | 
						|
        hmac = import_fresh_module("hmac", blocked=["_hashlib"])
 | 
						|
 | 
						|
        def watch_method(cls, name):
 | 
						|
            return mock.patch.object(
 | 
						|
                cls, name, autospec=True, wraps=getattr(cls, name)
 | 
						|
            )
 | 
						|
 | 
						|
        with (
 | 
						|
            watch_method(hmac.HMAC, '_init_openssl_hmac') as f,
 | 
						|
            watch_method(hmac.HMAC, '_init_builtin_hmac') as g,
 | 
						|
        ):
 | 
						|
            _ = hmac.HMAC(b'key', b'msg', digestmod="sha256")
 | 
						|
            f.assert_not_called()
 | 
						|
            g.assert_called_once()
 | 
						|
 | 
						|
    @hashlib_helper.requires_hashdigest('sha256')
 | 
						|
    def test_hmac_delegated_properties(self):
 | 
						|
        h = hmac.HMAC(b'key', b'msg', digestmod="sha256")
 | 
						|
        self.assertEqual(h.name, "hmac-sha256")
 | 
						|
        self.assertEqual(h.digest_size, 32)
 | 
						|
        self.assertEqual(h.block_size, 64)
 | 
						|
 | 
						|
    @hashlib_helper.requires_hashdigest('sha256')
 | 
						|
    def test_legacy_block_size_warnings(self):
 | 
						|
        class MockCrazyHash(object):
 | 
						|
            """Ain't no block_size attribute here."""
 | 
						|
            def __init__(self, *args):
 | 
						|
                self._x = hashlib.sha256(*args)
 | 
						|
                self.digest_size = self._x.digest_size
 | 
						|
            def update(self, v):
 | 
						|
                self._x.update(v)
 | 
						|
            def digest(self):
 | 
						|
                return self._x.digest()
 | 
						|
 | 
						|
        with warnings.catch_warnings():
 | 
						|
            warnings.simplefilter('error', RuntimeWarning)
 | 
						|
            with self.assertRaises(RuntimeWarning):
 | 
						|
                hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash)
 | 
						|
                self.fail('Expected warning about missing block_size')
 | 
						|
 | 
						|
            MockCrazyHash.block_size = 1
 | 
						|
            with self.assertRaises(RuntimeWarning):
 | 
						|
                hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash)
 | 
						|
                self.fail('Expected warning about small block_size')
 | 
						|
 | 
						|
    @hashlib_helper.requires_hashdigest('sha256')
 | 
						|
    def test_with_fallback(self):
 | 
						|
        cache = getattr(hashlib, '__builtin_constructor_cache')
 | 
						|
        try:
 | 
						|
            cache['foo'] = hashlib.sha256
 | 
						|
            hexdigest = hmac.digest(b'key', b'message', 'foo').hex()
 | 
						|
            expected = ('6e9ef29b75fffc5b7abae527d58fdadb'
 | 
						|
                        '2fe42e7219011976917343065f58ed4a')
 | 
						|
            self.assertEqual(hexdigest, expected)
 | 
						|
        finally:
 | 
						|
            cache.pop('foo')
 | 
						|
 | 
						|
 | 
						|
class BuiltinMiscellaneousTests(BuiltinModuleMixin, unittest.TestCase):
 | 
						|
    """HMAC-BLAKE2 is not standardized as BLAKE2 is a keyed hash function.
 | 
						|
 | 
						|
    In particular, there is no official test vectors for HMAC-BLAKE2.
 | 
						|
    However, we can test that the HACL* interface is correctly used by
 | 
						|
    checking against the pure Python implementation output.
 | 
						|
    """
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def setUpClass(cls):
 | 
						|
        super().setUpClass()
 | 
						|
        cls.blake2 = import_module("_blake2")
 | 
						|
        cls.blake2b = cls.blake2.blake2b
 | 
						|
        cls.blake2s = cls.blake2.blake2s
 | 
						|
 | 
						|
    def assert_hmac_blake_correctness(self, digest, key, msg, hashfunc):
 | 
						|
        self.assertIsInstance(digest, bytes)
 | 
						|
        expect = hmac._compute_digest_fallback(key, msg, hashfunc)
 | 
						|
        self.assertEqual(digest, expect)
 | 
						|
 | 
						|
    def test_compute_blake2b_32(self):
 | 
						|
        key, msg = random.randbytes(8), random.randbytes(16)
 | 
						|
        digest = self.hmac.compute_blake2b_32(key, msg)
 | 
						|
        self.assert_hmac_blake_correctness(digest, key, msg, self.blake2b)
 | 
						|
 | 
						|
    def test_compute_blake2s_32(self):
 | 
						|
        key, msg = random.randbytes(8), random.randbytes(16)
 | 
						|
        digest = self.hmac.compute_blake2s_32(key, msg)
 | 
						|
        self.assert_hmac_blake_correctness(digest, key, msg, self.blake2s)
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    unittest.main()
 |