@@ -47,7 +47,7 @@ def setUpClass(cls):
47
47
cls .hmac = import_fresh_module ('hmac' , blocked = ['_hashlib' , '_hmac' ])
48
48
49
49
50
- @unittest . skip ( "no builtin implementation for HMAC for now" )
50
+ @hashlib_helper . requires_builtin_hmac ( )
51
51
class BuiltinModuleMixin (ModuleMixin ):
52
52
"""Built-in HACL* implementation of HMAC."""
53
53
@@ -128,6 +128,16 @@ def hmac_digest(self, key, msg=None, digestmod=None):
128
128
return _hashlib .hmac_digest (key , msg , digest = digestmod )
129
129
130
130
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
+
131
141
class CheckerMixin :
132
142
"""Mixin for checking HMAC objects (pure Python, OpenSSL or built-in)."""
133
143
@@ -335,6 +345,10 @@ def hmac_digest_by_name(self, key, msg=None, *, hashname):
335
345
return self .hmac_digest (key , msg , digestmod = openssl_func )
336
346
337
347
348
+ class BuiltinAssertersMixin (ThroughBuiltinAPIMixin , TestVectorsMixin ):
349
+ pass
350
+
351
+
338
352
class HashFunctionsTrait :
339
353
"""Trait class for 'hashfunc' in hmac_new() and hmac_digest()."""
340
354
@@ -605,6 +619,13 @@ class OpenSSLRFCTestCase(OpenSSLTestVectorsMixin,
605
619
"""
606
620
607
621
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
+ """
608
629
609
630
# TODO(picnixz): once we have a HACL* HMAC, we should also test the Python
610
631
# implementation of HMAC with a HACL*-based hash function. For now, we only
@@ -613,7 +634,7 @@ class OpenSSLRFCTestCase(OpenSSLTestVectorsMixin,
613
634
614
635
615
636
class DigestModTestCaseMixin (CreatorMixin , DigestMixin ):
616
- """Tests for the 'digestmod' parameter."""
637
+ """Tests for the 'digestmod' parameter for hmac_new() and hmac_digest() ."""
617
638
618
639
def assert_raises_missing_digestmod (self ):
619
640
"""A context manager catching errors when a digestmod is missing."""
@@ -756,11 +777,15 @@ def raiser():
756
777
class ExtensionConstructorTestCaseMixin (DigestModTestCaseMixin ,
757
778
ConstructorTestCaseMixin ):
758
779
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
761
784
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
764
789
765
790
def test_internal_types (self ):
766
791
# internal C types are immutable and cannot be instantiated
@@ -807,6 +832,24 @@ def test_hmac_digest_digestmod_parameter(self):
807
832
self .hmac_digest (b'key' , b'msg' , value )
808
833
809
834
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
+
810
853
class SanityTestCaseMixin (CreatorMixin ):
811
854
"""Sanity checks for HMAC objects and their object interface.
812
855
@@ -862,6 +905,20 @@ def test_repr(self):
862
905
self .assertStartsWith (repr (h ), f"<{ self .digestname } HMAC object @" )
863
906
864
907
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
+
865
922
class UpdateTestCaseMixin :
866
923
"""Tests for the update() method (streaming HMAC)."""
867
924
@@ -893,7 +950,7 @@ class PyUpdateTestCase(UpdateTestCaseMixin, unittest.TestCase):
893
950
@classmethod
894
951
def setUpClass (cls ):
895
952
super ().setUpClass ()
896
- cls .hmac = import_fresh_module ('hmac' , blocked = ['_hashlib' ])
953
+ cls .hmac = import_fresh_module ('hmac' , blocked = ['_hashlib' , '_hmac' ])
897
954
898
955
def HMAC (self , key , msg = None ):
899
956
return self .hmac .HMAC (key , msg , digestmod = 'sha256' )
@@ -904,7 +961,16 @@ def HMAC(self, key, msg=None):
904
961
class OpenSSLUpdateTestCase (UpdateTestCaseMixin , unittest .TestCase ):
905
962
906
963
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' )
908
974
909
975
910
976
@hashlib_helper .requires_has
37A6
hdigest ('sha256' )
0 commit comments