blob: 2584272a092a2c0dbfe923e7c9f7ada94a1ed32a [file] [log] [blame]
Alex Gaynorbd458ae2013-10-16 11:59:30 -07001import binascii
2import os
3
David Reid5443e9d2014-01-22 17:18:49 -08004import itertools
5
Alex Gaynorbd458ae2013-10-16 11:59:30 -07006import pytest
7
Paul Kehrer22e80cb2013-11-20 21:27:00 -06008from cryptography.hazmat.primitives import hashes, hmac
Paul Kehrer1277bc72014-01-28 17:09:59 -06009from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
Paul Kehrer21dde562013-11-06 12:22:09 +080010from cryptography.hazmat.primitives.ciphers import Cipher
David Reid0d492db2014-01-27 17:05:49 -080011from cryptography.hazmat.primitives.kdf.hkdf import HKDF
David Reid66c9cd92014-01-20 16:05:53 -080012
Paul Kehrer22e80cb2013-11-20 21:27:00 -060013from cryptography.exceptions import (
Paul Kehrera4bfc082013-11-22 19:57:37 -060014 AlreadyFinalized, NotYetFinalized, AlreadyUpdated, InvalidTag,
Paul Kehrer22e80cb2013-11-20 21:27:00 -060015)
Alex Gaynorbd458ae2013-10-16 11:59:30 -070016
Paul Kehrerf7f6a9f2013-11-11 20:43:52 -060017from ...utils import load_vectors_from_file
18
Alex Gaynorbd458ae2013-10-16 11:59:30 -070019
Alex Gaynore5c5eec2013-12-13 08:10:20 -080020def _load_all_params(path, file_names, param_loader):
21 all_params = []
22 for file_name in file_names:
23 all_params.extend(
24 load_vectors_from_file(os.path.join(path, file_name), param_loader)
25 )
26 return all_params
27
Alex Gaynor4eec0bb2013-12-13 09:12:19 -080028
Alex Gaynor016eed12013-10-16 14:16:04 -070029def generate_encrypt_test(param_loader, path, file_names, cipher_factory,
Paul Kehrer783479c2013-12-26 21:08:45 -060030 mode_factory):
Alex Gaynore5c5eec2013-12-13 08:10:20 -080031 all_params = _load_all_params(path, file_names, param_loader)
32
33 @pytest.mark.parametrize("params", all_params)
34 def test_encryption(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -060035 encrypt_test(backend, cipher_factory, mode_factory, params)
Alex Gaynore5c5eec2013-12-13 08:10:20 -080036
Alex Gaynorbd458ae2013-10-16 11:59:30 -070037 return test_encryption
38
39
Paul Kehrer783479c2013-12-26 21:08:45 -060040def encrypt_test(backend, cipher_factory, mode_factory, params):
Paul Kehrera620b7d2013-12-20 22:59:02 -060041 plaintext = params["plaintext"]
42 ciphertext = params["ciphertext"]
Alex Gaynor21919e22013-12-13 08:56:32 -080043 cipher = Cipher(
44 cipher_factory(**params),
45 mode_factory(**params),
46 backend=backend
47 )
48 encryptor = cipher.encryptor()
49 actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext))
50 actual_ciphertext += encryptor.finalize()
51 assert actual_ciphertext == binascii.unhexlify(ciphertext)
52 decryptor = cipher.decryptor()
53 actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext))
54 actual_plaintext += decryptor.finalize()
55 assert actual_plaintext == binascii.unhexlify(plaintext)
56
57
Paul Kehrer22e80cb2013-11-20 21:27:00 -060058def generate_aead_test(param_loader, path, file_names, cipher_factory,
Paul Kehrer783479c2013-12-26 21:08:45 -060059 mode_factory):
Alex Gaynore5c5eec2013-12-13 08:10:20 -080060 all_params = _load_all_params(path, file_names, param_loader)
61
62 @pytest.mark.parametrize("params", all_params)
63 def test_aead(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -060064 aead_test(backend, cipher_factory, mode_factory, params)
Alex Gaynore5c5eec2013-12-13 08:10:20 -080065
Paul Kehrer22e80cb2013-11-20 21:27:00 -060066 return test_aead
67
68
Paul Kehrer783479c2013-12-26 21:08:45 -060069def aead_test(backend, cipher_factory, mode_factory, params):
Alex Gaynor21919e22013-12-13 08:56:32 -080070 if params.get("pt") is not None:
Paul Kehrera620b7d2013-12-20 22:59:02 -060071 plaintext = params["pt"]
72 ciphertext = params["ct"]
73 aad = params["aad"]
Alex Gaynor21919e22013-12-13 08:56:32 -080074 if params.get("fail") is True:
75 cipher = Cipher(
76 cipher_factory(binascii.unhexlify(params["key"])),
77 mode_factory(binascii.unhexlify(params["iv"]),
78 binascii.unhexlify(params["tag"])),
79 backend
80 )
81 decryptor = cipher.decryptor()
82 decryptor.authenticate_additional_data(binascii.unhexlify(aad))
83 actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext))
84 with pytest.raises(InvalidTag):
85 decryptor.finalize()
86 else:
87 cipher = Cipher(
88 cipher_factory(binascii.unhexlify(params["key"])),
89 mode_factory(binascii.unhexlify(params["iv"]), None),
90 backend
91 )
92 encryptor = cipher.encryptor()
93 encryptor.authenticate_additional_data(binascii.unhexlify(aad))
94 actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext))
95 actual_ciphertext += encryptor.finalize()
96 tag_len = len(params["tag"])
97 assert binascii.hexlify(encryptor.tag)[:tag_len] == params["tag"]
98 cipher = Cipher(
99 cipher_factory(binascii.unhexlify(params["key"])),
100 mode_factory(binascii.unhexlify(params["iv"]),
101 binascii.unhexlify(params["tag"])),
102 backend
103 )
104 decryptor = cipher.decryptor()
105 decryptor.authenticate_additional_data(binascii.unhexlify(aad))
106 actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext))
107 actual_plaintext += decryptor.finalize()
108 assert actual_plaintext == binascii.unhexlify(plaintext)
109
110
Paul Kehrer4da28c32013-11-07 07:50:17 +0800111def generate_stream_encryption_test(param_loader, path, file_names,
Paul Kehrer783479c2013-12-26 21:08:45 -0600112 cipher_factory):
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800113 all_params = _load_all_params(path, file_names, param_loader)
114
115 @pytest.mark.parametrize("params", all_params)
116 def test_stream_encryption(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -0600117 stream_encryption_test(backend, cipher_factory, params)
Paul Kehrer4da28c32013-11-07 07:50:17 +0800118 return test_stream_encryption
119
120
Paul Kehrer783479c2013-12-26 21:08:45 -0600121def stream_encryption_test(backend, cipher_factory, params):
Paul Kehrera620b7d2013-12-20 22:59:02 -0600122 plaintext = params["plaintext"]
123 ciphertext = params["ciphertext"]
124 offset = params["offset"]
Alex Gaynor21919e22013-12-13 08:56:32 -0800125 cipher = Cipher(cipher_factory(**params), None, backend=backend)
126 encryptor = cipher.encryptor()
127 # throw away offset bytes
128 encryptor.update(b"\x00" * int(offset))
129 actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext))
130 actual_ciphertext += encryptor.finalize()
131 assert actual_ciphertext == binascii.unhexlify(ciphertext)
132 decryptor = cipher.decryptor()
133 decryptor.update(b"\x00" * int(offset))
134 actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext))
135 actual_plaintext += decryptor.finalize()
136 assert actual_plaintext == binascii.unhexlify(plaintext)
137
138
Paul Kehrer783479c2013-12-26 21:08:45 -0600139def generate_hash_test(param_loader, path, file_names, hash_cls):
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800140 all_params = _load_all_params(path, file_names, param_loader)
Paul Kehrer4da28c32013-11-07 07:50:17 +0800141
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800142 @pytest.mark.parametrize("params", all_params)
143 def test_hash(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -0600144 hash_test(backend, hash_cls, params)
Paul Kehrerbde6fb52013-10-18 18:08:49 -0500145 return test_hash
146
147
Paul Kehrer783479c2013-12-26 21:08:45 -0600148def hash_test(backend, algorithm, params):
Alex Gaynor36e651c2014-01-27 10:08:35 -0800149 msg, md = params
Alex Gaynor21919e22013-12-13 08:56:32 -0800150 m = hashes.Hash(algorithm, backend=backend)
151 m.update(binascii.unhexlify(msg))
152 expected_md = md.replace(" ", "").lower().encode("ascii")
153 assert m.finalize() == binascii.unhexlify(expected_md)
154
155
Paul Kehrerb078d8e2013-12-27 16:33:14 -0600156def generate_base_hash_test(algorithm, digest_size, block_size):
157 def test_base_hash(self, backend):
158 base_hash_test(backend, algorithm, digest_size, block_size)
159 return test_base_hash
160
161
Paul Kehrer783479c2013-12-26 21:08:45 -0600162def base_hash_test(backend, algorithm, digest_size, block_size):
Alex Gaynor21919e22013-12-13 08:56:32 -0800163 m = hashes.Hash(algorithm, backend=backend)
164 assert m.algorithm.digest_size == digest_size
165 assert m.algorithm.block_size == block_size
166 m_copy = m.copy()
167 assert m != m_copy
168 assert m._ctx != m_copy._ctx
169
170 m.update(b"abc")
171 copy = m.copy()
172 copy.update(b"123")
173 m.update(b"123")
174 assert copy.finalize() == m.finalize()
175
176
Paul Kehrer783479c2013-12-26 21:08:45 -0600177def generate_long_string_hash_test(hash_factory, md):
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800178 def test_long_string_hash(self, backend):
Paul Kehrer783479c2013-12-26 21:08:45 -0600179 long_string_hash_test(backend, hash_factory, md)
Paul Kehrerc1794072013-10-18 21:42:57 -0500180 return test_long_string_hash
181
182
Paul Kehrer783479c2013-12-26 21:08:45 -0600183def long_string_hash_test(backend, algorithm, md):
Alex Gaynor21919e22013-12-13 08:56:32 -0800184 m = hashes.Hash(algorithm, backend=backend)
185 m.update(b"a" * 1000000)
186 assert m.finalize() == binascii.unhexlify(md.lower().encode("ascii"))
187
188
Paul Kehrerb078d8e2013-12-27 16:33:14 -0600189def generate_base_hmac_test(hash_cls):
190 def test_base_hmac(self, backend):
191 base_hmac_test(backend, hash_cls)
192 return test_base_hmac
193
194
195def base_hmac_test(backend, algorithm):
196 key = b"ab"
197 h = hmac.HMAC(binascii.unhexlify(key), algorithm, backend=backend)
198 h_copy = h.copy()
199 assert h != h_copy
200 assert h._ctx != h_copy._ctx
201
202
Paul Kehrer783479c2013-12-26 21:08:45 -0600203def generate_hmac_test(param_loader, path, file_names, algorithm):
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800204 all_params = _load_all_params(path, file_names, param_loader)
Paul Kehrer0317b042013-10-28 17:34:27 -0500205
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800206 @pytest.mark.parametrize("params", all_params)
207 def test_hmac(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -0600208 hmac_test(backend, algorithm, params)
Paul Kehrer0317b042013-10-28 17:34:27 -0500209 return test_hmac
210
211
Paul Kehrer783479c2013-12-26 21:08:45 -0600212def hmac_test(backend, algorithm, params):
Alex Gaynor36e651c2014-01-27 10:08:35 -0800213 msg, md, key = params
Alex Gaynor21919e22013-12-13 08:56:32 -0800214 h = hmac.HMAC(binascii.unhexlify(key), algorithm, backend=backend)
215 h.update(binascii.unhexlify(msg))
216 assert h.finalize() == binascii.unhexlify(md.encode("ascii"))
Paul Kehrer0317b042013-10-28 17:34:27 -0500217
Alex Gaynor21919e22013-12-13 08:56:32 -0800218
Paul Kehrer1050ddf2014-01-27 21:04:03 -0600219def generate_pbkdf2_test(param_loader, path, file_names, algorithm):
220 all_params = _load_all_params(path, file_names, param_loader)
221
222 @pytest.mark.parametrize("params", all_params)
223 def test_pbkdf2(self, backend, params):
224 pbkdf2_test(backend, algorithm, params)
225 return test_pbkdf2
226
227
228def pbkdf2_test(backend, algorithm, params):
229 # Password and salt can contain \0, which should be loaded as a null char.
230 # The NIST loader loads them as literal strings so we replace with the
231 # proper value.
Paul Kehrer1277bc72014-01-28 17:09:59 -0600232 kdf = PBKDF2HMAC(
Paul Kehrer1050ddf2014-01-27 21:04:03 -0600233 algorithm,
234 int(params["length"]),
235 params["salt"],
236 int(params["iterations"]),
237 backend
238 )
239 derived_key = kdf.derive(params["password"])
240 assert binascii.hexlify(derived_key) == params["derived_key"]
241
242
Paul Kehrer783479c2013-12-26 21:08:45 -0600243def generate_aead_exception_test(cipher_factory, mode_factory):
Alex Gaynor21919e22013-12-13 08:56:32 -0800244 def test_aead_exception(self, backend):
Paul Kehrer783479c2013-12-26 21:08:45 -0600245 aead_exception_test(backend, cipher_factory, mode_factory)
Paul Kehrerce9c6112013-11-22 14:10:59 -0600246 return test_aead_exception
Paul Kehrer22e80cb2013-11-20 21:27:00 -0600247
248
Paul Kehrer783479c2013-12-26 21:08:45 -0600249def aead_exception_test(backend, cipher_factory, mode_factory):
Alex Gaynor21919e22013-12-13 08:56:32 -0800250 cipher = Cipher(
251 cipher_factory(binascii.unhexlify(b"0" * 32)),
252 mode_factory(binascii.unhexlify(b"0" * 24)),
253 backend
254 )
255 encryptor = cipher.encryptor()
256 encryptor.update(b"a" * 16)
257 with pytest.raises(NotYetFinalized):
258 encryptor.tag
259 with pytest.raises(AlreadyUpdated):
260 encryptor.authenticate_additional_data(b"b" * 16)
261 encryptor.finalize()
262 with pytest.raises(AlreadyFinalized):
263 encryptor.authenticate_additional_data(b"b" * 16)
264 with pytest.raises(AlreadyFinalized):
265 encryptor.update(b"b" * 16)
266 with pytest.raises(AlreadyFinalized):
267 encryptor.finalize()
268 cipher = Cipher(
269 cipher_factory(binascii.unhexlify(b"0" * 32)),
270 mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16),
271 backend
272 )
273 decryptor = cipher.decryptor()
274 decryptor.update(b"a" * 16)
275 with pytest.raises(AttributeError):
276 decryptor.tag
Paul Kehrerb91221d2013-12-04 17:56:40 -0600277
Alex Gaynor21919e22013-12-13 08:56:32 -0800278
Paul Kehrer783479c2013-12-26 21:08:45 -0600279def generate_aead_tag_exception_test(cipher_factory, mode_factory):
Alex Gaynor21919e22013-12-13 08:56:32 -0800280 def test_aead_tag_exception(self, backend):
Paul Kehrer783479c2013-12-26 21:08:45 -0600281 aead_tag_exception_test(backend, cipher_factory, mode_factory)
Paul Kehrerb91221d2013-12-04 17:56:40 -0600282 return test_aead_tag_exception
Alex Gaynor21919e22013-12-13 08:56:32 -0800283
284
Paul Kehrer783479c2013-12-26 21:08:45 -0600285def aead_tag_exception_test(backend, cipher_factory, mode_factory):
Alex Gaynor21919e22013-12-13 08:56:32 -0800286 cipher = Cipher(
287 cipher_factory(binascii.unhexlify(b"0" * 32)),
288 mode_factory(binascii.unhexlify(b"0" * 24)),
289 backend
290 )
291 with pytest.raises(ValueError):
292 cipher.decryptor()
Alex Gaynor516b1ad2014-01-01 12:28:37 -0800293
Paul Kehrerf7b4ede2013-12-21 17:25:19 -0600294 with pytest.raises(ValueError):
Alex Gaynor516b1ad2014-01-01 12:28:37 -0800295 mode_factory(binascii.unhexlify(b"0" * 24), b"000")
296
Paul Kehrerf7b4ede2013-12-21 17:25:19 -0600297 cipher = Cipher(
298 cipher_factory(binascii.unhexlify(b"0" * 32)),
Alex Gaynor21919e22013-12-13 08:56:32 -0800299 mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16),
300 backend
301 )
302 with pytest.raises(ValueError):
303 cipher.encryptor()
David Reid66c9cd92014-01-20 16:05:53 -0800304
305
David Reid5443e9d2014-01-22 17:18:49 -0800306def hkdf_derive_test(backend, algorithm, params):
David Reid0d492db2014-01-27 17:05:49 -0800307 hkdf = HKDF(
David Reid66c9cd92014-01-20 16:05:53 -0800308 algorithm,
David Reid0d492db2014-01-27 17:05:49 -0800309 int(params["l"]),
310 salt=binascii.unhexlify(params["salt"]) or None,
311 info=binascii.unhexlify(params["info"]) or None,
David Reid66c9cd92014-01-20 16:05:53 -0800312 backend=backend
313 )
314
David Reid0d492db2014-01-27 17:05:49 -0800315 okm = hkdf.derive(binascii.unhexlify(params["ikm"]))
316
David Reid14367302014-01-27 16:33:31 -0800317 assert okm == binascii.unhexlify(params["okm"])
David Reid66c9cd92014-01-20 16:05:53 -0800318
319
David Reid5443e9d2014-01-22 17:18:49 -0800320def hkdf_extract_test(backend, algorithm, params):
David Reid0d492db2014-01-27 17:05:49 -0800321 hkdf = HKDF(
David Reid5443e9d2014-01-22 17:18:49 -0800322 algorithm,
David Reid0d492db2014-01-27 17:05:49 -0800323 int(params["l"]),
324 salt=binascii.unhexlify(params["salt"]) or None,
325 info=binascii.unhexlify(params["info"]) or None,
David Reid5443e9d2014-01-22 17:18:49 -0800326 backend=backend
327 )
328
David Reid0d492db2014-01-27 17:05:49 -0800329 prk = hkdf.extract(binascii.unhexlify(params["ikm"]))
330
David Reid14367302014-01-27 16:33:31 -0800331 assert prk == binascii.unhexlify(params["prk"])
David Reid5443e9d2014-01-22 17:18:49 -0800332
333
334def hkdf_expand_test(backend, algorithm, params):
David Reid0d492db2014-01-27 17:05:49 -0800335 hkdf = HKDF(
David Reid5443e9d2014-01-22 17:18:49 -0800336 algorithm,
David Reid14367302014-01-27 16:33:31 -0800337 int(params["l"]),
David Reid0d492db2014-01-27 17:05:49 -0800338 salt=binascii.unhexlify(params["salt"]) or None,
339 info=binascii.unhexlify(params["info"]) or None,
David Reid5443e9d2014-01-22 17:18:49 -0800340 backend=backend
341 )
342
David Reid0d492db2014-01-27 17:05:49 -0800343 okm = hkdf.expand(binascii.unhexlify(params["prk"]))
344
David Reid14367302014-01-27 16:33:31 -0800345 assert okm == binascii.unhexlify(params["okm"])
David Reid5443e9d2014-01-22 17:18:49 -0800346
347
David Reid66c9cd92014-01-20 16:05:53 -0800348def generate_hkdf_test(param_loader, path, file_names, algorithm):
349 all_params = _load_all_params(path, file_names, param_loader)
350
David Reid5443e9d2014-01-22 17:18:49 -0800351 all_tests = [hkdf_extract_test, hkdf_expand_test, hkdf_derive_test]
352
353 @pytest.mark.parametrize(
354 ("params", "hkdf_test"),
355 itertools.product(all_params, all_tests)
356 )
357 def test_hkdf(self, backend, params, hkdf_test):
David Reid66c9cd92014-01-20 16:05:53 -0800358 hkdf_test(backend, algorithm, params)
359
360 return test_hkdf