@@ -70,7 +70,7 @@ def test_hmac_should_reject_nonstring_key(self):
7070 def test_hmac_should_accept_unicode_key (self ):
7171 algo = HMACAlgorithm (HMACAlgorithm .SHA256 )
7272
73- algo .prepare_key ("awesome" )
73+ algo .prepare_key ("awesome" * 5 ) # 35 characters > 32 bytes minimum
7474
7575 @pytest .mark .parametrize (
7676 "key" ,
@@ -101,12 +101,12 @@ def test_hmac_jwk_should_parse_and_verify(self):
101101 @pytest .mark .parametrize ("as_dict" , (False , True ))
102102 def test_hmac_to_jwk_returns_correct_values (self , as_dict ):
103103 algo = HMACAlgorithm (HMACAlgorithm .SHA256 )
104- key : Any = algo .to_jwk ("secret " , as_dict = as_dict )
104+ key : Any = algo .to_jwk ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa " , as_dict = as_dict )
105105
106106 if not as_dict :
107107 key = json .loads (key )
108108
109- assert key == {"kty" : "oct" , "k" : "c2VjcmV0 " }
109+ assert key == {"kty" : "oct" , "k" : "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE " }
110110
111111 def test_hmac_from_jwk_should_raise_exception_if_not_hmac_key (self ):
112112 algo = HMACAlgorithm (HMACAlgorithm .SHA256 )
@@ -122,6 +122,57 @@ def test_hmac_from_jwk_should_raise_exception_if_empty_json(self):
122122 with pytest .raises (InvalidKeyError ):
123123 algo .from_jwk (keyfile .read ())
124124
125+ # CVE-2025-45768: Test minimum key length enforcement
126+ @pytest .mark .parametrize (
127+ "hash_alg,min_length,weak_key" ,
128+ [
129+ (HMACAlgorithm .SHA256 , 32 , b"short" ), # 5 bytes, too short for HS256
130+ (HMACAlgorithm .SHA256 , 32 , b"a" * 31 ), # 31 bytes, just under minimum
131+ (HMACAlgorithm .SHA384 , 48 , b"b" * 47 ), # 47 bytes, just under minimum
132+ (HMACAlgorithm .SHA512 , 64 , b"c" * 63 ), # 63 bytes, just under minimum
133+ ],
134+ )
135+ def test_hmac_should_reject_weak_keys (self , hash_alg , min_length , weak_key ):
136+ """Test that HMAC keys below minimum length are rejected (CVE-2025-45768)"""
137+ algo = HMACAlgorithm (hash_alg )
138+
139+ with pytest .raises (InvalidKeyError ) as excinfo :
140+ algo .prepare_key (weak_key )
141+
142+ error_msg = str (excinfo .value )
143+ assert f"at least { min_length * 8 } bits" in error_msg
144+ assert f"Key provided is { len (weak_key ) * 8 } bits" in error_msg
145+
146+ @pytest .mark .parametrize (
147+ "hash_alg,adequate_key" ,
148+ [
149+ (HMACAlgorithm .SHA256 , b"a" * 32 ), # 32 bytes for HS256
150+ (HMACAlgorithm .SHA384 , b"b" * 48 ), # 48 bytes for HS384
151+ (HMACAlgorithm .SHA512 , b"c" * 64 ), # 64 bytes for HS512
152+ ],
153+ )
154+ def test_hmac_should_accept_adequate_keys (self , hash_alg , adequate_key ):
155+ """Test that HMAC keys at or above minimum length are accepted"""
156+ algo = HMACAlgorithm (hash_alg )
157+
158+ # Should not raise an exception
159+ prepared_key = algo .prepare_key (adequate_key )
160+ assert prepared_key == adequate_key
161+
162+ def test_hmac_from_jwk_should_reject_weak_keys (self ):
163+ """Test that weak HMAC keys are rejected when loaded from JWK (CVE-2025-45768)"""
164+ algo = HMACAlgorithm (HMACAlgorithm .SHA256 )
165+
166+ # Create a JWK with a weak key (5 bytes)
167+ weak_jwk = {"kty" : "oct" , "k" : "c2hvcnQ" } # base64url("short") - only 5 bytes
168+
169+ with pytest .raises (InvalidKeyError ) as excinfo :
170+ algo .from_jwk (weak_jwk )
171+
172+ error_msg = str (excinfo .value )
173+ assert "at least 256 bits" in error_msg
174+ assert "40 bits" in error_msg # 5 bytes * 8 = 40 bits
175+
125176 @crypto_required
126177 def test_rsa_should_parse_pem_public_key (self ):
127178 algo = RSAAlgorithm (RSAAlgorithm .SHA256 )
@@ -173,6 +224,75 @@ def test_rsa_verify_should_return_false_if_signature_invalid(self):
173224 result = algo .verify (message , pub_key , sig )
174225 assert not result
175226
227+ # CVE-2025-45768: Test RSA minimum key size enforcement
228+ @crypto_required
229+ def test_rsa_should_reject_weak_keys (self ):
230+ """Test that RSA keys below 2048 bits are rejected (CVE-2025-45768)"""
231+ from cryptography .hazmat .primitives .asymmetric import rsa
232+
233+ algo = RSAAlgorithm (RSAAlgorithm .SHA256 )
234+
235+ # Generate a weak 1024-bit RSA key
236+ weak_private_key = rsa .generate_private_key (
237+ public_exponent = 65537 , key_size = 1024
238+ )
239+ weak_public_key = weak_private_key .public_key ()
240+
241+ # Test with private key
242+ with pytest .raises (InvalidKeyError ) as excinfo :
243+ algo .prepare_key (weak_private_key )
244+
245+ error_msg = str (excinfo .value )
246+ assert "at least 2048 bits" in error_msg
247+ assert "1024 bits" in error_msg
248+
249+ # Test with public key
250+ with pytest .raises (InvalidKeyError ) as excinfo :
251+ algo .prepare_key (weak_public_key )
252+
253+ error_msg = str (excinfo .value )
254+ assert "at least 2048 bits" in error_msg
255+ assert "1024 bits" in error_msg
256+
257+ @crypto_required
258+ def test_rsa_should_accept_adequate_keys (self ):
259+ """Test that RSA keys at or above 2048 bits are accepted"""
260+ from cryptography .hazmat .primitives .asymmetric import rsa
261+
262+ algo = RSAAlgorithm (RSAAlgorithm .SHA256 )
263+
264+ # Generate a strong 2048-bit RSA key
265+ strong_private_key = rsa .generate_private_key (
266+ public_exponent = 65537 , key_size = 2048
267+ )
268+ strong_public_key = strong_private_key .public_key ()
269+
270+ # Should not raise exceptions
271+ prepared_private = algo .prepare_key (strong_private_key )
272+ prepared_public = algo .prepare_key (strong_public_key )
273+
274+ assert prepared_private == strong_private_key
275+ assert prepared_public == strong_public_key
276+
277+ @crypto_required
278+ def test_rsa_from_jwk_should_reject_weak_keys (self ):
279+ """Test that weak RSA keys are rejected when loaded from JWK (CVE-2025-45768)"""
280+ from cryptography .hazmat .primitives .asymmetric import rsa
281+
282+ # Generate a weak 1024-bit RSA key and convert to JWK
283+ weak_key = rsa .generate_private_key (public_exponent = 65537 , key_size = 1024 )
284+
285+ # Convert to JWK format (this will work since to_jwk doesn't validate)
286+ weak_jwk = RSAAlgorithm .to_jwk (weak_key , as_dict = True )
287+
288+ # Now try to load it back - should fail
289+ with pytest .raises (InvalidKeyError ) as excinfo :
290+ RSAAlgorithm .from_jwk (weak_jwk )
291+
292+ error_msg = str (excinfo .value )
293+ assert "at least 2048 bits" in error_msg
294+ assert "1024 bits" in error_msg
295+
176296 @crypto_required
177297 def test_ec_jwk_public_and_private_keys_should_parse_and_verify (self ):
178298 tests = {
0 commit comments