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.exceptions import AlreadyFinalized, _Reasons 13from cryptography.hazmat.backends.interfaces import CipherBackend 14from cryptography.hazmat.primitives import ciphers 15from cryptography.hazmat.primitives.ciphers import modes 16from cryptography.hazmat.primitives.ciphers.algorithms import ( 17 AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES 18) 19 20from ...utils import ( 21 load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm 22) 23 24 25class TestAES(object): 26 @pytest.mark.parametrize(("key", "keysize"), [ 27 (b"0" * 32, 128), 28 (b"0" * 48, 192), 29 (b"0" * 64, 256), 30 ]) 31 def test_key_size(self, key, keysize): 32 cipher = AES(binascii.unhexlify(key)) 33 assert cipher.key_size == keysize 34 35 def test_invalid_key_size(self): 36 with pytest.raises(ValueError): 37 AES(binascii.unhexlify(b"0" * 12)) 38 39 def test_invalid_key_type(self): 40 with pytest.raises(TypeError, match="key must be bytes"): 41 AES(u"0" * 32) 42 43 44class TestAESXTS(object): 45 @pytest.mark.requires_backend_interface(interface=CipherBackend) 46 @pytest.mark.parametrize( 47 "mode", 48 (modes.CBC, modes.CTR, modes.CFB, modes.CFB8, modes.OFB) 49 ) 50 def test_invalid_key_size_with_mode(self, mode, backend): 51 with pytest.raises(ValueError): 52 ciphers.Cipher(AES(b"0" * 64), mode(b"0" * 16), backend) 53 54 def test_xts_tweak_not_bytes(self): 55 with pytest.raises(TypeError): 56 modes.XTS(32) 57 58 def test_xts_tweak_too_small(self): 59 with pytest.raises(ValueError): 60 modes.XTS(b"0") 61 62 @pytest.mark.requires_backend_interface(interface=CipherBackend) 63 def test_xts_wrong_key_size(self, backend): 64 with pytest.raises(ValueError): 65 ciphers.Cipher(AES(b"0" * 16), modes.XTS(b"0" * 16), backend) 66 67 68class TestCamellia(object): 69 @pytest.mark.parametrize(("key", "keysize"), [ 70 (b"0" * 32, 128), 71 (b"0" * 48, 192), 72 (b"0" * 64, 256), 73 ]) 74 def test_key_size(self, key, keysize): 75 cipher = Camellia(binascii.unhexlify(key)) 76 assert cipher.key_size == keysize 77 78 def test_invalid_key_size(self): 79 with pytest.raises(ValueError): 80 Camellia(binascii.unhexlify(b"0" * 12)) 81 82 def test_invalid_key_type(self): 83 with pytest.raises(TypeError, match="key must be bytes"): 84 Camellia(u"0" * 32) 85 86 87class TestTripleDES(object): 88 @pytest.mark.parametrize("key", [ 89 b"0" * 16, 90 b"0" * 32, 91 b"0" * 48, 92 ]) 93 def test_key_size(self, key): 94 cipher = TripleDES(binascii.unhexlify(key)) 95 assert cipher.key_size == 192 96 97 def test_invalid_key_size(self): 98 with pytest.raises(ValueError): 99 TripleDES(binascii.unhexlify(b"0" * 12)) 100 101 def test_invalid_key_type(self): 102 with pytest.raises(TypeError, match="key must be bytes"): 103 TripleDES(u"0" * 16) 104 105 106class TestBlowfish(object): 107 @pytest.mark.parametrize(("key", "keysize"), [ 108 (b"0" * (keysize // 4), keysize) for keysize in range(32, 449, 8) 109 ]) 110 def test_key_size(self, key, keysize): 111 cipher = Blowfish(binascii.unhexlify(key)) 112 assert cipher.key_size == keysize 113 114 def test_invalid_key_size(self): 115 with pytest.raises(ValueError): 116 Blowfish(binascii.unhexlify(b"0" * 6)) 117 118 def test_invalid_key_type(self): 119 with pytest.raises(TypeError, match="key must be bytes"): 120 Blowfish(u"0" * 8) 121 122 123class TestCAST5(object): 124 @pytest.mark.parametrize(("key", "keysize"), [ 125 (b"0" * (keysize // 4), keysize) for keysize in range(40, 129, 8) 126 ]) 127 def test_key_size(self, key, keysize): 128 cipher = CAST5(binascii.unhexlify(key)) 129 assert cipher.key_size == keysize 130 131 def test_invalid_key_size(self): 132 with pytest.raises(ValueError): 133 CAST5(binascii.unhexlify(b"0" * 34)) 134 135 def test_invalid_key_type(self): 136 with pytest.raises(TypeError, match="key must be bytes"): 137 CAST5(u"0" * 10) 138 139 140class TestARC4(object): 141 @pytest.mark.parametrize(("key", "keysize"), [ 142 (b"0" * 10, 40), 143 (b"0" * 14, 56), 144 (b"0" * 16, 64), 145 (b"0" * 20, 80), 146 (b"0" * 32, 128), 147 (b"0" * 48, 192), 148 (b"0" * 64, 256), 149 ]) 150 def test_key_size(self, key, keysize): 151 cipher = ARC4(binascii.unhexlify(key)) 152 assert cipher.key_size == keysize 153 154 def test_invalid_key_size(self): 155 with pytest.raises(ValueError): 156 ARC4(binascii.unhexlify(b"0" * 34)) 157 158 def test_invalid_key_type(self): 159 with pytest.raises(TypeError, match="key must be bytes"): 160 ARC4(u"0" * 10) 161 162 163class TestIDEA(object): 164 def test_key_size(self): 165 cipher = IDEA(b"\x00" * 16) 166 assert cipher.key_size == 128 167 168 def test_invalid_key_size(self): 169 with pytest.raises(ValueError): 170 IDEA(b"\x00" * 17) 171 172 def test_invalid_key_type(self): 173 with pytest.raises(TypeError, match="key must be bytes"): 174 IDEA(u"0" * 16) 175 176 177class TestSEED(object): 178 def test_key_size(self): 179 cipher = SEED(b"\x00" * 16) 180 assert cipher.key_size == 128 181 182 def test_invalid_key_size(self): 183 with pytest.raises(ValueError): 184 SEED(b"\x00" * 17) 185 186 def test_invalid_key_type(self): 187 with pytest.raises(TypeError, match="key must be bytes"): 188 SEED(u"0" * 16) 189 190 191def test_invalid_backend(): 192 pretend_backend = object() 193 194 with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): 195 ciphers.Cipher(AES(b"AAAAAAAAAAAAAAAA"), modes.ECB, pretend_backend) 196 197 198@pytest.mark.supported( 199 only_if=lambda backend: backend.cipher_supported( 200 AES(b"\x00" * 16), modes.ECB() 201 ), 202 skip_message="Does not support AES ECB", 203) 204@pytest.mark.requires_backend_interface(interface=CipherBackend) 205class TestCipherUpdateInto(object): 206 @pytest.mark.parametrize( 207 "params", 208 load_vectors_from_file( 209 os.path.join("ciphers", "AES", "ECB", "ECBGFSbox128.rsp"), 210 load_nist_vectors 211 ) 212 ) 213 def test_update_into(self, params, backend): 214 key = binascii.unhexlify(params["key"]) 215 pt = binascii.unhexlify(params["plaintext"]) 216 ct = binascii.unhexlify(params["ciphertext"]) 217 c = ciphers.Cipher(AES(key), modes.ECB(), backend) 218 encryptor = c.encryptor() 219 buf = bytearray(len(pt) + 15) 220 res = encryptor.update_into(pt, buf) 221 assert res == len(pt) 222 assert bytes(buf)[:res] == ct 223 224 @pytest.mark.supported( 225 only_if=lambda backend: backend.cipher_supported( 226 AES(b"\x00" * 16), modes.GCM(b"0" * 12) 227 ), 228 skip_message="Does not support AES GCM", 229 ) 230 def test_update_into_gcm(self, backend): 231 key = binascii.unhexlify(b"e98b72a9881a84ca6b76e0f43e68647a") 232 iv = binascii.unhexlify(b"8b23299fde174053f3d652ba") 233 ct = binascii.unhexlify(b"5a3c1cf1985dbb8bed818036fdd5ab42") 234 pt = binascii.unhexlify(b"28286a321293253c3e0aa2704a278032") 235 c = ciphers.Cipher(AES(key), modes.GCM(iv), backend) 236 encryptor = c.encryptor() 237 buf = bytearray(len(pt) + 15) 238 res = encryptor.update_into(pt, buf) 239 assert res == len(pt) 240 assert bytes(buf)[:res] == ct 241 encryptor.finalize() 242 c = ciphers.Cipher(AES(key), modes.GCM(iv, encryptor.tag), backend) 243 decryptor = c.decryptor() 244 res = decryptor.update_into(ct, buf) 245 decryptor.finalize() 246 assert res == len(pt) 247 assert bytes(buf)[:res] == pt 248 249 @pytest.mark.supported( 250 only_if=lambda backend: backend.cipher_supported( 251 AES(b"\x00" * 16), modes.GCM(b"0" * 12) 252 ), 253 skip_message="Does not support AES GCM", 254 ) 255 def test_finalize_with_tag_already_finalized(self, backend): 256 key = binascii.unhexlify(b"e98b72a9881a84ca6b76e0f43e68647a") 257 iv = binascii.unhexlify(b"8b23299fde174053f3d652ba") 258 encryptor = ciphers.Cipher( 259 AES(key), modes.GCM(iv), backend 260 ).encryptor() 261 ciphertext = encryptor.update(b"abc") + encryptor.finalize() 262 263 decryptor = ciphers.Cipher( 264 AES(key), modes.GCM(iv, tag=encryptor.tag), backend 265 ).decryptor() 266 decryptor.update(ciphertext) 267 decryptor.finalize() 268 with pytest.raises(AlreadyFinalized): 269 decryptor.finalize_with_tag(encryptor.tag) 270 271 @pytest.mark.parametrize( 272 "params", 273 load_vectors_from_file( 274 os.path.join("ciphers", "AES", "ECB", "ECBGFSbox128.rsp"), 275 load_nist_vectors 276 ) 277 ) 278 def test_update_into_multiple_calls(self, params, backend): 279 key = binascii.unhexlify(params["key"]) 280 pt = binascii.unhexlify(params["plaintext"]) 281 ct = binascii.unhexlify(params["ciphertext"]) 282 c = ciphers.Cipher(AES(key), modes.ECB(), backend) 283 encryptor = c.encryptor() 284 buf = bytearray(len(pt) + 15) 285 res = encryptor.update_into(pt[:3], buf) 286 assert res == 0 287 res = encryptor.update_into(pt[3:], buf) 288 assert res == len(pt) 289 assert bytes(buf)[:res] == ct 290 291 def test_update_into_buffer_too_small(self, backend): 292 key = b"\x00" * 16 293 c = ciphers.Cipher(AES(key), modes.ECB(), backend) 294 encryptor = c.encryptor() 295 buf = bytearray(16) 296 with pytest.raises(ValueError): 297 encryptor.update_into(b"testing", buf) 298 299 @pytest.mark.supported( 300 only_if=lambda backend: backend.cipher_supported( 301 AES(b"\x00" * 16), modes.GCM(b"\x00" * 12) 302 ), 303 skip_message="Does not support AES GCM", 304 ) 305 def test_update_into_buffer_too_small_gcm(self, backend): 306 key = b"\x00" * 16 307 c = ciphers.Cipher(AES(key), modes.GCM(b"\x00" * 12), backend) 308 encryptor = c.encryptor() 309 buf = bytearray(5) 310 with pytest.raises(ValueError): 311 encryptor.update_into(b"testing", buf) 312