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 8import os 9 10import pytest 11 12from cryptography.hazmat.backends.interfaces import CipherBackend 13from cryptography.hazmat.primitives.ciphers import algorithms, base, modes 14 15from .utils import _load_all_params, generate_encrypt_test 16from ...doubles import DummyMode 17from ...utils import load_nist_vectors 18 19 20@pytest.mark.supported( 21 only_if=lambda backend: backend.cipher_supported( 22 algorithms.AES(b"\x00" * 32), modes.XTS(b"\x00" * 16) 23 ), 24 skip_message="Does not support AES XTS", 25) 26@pytest.mark.requires_backend_interface(interface=CipherBackend) 27class TestAESModeXTS(object): 28 @pytest.mark.parametrize( 29 "vector", 30 # This list comprehension excludes any vector that does not have a 31 # data unit length that is divisible by 8. The NIST vectors include 32 # tests for implementations that support encryption of data that is 33 # not divisible modulo 8, but OpenSSL is not such an implementation. 34 [ 35 x 36 for x in _load_all_params( 37 os.path.join("ciphers", "AES", "XTS", "tweak-128hexstr"), 38 ["XTSGenAES128.rsp", "XTSGenAES256.rsp"], 39 load_nist_vectors, 40 ) 41 if int(x["dataunitlen"]) / 8.0 == int(x["dataunitlen"]) // 8 42 ], 43 ) 44 def test_xts_vectors(self, vector, backend): 45 key = binascii.unhexlify(vector["key"]) 46 tweak = binascii.unhexlify(vector["i"]) 47 pt = binascii.unhexlify(vector["pt"]) 48 ct = binascii.unhexlify(vector["ct"]) 49 cipher = base.Cipher(algorithms.AES(key), modes.XTS(tweak), backend) 50 enc = cipher.encryptor() 51 computed_ct = enc.update(pt) + enc.finalize() 52 assert computed_ct == ct 53 dec = cipher.decryptor() 54 computed_pt = dec.update(ct) + dec.finalize() 55 assert computed_pt == pt 56 57 58@pytest.mark.supported( 59 only_if=lambda backend: backend.cipher_supported( 60 algorithms.AES(b"\x00" * 16), modes.CBC(b"\x00" * 16) 61 ), 62 skip_message="Does not support AES CBC", 63) 64@pytest.mark.requires_backend_interface(interface=CipherBackend) 65class TestAESModeCBC(object): 66 test_cbc = generate_encrypt_test( 67 load_nist_vectors, 68 os.path.join("ciphers", "AES", "CBC"), 69 [ 70 "CBCGFSbox128.rsp", 71 "CBCGFSbox192.rsp", 72 "CBCGFSbox256.rsp", 73 "CBCKeySbox128.rsp", 74 "CBCKeySbox192.rsp", 75 "CBCKeySbox256.rsp", 76 "CBCVarKey128.rsp", 77 "CBCVarKey192.rsp", 78 "CBCVarKey256.rsp", 79 "CBCVarTxt128.rsp", 80 "CBCVarTxt192.rsp", 81 "CBCVarTxt256.rsp", 82 "CBCMMT128.rsp", 83 "CBCMMT192.rsp", 84 "CBCMMT256.rsp", 85 ], 86 lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)), 87 lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)), 88 ) 89 90 91@pytest.mark.supported( 92 only_if=lambda backend: backend.cipher_supported( 93 algorithms.AES(b"\x00" * 16), modes.ECB() 94 ), 95 skip_message="Does not support AES ECB", 96) 97@pytest.mark.requires_backend_interface(interface=CipherBackend) 98class TestAESModeECB(object): 99 test_ecb = generate_encrypt_test( 100 load_nist_vectors, 101 os.path.join("ciphers", "AES", "ECB"), 102 [ 103 "ECBGFSbox128.rsp", 104 "ECBGFSbox192.rsp", 105 "ECBGFSbox256.rsp", 106 "ECBKeySbox128.rsp", 107 "ECBKeySbox192.rsp", 108 "ECBKeySbox256.rsp", 109 "ECBVarKey128.rsp", 110 "ECBVarKey192.rsp", 111 "ECBVarKey256.rsp", 112 "ECBVarTxt128.rsp", 113 "ECBVarTxt192.rsp", 114 "ECBVarTxt256.rsp", 115 "ECBMMT128.rsp", 116 "ECBMMT192.rsp", 117 "ECBMMT256.rsp", 118 ], 119 lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)), 120 lambda **kwargs: modes.ECB(), 121 ) 122 123 124@pytest.mark.supported( 125 only_if=lambda backend: backend.cipher_supported( 126 algorithms.AES(b"\x00" * 16), modes.OFB(b"\x00" * 16) 127 ), 128 skip_message="Does not support AES OFB", 129) 130@pytest.mark.requires_backend_interface(interface=CipherBackend) 131class TestAESModeOFB(object): 132 test_ofb = generate_encrypt_test( 133 load_nist_vectors, 134 os.path.join("ciphers", "AES", "OFB"), 135 [ 136 "OFBGFSbox128.rsp", 137 "OFBGFSbox192.rsp", 138 "OFBGFSbox256.rsp", 139 "OFBKeySbox128.rsp", 140 "OFBKeySbox192.rsp", 141 "OFBKeySbox256.rsp", 142 "OFBVarKey128.rsp", 143 "OFBVarKey192.rsp", 144 "OFBVarKey256.rsp", 145 "OFBVarTxt128.rsp", 146 "OFBVarTxt192.rsp", 147 "OFBVarTxt256.rsp", 148 "OFBMMT128.rsp", 149 "OFBMMT192.rsp", 150 "OFBMMT256.rsp", 151 ], 152 lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)), 153 lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)), 154 ) 155 156 157@pytest.mark.supported( 158 only_if=lambda backend: backend.cipher_supported( 159 algorithms.AES(b"\x00" * 16), modes.CFB(b"\x00" * 16) 160 ), 161 skip_message="Does not support AES CFB", 162) 163@pytest.mark.requires_backend_interface(interface=CipherBackend) 164class TestAESModeCFB(object): 165 test_cfb = generate_encrypt_test( 166 load_nist_vectors, 167 os.path.join("ciphers", "AES", "CFB"), 168 [ 169 "CFB128GFSbox128.rsp", 170 "CFB128GFSbox192.rsp", 171 "CFB128GFSbox256.rsp", 172 "CFB128KeySbox128.rsp", 173 "CFB128KeySbox192.rsp", 174 "CFB128KeySbox256.rsp", 175 "CFB128VarKey128.rsp", 176 "CFB128VarKey192.rsp", 177 "CFB128VarKey256.rsp", 178 "CFB128VarTxt128.rsp", 179 "CFB128VarTxt192.rsp", 180 "CFB128VarTxt256.rsp", 181 "CFB128MMT128.rsp", 182 "CFB128MMT192.rsp", 183 "CFB128MMT256.rsp", 184 ], 185 lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)), 186 lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)), 187 ) 188 189 190@pytest.mark.supported( 191 only_if=lambda backend: backend.cipher_supported( 192 algorithms.AES(b"\x00" * 16), modes.CFB8(b"\x00" * 16) 193 ), 194 skip_message="Does not support AES CFB8", 195) 196@pytest.mark.requires_backend_interface(interface=CipherBackend) 197class TestAESModeCFB8(object): 198 test_cfb8 = generate_encrypt_test( 199 load_nist_vectors, 200 os.path.join("ciphers", "AES", "CFB"), 201 [ 202 "CFB8GFSbox128.rsp", 203 "CFB8GFSbox192.rsp", 204 "CFB8GFSbox256.rsp", 205 "CFB8KeySbox128.rsp", 206 "CFB8KeySbox192.rsp", 207 "CFB8KeySbox256.rsp", 208 "CFB8VarKey128.rsp", 209 "CFB8VarKey192.rsp", 210 "CFB8VarKey256.rsp", 211 "CFB8VarTxt128.rsp", 212 "CFB8VarTxt192.rsp", 213 "CFB8VarTxt256.rsp", 214 "CFB8MMT128.rsp", 215 "CFB8MMT192.rsp", 216 "CFB8MMT256.rsp", 217 ], 218 lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)), 219 lambda iv, **kwargs: modes.CFB8(binascii.unhexlify(iv)), 220 ) 221 222 223@pytest.mark.supported( 224 only_if=lambda backend: backend.cipher_supported( 225 algorithms.AES(b"\x00" * 16), modes.CTR(b"\x00" * 16) 226 ), 227 skip_message="Does not support AES CTR", 228) 229@pytest.mark.requires_backend_interface(interface=CipherBackend) 230class TestAESModeCTR(object): 231 test_ctr = generate_encrypt_test( 232 load_nist_vectors, 233 os.path.join("ciphers", "AES", "CTR"), 234 ["aes-128-ctr.txt", "aes-192-ctr.txt", "aes-256-ctr.txt"], 235 lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)), 236 lambda iv, **kwargs: modes.CTR(binascii.unhexlify(iv)), 237 ) 238 239 240@pytest.mark.parametrize( 241 "mode", 242 [ 243 modes.CBC(bytearray(b"\x00" * 16)), 244 modes.CTR(bytearray(b"\x00" * 16)), 245 modes.OFB(bytearray(b"\x00" * 16)), 246 modes.CFB(bytearray(b"\x00" * 16)), 247 modes.CFB8(bytearray(b"\x00" * 16)), 248 modes.XTS(bytearray(b"\x00" * 16)), 249 # Add a dummy mode for coverage of the cipher_supported check. 250 DummyMode(), 251 ], 252) 253@pytest.mark.requires_backend_interface(interface=CipherBackend) 254def test_buffer_protocol_alternate_modes(mode, backend): 255 data = bytearray(b"sixteen_byte_msg") 256 key = algorithms.AES(bytearray(os.urandom(32))) 257 if not backend.cipher_supported(key, mode): 258 pytest.skip("AES in {} mode not supported".format(mode.name)) 259 cipher = base.Cipher(key, mode, backend) 260 enc = cipher.encryptor() 261 ct = enc.update(data) + enc.finalize() 262 dec = cipher.decryptor() 263 pt = dec.update(ct) + dec.finalize() 264 assert pt == data 265