1# This file is dual licensed under the terms of the Apache License, Version 2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 3# for complete details. 4 5from __future__ import absolute_import, division, print_function 6 7import binascii 8 9import pytest 10 11from cryptography.exceptions import InvalidSignature 12from cryptography.hazmat.backends.interfaces import RSABackend 13from cryptography.hazmat.primitives import hashes, serialization 14from cryptography.hazmat.primitives.asymmetric import padding 15 16 17_DIGESTS = { 18 "SHA-1": hashes.SHA1(), 19 "SHA-224": hashes.SHA224(), 20 "SHA-256": hashes.SHA256(), 21 "SHA-384": hashes.SHA384(), 22 "SHA-512": hashes.SHA512(), 23 # Not supported by OpenSSL for RSA signing 24 "SHA-512/224": None, 25 "SHA-512/256": None, 26 "SHA3-224": hashes.SHA3_224(), 27 "SHA3-256": hashes.SHA3_256(), 28 "SHA3-384": hashes.SHA3_384(), 29 "SHA3-512": hashes.SHA3_512(), 30} 31 32 33def should_verify(backend, wycheproof): 34 if wycheproof.valid: 35 return True 36 37 if wycheproof.acceptable: 38 return not wycheproof.has_flag("MissingNull") 39 40 return False 41 42 43@pytest.mark.requires_backend_interface(interface=RSABackend) 44@pytest.mark.wycheproof_tests( 45 "rsa_signature_test.json", 46 "rsa_signature_2048_sha224_test.json", 47 "rsa_signature_2048_sha256_test.json", 48 "rsa_signature_2048_sha384_test.json", 49 "rsa_signature_2048_sha512_test.json", 50 "rsa_signature_2048_sha512_224_test.json", 51 "rsa_signature_2048_sha512_256_test.json", 52 "rsa_signature_2048_sha3_224_test.json", 53 "rsa_signature_2048_sha3_256_test.json", 54 "rsa_signature_2048_sha3_384_test.json", 55 "rsa_signature_2048_sha3_512_test.json", 56 "rsa_signature_3072_sha256_test.json", 57 "rsa_signature_3072_sha384_test.json", 58 "rsa_signature_3072_sha512_test.json", 59 "rsa_signature_3072_sha512_256_test.json", 60 "rsa_signature_3072_sha3_256_test.json", 61 "rsa_signature_3072_sha3_384_test.json", 62 "rsa_signature_3072_sha3_512_test.json", 63 "rsa_signature_4096_sha384_test.json", 64 "rsa_signature_4096_sha512_test.json", 65 "rsa_signature_4096_sha512_256_test.json", 66) 67def test_rsa_pkcs1v15_signature(backend, wycheproof): 68 key = serialization.load_der_public_key( 69 binascii.unhexlify(wycheproof.testgroup["keyDer"]), backend 70 ) 71 digest = _DIGESTS[wycheproof.testgroup["sha"]] 72 73 if digest is None or not backend.hash_supported(digest): 74 pytest.skip( 75 "Hash {} not supported".format(wycheproof.testgroup["sha"]) 76 ) 77 78 if should_verify(backend, wycheproof): 79 key.verify( 80 binascii.unhexlify(wycheproof.testcase["sig"]), 81 binascii.unhexlify(wycheproof.testcase["msg"]), 82 padding.PKCS1v15(), 83 digest, 84 ) 85 else: 86 with pytest.raises(InvalidSignature): 87 key.verify( 88 binascii.unhexlify(wycheproof.testcase["sig"]), 89 binascii.unhexlify(wycheproof.testcase["msg"]), 90 padding.PKCS1v15(), 91 digest, 92 ) 93 94 95@pytest.mark.wycheproof_tests("rsa_sig_gen_misc_test.json") 96def test_rsa_pkcs1v15_signature_generation(backend, wycheproof): 97 key = serialization.load_pem_private_key( 98 wycheproof.testgroup["privateKeyPem"].encode(), 99 password=None, 100 backend=backend, 101 ) 102 digest = _DIGESTS[wycheproof.testgroup["sha"]] 103 104 sig = key.sign( 105 binascii.unhexlify(wycheproof.testcase["msg"]), 106 padding.PKCS1v15(), 107 digest, 108 ) 109 assert sig == binascii.unhexlify(wycheproof.testcase["sig"]) 110 111 112@pytest.mark.requires_backend_interface(interface=RSABackend) 113@pytest.mark.wycheproof_tests( 114 "rsa_pss_2048_sha1_mgf1_20_test.json", 115 "rsa_pss_2048_sha256_mgf1_0_test.json", 116 "rsa_pss_2048_sha256_mgf1_32_test.json", 117 "rsa_pss_2048_sha512_256_mgf1_28_test.json", 118 "rsa_pss_2048_sha512_256_mgf1_32_test.json", 119 "rsa_pss_3072_sha256_mgf1_32_test.json", 120 "rsa_pss_4096_sha256_mgf1_32_test.json", 121 "rsa_pss_4096_sha512_mgf1_32_test.json", 122 "rsa_pss_misc_test.json", 123) 124def test_rsa_pss_signature(backend, wycheproof): 125 key = serialization.load_der_public_key( 126 binascii.unhexlify(wycheproof.testgroup["keyDer"]), backend 127 ) 128 digest = _DIGESTS[wycheproof.testgroup["sha"]] 129 mgf_digest = _DIGESTS[wycheproof.testgroup["mgfSha"]] 130 131 if digest is None or mgf_digest is None: 132 pytest.skip( 133 "PSS with digest={} and MGF digest={} not supported".format( 134 wycheproof.testgroup["sha"], 135 wycheproof.testgroup["mgfSha"], 136 ) 137 ) 138 139 if wycheproof.valid or wycheproof.acceptable: 140 key.verify( 141 binascii.unhexlify(wycheproof.testcase["sig"]), 142 binascii.unhexlify(wycheproof.testcase["msg"]), 143 padding.PSS( 144 mgf=padding.MGF1(mgf_digest), 145 salt_length=wycheproof.testgroup["sLen"], 146 ), 147 digest, 148 ) 149 else: 150 with pytest.raises(InvalidSignature): 151 key.verify( 152 binascii.unhexlify(wycheproof.testcase["sig"]), 153 binascii.unhexlify(wycheproof.testcase["msg"]), 154 padding.PSS( 155 mgf=padding.MGF1(mgf_digest), 156 salt_length=wycheproof.testgroup["sLen"], 157 ), 158 digest, 159 ) 160 161 162@pytest.mark.requires_backend_interface(interface=RSABackend) 163@pytest.mark.wycheproof_tests( 164 "rsa_oaep_2048_sha1_mgf1sha1_test.json", 165 "rsa_oaep_2048_sha224_mgf1sha1_test.json", 166 "rsa_oaep_2048_sha224_mgf1sha224_test.json", 167 "rsa_oaep_2048_sha256_mgf1sha1_test.json", 168 "rsa_oaep_2048_sha256_mgf1sha256_test.json", 169 "rsa_oaep_2048_sha384_mgf1sha1_test.json", 170 "rsa_oaep_2048_sha384_mgf1sha384_test.json", 171 "rsa_oaep_2048_sha512_mgf1sha1_test.json", 172 "rsa_oaep_2048_sha512_mgf1sha512_test.json", 173 "rsa_oaep_3072_sha256_mgf1sha1_test.json", 174 "rsa_oaep_3072_sha256_mgf1sha256_test.json", 175 "rsa_oaep_3072_sha512_mgf1sha1_test.json", 176 "rsa_oaep_3072_sha512_mgf1sha512_test.json", 177 "rsa_oaep_4096_sha256_mgf1sha1_test.json", 178 "rsa_oaep_4096_sha256_mgf1sha256_test.json", 179 "rsa_oaep_4096_sha512_mgf1sha1_test.json", 180 "rsa_oaep_4096_sha512_mgf1sha512_test.json", 181 "rsa_oaep_misc_test.json", 182) 183def test_rsa_oaep_encryption(backend, wycheproof): 184 key = serialization.load_pem_private_key( 185 wycheproof.testgroup["privateKeyPem"].encode("ascii"), 186 password=None, 187 backend=backend, 188 ) 189 digest = _DIGESTS[wycheproof.testgroup["sha"]] 190 mgf_digest = _DIGESTS[wycheproof.testgroup["mgfSha"]] 191 192 padding_algo = padding.OAEP( 193 mgf=padding.MGF1(algorithm=mgf_digest), 194 algorithm=digest, 195 label=binascii.unhexlify(wycheproof.testcase["label"]), 196 ) 197 198 if not backend.rsa_padding_supported(padding_algo): 199 pytest.skip( 200 "OAEP with digest={} and MGF digest={} not supported".format( 201 wycheproof.testgroup["sha"], 202 wycheproof.testgroup["mgfSha"], 203 ) 204 ) 205 206 if wycheproof.valid or wycheproof.acceptable: 207 pt = key.decrypt( 208 binascii.unhexlify(wycheproof.testcase["ct"]), padding_algo 209 ) 210 assert pt == binascii.unhexlify(wycheproof.testcase["msg"]) 211 else: 212 with pytest.raises(ValueError): 213 key.decrypt( 214 binascii.unhexlify(wycheproof.testcase["ct"]), padding_algo 215 ) 216 217 218@pytest.mark.wycheproof_tests( 219 "rsa_pkcs1_2048_test.json", 220 "rsa_pkcs1_3072_test.json", 221 "rsa_pkcs1_4096_test.json", 222) 223def test_rsa_pkcs1_encryption(backend, wycheproof): 224 key = serialization.load_pem_private_key( 225 wycheproof.testgroup["privateKeyPem"].encode("ascii"), 226 password=None, 227 backend=backend, 228 ) 229 230 if wycheproof.valid: 231 pt = key.decrypt( 232 binascii.unhexlify(wycheproof.testcase["ct"]), padding.PKCS1v15() 233 ) 234 assert pt == binascii.unhexlify(wycheproof.testcase["msg"]) 235 else: 236 with pytest.raises(ValueError): 237 key.decrypt( 238 binascii.unhexlify(wycheproof.testcase["ct"]), 239 padding.PKCS1v15(), 240 ) 241