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 InvalidTag 12from cryptography.hazmat.backends.interfaces import CipherBackend 13from cryptography.hazmat.primitives import padding 14from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 15from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESGCM 16 17from ..hazmat.primitives.test_aead import _aead_supported 18 19 20@pytest.mark.requires_backend_interface(interface=CipherBackend) 21@pytest.mark.wycheproof_tests("aes_cbc_pkcs5_test.json") 22def test_aes_cbc_pkcs5(backend, wycheproof): 23 key = binascii.unhexlify(wycheproof.testcase["key"]) 24 iv = binascii.unhexlify(wycheproof.testcase["iv"]) 25 msg = binascii.unhexlify(wycheproof.testcase["msg"]) 26 ct = binascii.unhexlify(wycheproof.testcase["ct"]) 27 28 padder = padding.PKCS7(128).padder() 29 30 cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend) 31 enc = cipher.encryptor() 32 computed_ct = ( 33 enc.update(padder.update(msg) + padder.finalize()) + enc.finalize() 34 ) 35 dec = cipher.decryptor() 36 padded_msg = dec.update(ct) + dec.finalize() 37 unpadder = padding.PKCS7(128).unpadder() 38 if wycheproof.valid or wycheproof.acceptable: 39 assert computed_ct == ct 40 computed_msg = unpadder.update(padded_msg) + unpadder.finalize() 41 assert computed_msg == msg 42 else: 43 assert computed_ct != ct 44 with pytest.raises(ValueError): 45 unpadder.update(padded_msg) + unpadder.finalize() 46 47 48@pytest.mark.requires_backend_interface(interface=CipherBackend) 49@pytest.mark.wycheproof_tests("aes_gcm_test.json") 50def test_aes_gcm(backend, wycheproof): 51 key = binascii.unhexlify(wycheproof.testcase["key"]) 52 iv = binascii.unhexlify(wycheproof.testcase["iv"]) 53 aad = binascii.unhexlify(wycheproof.testcase["aad"]) 54 msg = binascii.unhexlify(wycheproof.testcase["msg"]) 55 ct = binascii.unhexlify(wycheproof.testcase["ct"]) 56 tag = binascii.unhexlify(wycheproof.testcase["tag"]) 57 if len(iv) < 8 or len(iv) > 128: 58 pytest.skip( 59 "Less than 64-bit IVs (and greater than 1024-bit) are no longer " 60 "supported" 61 ) 62 if backend._fips_enabled and len(iv) != 12: 63 # Red Hat disables non-96-bit IV support as part of its FIPS 64 # patches. 65 pytest.skip("Non-96-bit IVs unsupported in FIPS mode.") 66 if wycheproof.valid or wycheproof.acceptable: 67 enc = Cipher(algorithms.AES(key), modes.GCM(iv), backend).encryptor() 68 enc.authenticate_additional_data(aad) 69 computed_ct = enc.update(msg) + enc.finalize() 70 computed_tag = enc.tag 71 assert computed_ct == ct 72 assert computed_tag == tag 73 dec = Cipher( 74 algorithms.AES(key), 75 modes.GCM(iv, tag, min_tag_length=len(tag)), 76 backend, 77 ).decryptor() 78 dec.authenticate_additional_data(aad) 79 computed_msg = dec.update(ct) + dec.finalize() 80 assert computed_msg == msg 81 else: 82 dec = Cipher( 83 algorithms.AES(key), 84 modes.GCM(iv, tag, min_tag_length=len(tag)), 85 backend, 86 ).decryptor() 87 dec.authenticate_additional_data(aad) 88 dec.update(ct) 89 with pytest.raises(InvalidTag): 90 dec.finalize() 91 92 93@pytest.mark.requires_backend_interface(interface=CipherBackend) 94@pytest.mark.wycheproof_tests("aes_gcm_test.json") 95def test_aes_gcm_aead_api(backend, wycheproof): 96 key = binascii.unhexlify(wycheproof.testcase["key"]) 97 iv = binascii.unhexlify(wycheproof.testcase["iv"]) 98 aad = binascii.unhexlify(wycheproof.testcase["aad"]) 99 msg = binascii.unhexlify(wycheproof.testcase["msg"]) 100 ct = binascii.unhexlify(wycheproof.testcase["ct"]) 101 tag = binascii.unhexlify(wycheproof.testcase["tag"]) 102 if len(iv) < 8 or len(iv) > 128: 103 pytest.skip( 104 "Less than 64-bit IVs (and greater than 1024-bit) are no longer " 105 "supported" 106 ) 107 108 if backend._fips_enabled and len(iv) != 12: 109 # Red Hat disables non-96-bit IV support as part of its FIPS 110 # patches. 111 pytest.skip("Non-96-bit IVs unsupported in FIPS mode.") 112 aesgcm = AESGCM(key) 113 if wycheproof.valid or wycheproof.acceptable: 114 computed_ct = aesgcm.encrypt(iv, msg, aad) 115 assert computed_ct == ct + tag 116 computed_msg = aesgcm.decrypt(iv, ct + tag, aad) 117 assert computed_msg == msg 118 else: 119 with pytest.raises(InvalidTag): 120 aesgcm.decrypt(iv, ct + tag, aad) 121 122 123@pytest.mark.skipif( 124 not _aead_supported(AESCCM), 125 reason="Requires OpenSSL with AES-CCM support", 126) 127@pytest.mark.requires_backend_interface(interface=CipherBackend) 128@pytest.mark.wycheproof_tests("aes_ccm_test.json") 129def test_aes_ccm_aead_api(backend, wycheproof): 130 key = binascii.unhexlify(wycheproof.testcase["key"]) 131 iv = binascii.unhexlify(wycheproof.testcase["iv"]) 132 aad = binascii.unhexlify(wycheproof.testcase["aad"]) 133 msg = binascii.unhexlify(wycheproof.testcase["msg"]) 134 ct = binascii.unhexlify(wycheproof.testcase["ct"]) 135 tag = binascii.unhexlify(wycheproof.testcase["tag"]) 136 137 if ( 138 wycheproof.invalid 139 and wycheproof.testcase["comment"] == "Invalid tag size" 140 ): 141 with pytest.raises(ValueError): 142 AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8) 143 return 144 145 aesccm = AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8) 146 if wycheproof.valid or wycheproof.acceptable: 147 computed_ct = aesccm.encrypt(iv, msg, aad) 148 assert computed_ct == ct + tag 149 computed_msg = aesccm.decrypt(iv, ct + tag, aad) 150 assert computed_msg == msg 151 elif not 7 <= len(iv) <= 13: 152 with pytest.raises(ValueError): 153 aesccm.decrypt(iv, ct + tag, aad) 154 else: 155 with pytest.raises(InvalidTag): 156 aesccm.decrypt(iv, ct + tag, aad) 157