8000 add various tests for the HACL* HMAC implementation · python/cpython@b874961 · GitHub
[go: up one dir, main page]

Skip to content

Commit b874961

Browse files
committed
add various tests for the HACL* HMAC implementation
- create `ThroughBuiltinAPIMixin` similar to `ThroughOpenSSLAPIMixin` - add tests for RFC test vectors - add tests for `digestmod` parameter - add sanity check tests - add `HMAC.update()` tests
1 parent 128a99d commit b874961

File tree

1 file changed

+74
-8
lines changed

1 file changed

+74
-8
lines changed

Lib/test/test_hmac.py

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def setUpClass(cls):
4747
cls.hmac = import_fresh_module('hmac', blocked=['_hashlib', '_hmac'])
4848

4949

50-
@unittest.skip("no builtin implementation for HMAC for now")
50+
@hashlib_helper.requires_builtin_hmac()
5151
class BuiltinModuleMixin(ModuleMixin):
5252
"""Built-in HACL* implementation of HMAC."""
5353

@@ -128,6 +128,16 @@ def hmac_digest(self, key, msg=None, digestmod=None):
128128
return _hashlib.hmac_digest(key, msg, digest=digestmod)
129129

130130

131+
class ThroughBuiltinAPIMixin(BuiltinModuleMixin, CreatorMixin, DigestMixin):
132+
"""Mixin delegating to _hmac.new() and _hmac.compute_digest()."""
133+
134+
def hmac_new(self, key, msg=None, digestmod=None):
135+
return self.hmac.new(key, msg, digestmod=digestmod)
136+
137+
def hmac_digest(self, key, msg=None, digestmod=None):
138+
return self.hmac.compute_digest(key, msg, digest=digestmod)
139+
140+
131141
class CheckerMixin:
132142
"""Mixin for checking HMAC objects (pure Python, OpenSSL or built-in)."""
133143

@@ -335,6 +345,10 @@ def hmac_digest_by_name(self, key, msg=None, *, hashname):
335345
return self.hmac_digest(key, msg, digestmod=openssl_func)
336346

337347

348+
class BuiltinAssertersMixin(ThroughBuiltinAPIMixin, TestVectorsMixin):
349+
pass
350+
351+
338352
class HashFunctionsTrait:
339353
"""Trait class for 'hashfunc' in hmac_new() and hmac_digest()."""
340354

@@ -605,6 +619,13 @@ class OpenSSLRFCTestCase(OpenSSLTestVectorsMixin,
605619
"""
606620

607621

622+
class BuiltinRFCTestCase(BuiltinAssertersMixin,
623+
WithNamedHashFunctions, RFCTestCasesMixin,
624+
unittest.TestCase):
625+
"""Built-in HACL* implementation of HMAC.
626+
627+
The underlying hash functions are also HACL*-based.
628+
"""
608629

609630
# TODO(picnixz): once we have a HACL* HMAC, we should also test the Python
610631
# implementation of HMAC with a HACL*-based hash function. For now, we only
@@ -613,7 +634,7 @@ class OpenSSLRFCTestCase(OpenSSLTestVectorsMixin,
613634

614635

615636
class DigestModTestCaseMixin(CreatorMixin, DigestMixin):
616-
"""Tests for the 'digestmod' parameter."""
637+
"""Tests for the 'digestmod' parameter for hmac_new() and hmac_digest()."""
617638

618639
def assert_raises_missing_digestmod(self):
619640
"""A context manager catching errors when a digestmod is missing."""
@@ -756,11 +777,15 @@ def raiser():
756777
class ExtensionConstructorTestCaseMixin(DigestModTestCaseMixin,
757778
ConstructorTestCaseMixin):
758779

759-
# The underlying C class.
760-
obj_type = None
780+
@property
781+
def obj_type(self):
782+
"""The underlying (non-instantiable) C class."""
783+
raise NotImplementedError
761784

762-
# The exact exception class raised when a 'digestmod' parameter is invalid.
763-
exc_type = None
785+
@property
786+
def exc_type(self):
787+
"""The exact exception class raised upon invalid 'digestmod' values."""
788+
raise NotImplementedError
764789

765790
def test_internal_types(self):
766791
# internal C types are immutable and cannot be instantiated
@@ -807,6 +832,24 @@ def test_hmac_digest_digestmod_parameter(self):
807832
self.hmac_digest(b'key', b'msg', value)
808833

809834

835+
class BuiltinConstructorTestCase(ThroughBuiltinAPIMixin,
836+
ExtensionConstructorTestCaseMixin,
837+
unittest.TestCase):
838+
839+
@property
840+
def obj_type(self):
841+
return self.hmac.HMAC
842+
843+
@property
844+
def exc_type(self):
845+
return self.hmac.UnknownHashError
846+
847+
def test_hmac_digest_digestmod_parameter(self):
848+
for value in [object, 'unknown', 1234, None]:
849+
with self.subTest(value=value), self.assert_digestmod_error():
850+
self.hmac_digest(b'key', b'msg', value)
851+
852+
810853
class SanityTestCaseMixin(CreatorMixin):
811854
"""Sanity checks for HMAC objects and their object interface.
812855
@@ -862,6 +905,20 @@ def test_repr(self):
862905
self.assertStartsWith(repr(h), f"<{self.digestname} HMAC object @")
863906

864907

908+
class BuiltinSanityTestCase(ThroughBuiltinAPIMixin, SanityTestCaseMixin,
909+
unittest.TestCase):
910+
911+
@classmethod
912+
def setUpClass(cls):
913+
super().setUpClass()
914+
cls.hmac_class = cls.hmac.HMAC
915+
cls.digestname = 'sha256'
916+
917+
def test_repr(self):
918+
h = self.hmac_new(b"my secret key", digestmod=self.digestname)
919+
self.assertStartsWith(repr(h), f"<{self.digestname} HMAC object @")
920+
921+
865922
class UpdateTestCaseMixin:
866923
"""Tests for the update() method (streaming HMAC)."""
867924

@@ -893,7 +950,7 @@ class PyUpdateTestCase(UpdateTestCaseMixin, unittest.TestCase):
893950
@classmethod
894951
def setUpClass(cls):
895952
super().setUpClass()
896-
cls.hmac = import_fresh_module('hmac', blocked=['_hashlib'])
953+
cls.hmac = import_fresh_module('hmac', blocked=['_hashlib', '_hmac'])
897954

898955
def HMAC(self, key, msg=None):
899956
return self.hmac.HMAC(key, msg, digestmod='sha256')
@@ -904,7 +961,16 @@ def HMAC(self, key, msg=None):
904961
class OpenSSLUpdateTestCase(UpdateTestCaseMixin, unittest.TestCase):
905962

906963
def HMAC(self, key, msg=None):
907-
return hmac.new(key, msg, digestmod='sha256')
964+
return _hashlib.hmac_new(key, msg, digestmod='sha256')
965+
966+
967+
class BuiltinUpdateTestCase(BuiltinModuleMixin,
968+
UpdateTestCaseMixin, unittest.TestCase):
969+
970+
def HMAC(self, key, msg=None):
971+
# Even if Python does not build '_sha2', the HACL* sources
972+
# are still built, making it possible to use SHA-2 hashes.
973+
return self.hmac.new(key, msg, digestmod='sha256')
908974

909975

910976
@hashlib_helper.requires_has 37A6 hdigest('sha256')

0 commit comments

Comments
 (0)
0