blob: e546fa7951da48897a32f33920b12d885c5a7f93 [file] [log] [blame]
Alex Gaynorbd458ae2013-10-16 11:59:30 -07001import binascii
2import os
3
4import pytest
5
Paul Kehrer22e80cb2013-11-20 21:27:00 -06006from cryptography.hazmat.primitives import hashes, hmac
Paul Kehrer1277bc72014-01-28 17:09:59 -06007from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
Paul Kehrer21dde562013-11-06 12:22:09 +08008from cryptography.hazmat.primitives.ciphers import Cipher
David Reid66c9cd92014-01-20 16:05:53 -08009from cryptography.hazmat.primitives.kdf.hkdf import hkdf_derive
10
Paul Kehrer22e80cb2013-11-20 21:27:00 -060011from cryptography.exceptions import (
Paul Kehrera4bfc082013-11-22 19:57:37 -060012 AlreadyFinalized, NotYetFinalized, AlreadyUpdated, InvalidTag,
Paul Kehrer22e80cb2013-11-20 21:27:00 -060013)
Alex Gaynorbd458ae2013-10-16 11:59:30 -070014
Paul Kehrerf7f6a9f2013-11-11 20:43:52 -060015from ...utils import load_vectors_from_file
16
Alex Gaynorbd458ae2013-10-16 11:59:30 -070017
Alex Gaynore5c5eec2013-12-13 08:10:20 -080018def _load_all_params(path, file_names, param_loader):
19 all_params = []
20 for file_name in file_names:
21 all_params.extend(
22 load_vectors_from_file(os.path.join(path, file_name), param_loader)
23 )
24 return all_params
25
Alex Gaynor4eec0bb2013-12-13 09:12:19 -080026
Alex Gaynor016eed12013-10-16 14:16:04 -070027def generate_encrypt_test(param_loader, path, file_names, cipher_factory,
Paul Kehrer783479c2013-12-26 21:08:45 -060028 mode_factory):
Alex Gaynore5c5eec2013-12-13 08:10:20 -080029 all_params = _load_all_params(path, file_names, param_loader)
30
31 @pytest.mark.parametrize("params", all_params)
32 def test_encryption(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -060033 encrypt_test(backend, cipher_factory, mode_factory, params)
Alex Gaynore5c5eec2013-12-13 08:10:20 -080034
Alex Gaynorbd458ae2013-10-16 11:59:30 -070035 return test_encryption
36
37
Paul Kehrer783479c2013-12-26 21:08:45 -060038def encrypt_test(backend, cipher_factory, mode_factory, params):
Paul Kehrera620b7d2013-12-20 22:59:02 -060039 plaintext = params["plaintext"]
40 ciphertext = params["ciphertext"]
Alex Gaynor21919e22013-12-13 08:56:32 -080041 cipher = Cipher(
42 cipher_factory(**params),
43 mode_factory(**params),
44 backend=backend
45 )
46 encryptor = cipher.encryptor()
47 actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext))
48 actual_ciphertext += encryptor.finalize()
49 assert actual_ciphertext == binascii.unhexlify(ciphertext)
50 decryptor = cipher.decryptor()
51 actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext))
52 actual_plaintext += decryptor.finalize()
53 assert actual_plaintext == binascii.unhexlify(plaintext)
54
55
Paul Kehrer22e80cb2013-11-20 21:27:00 -060056def generate_aead_test(param_loader, path, file_names, cipher_factory,
Paul Kehrer783479c2013-12-26 21:08:45 -060057 mode_factory):
Alex Gaynore5c5eec2013-12-13 08:10:20 -080058 all_params = _load_all_params(path, file_names, param_loader)
59
60 @pytest.mark.parametrize("params", all_params)
61 def test_aead(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -060062 aead_test(backend, cipher_factory, mode_factory, params)
Alex Gaynore5c5eec2013-12-13 08:10:20 -080063
Paul Kehrer22e80cb2013-11-20 21:27:00 -060064 return test_aead
65
66
Paul Kehrer783479c2013-12-26 21:08:45 -060067def aead_test(backend, cipher_factory, mode_factory, params):
Alex Gaynor21919e22013-12-13 08:56:32 -080068 if params.get("pt") is not None:
Paul Kehrera620b7d2013-12-20 22:59:02 -060069 plaintext = params["pt"]
70 ciphertext = params["ct"]
71 aad = params["aad"]
Alex Gaynor21919e22013-12-13 08:56:32 -080072 if params.get("fail") is True:
73 cipher = Cipher(
74 cipher_factory(binascii.unhexlify(params["key"])),
75 mode_factory(binascii.unhexlify(params["iv"]),
76 binascii.unhexlify(params["tag"])),
77 backend
78 )
79 decryptor = cipher.decryptor()
80 decryptor.authenticate_additional_data(binascii.unhexlify(aad))
81 actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext))
82 with pytest.raises(InvalidTag):
83 decryptor.finalize()
84 else:
85 cipher = Cipher(
86 cipher_factory(binascii.unhexlify(params["key"])),
87 mode_factory(binascii.unhexlify(params["iv"]), None),
88 backend
89 )
90 encryptor = cipher.encryptor()
91 encryptor.authenticate_additional_data(binascii.unhexlify(aad))
92 actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext))
93 actual_ciphertext += encryptor.finalize()
94 tag_len = len(params["tag"])
95 assert binascii.hexlify(encryptor.tag)[:tag_len] == params["tag"]
96 cipher = Cipher(
97 cipher_factory(binascii.unhexlify(params["key"])),
98 mode_factory(binascii.unhexlify(params["iv"]),
99 binascii.unhexlify(params["tag"])),
100 backend
101 )
102 decryptor = cipher.decryptor()
103 decryptor.authenticate_additional_data(binascii.unhexlify(aad))
104 actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext))
105 actual_plaintext += decryptor.finalize()
106 assert actual_plaintext == binascii.unhexlify(plaintext)
107
108
Paul Kehrer4da28c32013-11-07 07:50:17 +0800109def generate_stream_encryption_test(param_loader, path, file_names,
Paul Kehrer783479c2013-12-26 21:08:45 -0600110 cipher_factory):
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800111 all_params = _load_all_params(path, file_names, param_loader)
112
113 @pytest.mark.parametrize("params", all_params)
114 def test_stream_encryption(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -0600115 stream_encryption_test(backend, cipher_factory, params)
Paul Kehrer4da28c32013-11-07 07:50:17 +0800116 return test_stream_encryption
117
118
Paul Kehrer783479c2013-12-26 21:08:45 -0600119def stream_encryption_test(backend, cipher_factory, params):
Paul Kehrera620b7d2013-12-20 22:59:02 -0600120 plaintext = params["plaintext"]
121 ciphertext = params["ciphertext"]
122 offset = params["offset"]
Alex Gaynor21919e22013-12-13 08:56:32 -0800123 cipher = Cipher(cipher_factory(**params), None, backend=backend)
124 encryptor = cipher.encryptor()
125 # throw away offset bytes
126 encryptor.update(b"\x00" * int(offset))
127 actual_ciphertext = encryptor.update(binascii.unhexlify(plaintext))
128 actual_ciphertext += encryptor.finalize()
129 assert actual_ciphertext == binascii.unhexlify(ciphertext)
130 decryptor = cipher.decryptor()
131 decryptor.update(b"\x00" * int(offset))
132 actual_plaintext = decryptor.update(binascii.unhexlify(ciphertext))
133 actual_plaintext += decryptor.finalize()
134 assert actual_plaintext == binascii.unhexlify(plaintext)
135
136
Paul Kehrer783479c2013-12-26 21:08:45 -0600137def generate_hash_test(param_loader, path, file_names, hash_cls):
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800138 all_params = _load_all_params(path, file_names, param_loader)
Paul Kehrer4da28c32013-11-07 07:50:17 +0800139
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800140 @pytest.mark.parametrize("params", all_params)
141 def test_hash(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -0600142 hash_test(backend, hash_cls, params)
Paul Kehrerbde6fb52013-10-18 18:08:49 -0500143 return test_hash
144
145
Paul Kehrer783479c2013-12-26 21:08:45 -0600146def hash_test(backend, algorithm, params):
Alex Gaynor36e651c2014-01-27 10:08:35 -0800147 msg, md = params
Alex Gaynor21919e22013-12-13 08:56:32 -0800148 m = hashes.Hash(algorithm, backend=backend)
149 m.update(binascii.unhexlify(msg))
150 expected_md = md.replace(" ", "").lower().encode("ascii")
151 assert m.finalize() == binascii.unhexlify(expected_md)
152
153
Paul Kehrerb078d8e2013-12-27 16:33:14 -0600154def generate_base_hash_test(algorithm, digest_size, block_size):
155 def test_base_hash(self, backend):
156 base_hash_test(backend, algorithm, digest_size, block_size)
157 return test_base_hash
158
159
Paul Kehrer783479c2013-12-26 21:08:45 -0600160def base_hash_test(backend, algorithm, digest_size, block_size):
Alex Gaynor21919e22013-12-13 08:56:32 -0800161 m = hashes.Hash(algorithm, backend=backend)
162 assert m.algorithm.digest_size == digest_size
163 assert m.algorithm.block_size == block_size
164 m_copy = m.copy()
165 assert m != m_copy
166 assert m._ctx != m_copy._ctx
167
168 m.update(b"abc")
169 copy = m.copy()
170 copy.update(b"123")
171 m.update(b"123")
172 assert copy.finalize() == m.finalize()
173
174
Paul Kehrer783479c2013-12-26 21:08:45 -0600175def generate_long_string_hash_test(hash_factory, md):
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800176 def test_long_string_hash(self, backend):
Paul Kehrer783479c2013-12-26 21:08:45 -0600177 long_string_hash_test(backend, hash_factory, md)
Paul Kehrerc1794072013-10-18 21:42:57 -0500178 return test_long_string_hash
179
180
Paul Kehrer783479c2013-12-26 21:08:45 -0600181def long_string_hash_test(backend, algorithm, md):
Alex Gaynor21919e22013-12-13 08:56:32 -0800182 m = hashes.Hash(algorithm, backend=backend)
183 m.update(b"a" * 1000000)
184 assert m.finalize() == binascii.unhexlify(md.lower().encode("ascii"))
185
186
Paul Kehrerb078d8e2013-12-27 16:33:14 -0600187def generate_base_hmac_test(hash_cls):
188 def test_base_hmac(self, backend):
189 base_hmac_test(backend, hash_cls)
190 return test_base_hmac
191
192
193def base_hmac_test(backend, algorithm):
194 key = b"ab"
195 h = hmac.HMAC(binascii.unhexlify(key), algorithm, backend=backend)
196 h_copy = h.copy()
197 assert h != h_copy
198 assert h._ctx != h_copy._ctx
199
200
Paul Kehrer783479c2013-12-26 21:08:45 -0600201def generate_hmac_test(param_loader, path, file_names, algorithm):
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800202 all_params = _load_all_params(path, file_names, param_loader)
Paul Kehrer0317b042013-10-28 17:34:27 -0500203
Alex Gaynore5c5eec2013-12-13 08:10:20 -0800204 @pytest.mark.parametrize("params", all_params)
205 def test_hmac(self, backend, params):
Paul Kehrer783479c2013-12-26 21:08:45 -0600206 hmac_test(backend, algorithm, params)
Paul Kehrer0317b042013-10-28 17:34:27 -0500207 return test_hmac
208
209
Paul Kehrer783479c2013-12-26 21:08:45 -0600210def hmac_test(backend, algorithm, params):
Alex Gaynor36e651c2014-01-27 10:08:35 -0800211 msg, md, key = params
Alex Gaynor21919e22013-12-13 08:56:32 -0800212 h = hmac.HMAC(binascii.unhexlify(key), algorithm, backend=backend)
213 h.update(binascii.unhexlify(msg))
214 assert h.finalize() == binascii.unhexlify(md.encode("ascii"))
Paul Kehrer0317b042013-10-28 17:34:27 -0500215
Alex Gaynor21919e22013-12-13 08:56:32 -0800216
Paul Kehrer1050ddf2014-01-27 21:04:03 -0600217def generate_pbkdf2_test(param_loader, path, file_names, algorithm):
218 all_params = _load_all_params(path, file_names, param_loader)
219
220 @pytest.mark.parametrize("params", all_params)
221 def test_pbkdf2(self, backend, params):
222 pbkdf2_test(backend, algorithm, params)
223 return test_pbkdf2
224
225
226def pbkdf2_test(backend, algorithm, params):
227 # Password and salt can contain \0, which should be loaded as a null char.
228 # The NIST loader loads them as literal strings so we replace with the
229 # proper value.
Paul Kehrer1277bc72014-01-28 17:09:59 -0600230 kdf = PBKDF2HMAC(
Paul Kehrer1050ddf2014-01-27 21:04:03 -0600231 algorithm,
232 int(params["length"]),
233 params["salt"],
234 int(params["iterations"]),
235 backend
236 )
237 derived_key = kdf.derive(params["password"])
238 assert binascii.hexlify(derived_key) == params["derived_key"]
239
240
Paul Kehrer783479c2013-12-26 21:08:45 -0600241def generate_aead_exception_test(cipher_factory, mode_factory):
Alex Gaynor21919e22013-12-13 08:56:32 -0800242 def test_aead_exception(self, backend):
Paul Kehrer783479c2013-12-26 21:08:45 -0600243 aead_exception_test(backend, cipher_factory, mode_factory)
Paul Kehrerce9c6112013-11-22 14:10:59 -0600244 return test_aead_exception
Paul Kehrer22e80cb2013-11-20 21:27:00 -0600245
246
Paul Kehrer783479c2013-12-26 21:08:45 -0600247def aead_exception_test(backend, cipher_factory, mode_factory):
Alex Gaynor21919e22013-12-13 08:56:32 -0800248 cipher = Cipher(
249 cipher_factory(binascii.unhexlify(b"0" * 32)),
250 mode_factory(binascii.unhexlify(b"0" * 24)),
251 backend
252 )
253 encryptor = cipher.encryptor()
254 encryptor.update(b"a" * 16)
255 with pytest.raises(NotYetFinalized):
256 encryptor.tag
257 with pytest.raises(AlreadyUpdated):
258 encryptor.authenticate_additional_data(b"b" * 16)
259 encryptor.finalize()
260 with pytest.raises(AlreadyFinalized):
261 encryptor.authenticate_additional_data(b"b" * 16)
262 with pytest.raises(AlreadyFinalized):
263 encryptor.update(b"b" * 16)
264 with pytest.raises(AlreadyFinalized):
265 encryptor.finalize()
266 cipher = Cipher(
267 cipher_factory(binascii.unhexlify(b"0" * 32)),
268 mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16),
269 backend
270 )
271 decryptor = cipher.decryptor()
272 decryptor.update(b"a" * 16)
273 with pytest.raises(AttributeError):
274 decryptor.tag
Paul Kehrerb91221d2013-12-04 17:56:40 -0600275
Alex Gaynor21919e22013-12-13 08:56:32 -0800276
Paul Kehrer783479c2013-12-26 21:08:45 -0600277def generate_aead_tag_exception_test(cipher_factory, mode_factory):
Alex Gaynor21919e22013-12-13 08:56:32 -0800278 def test_aead_tag_exception(self, backend):
Paul Kehrer783479c2013-12-26 21:08:45 -0600279 aead_tag_exception_test(backend, cipher_factory, mode_factory)
Paul Kehrerb91221d2013-12-04 17:56:40 -0600280 return test_aead_tag_exception
Alex Gaynor21919e22013-12-13 08:56:32 -0800281
282
Paul Kehrer783479c2013-12-26 21:08:45 -0600283def aead_tag_exception_test(backend, cipher_factory, mode_factory):
Alex Gaynor21919e22013-12-13 08:56:32 -0800284 cipher = Cipher(
285 cipher_factory(binascii.unhexlify(b"0" * 32)),
286 mode_factory(binascii.unhexlify(b"0" * 24)),
287 backend
288 )
289 with pytest.raises(ValueError):
290 cipher.decryptor()
Alex Gaynor516b1ad2014-01-01 12:28:37 -0800291
Paul Kehrerf7b4ede2013-12-21 17:25:19 -0600292 with pytest.raises(ValueError):
Alex Gaynor516b1ad2014-01-01 12:28:37 -0800293 mode_factory(binascii.unhexlify(b"0" * 24), b"000")
294
Paul Kehrerf7b4ede2013-12-21 17:25:19 -0600295 cipher = Cipher(
296 cipher_factory(binascii.unhexlify(b"0" * 32)),
Alex Gaynor21919e22013-12-13 08:56:32 -0800297 mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16),
298 backend
299 )
300 with pytest.raises(ValueError):
301 cipher.encryptor()
David Reid66c9cd92014-01-20 16:05:53 -0800302
303
304def hkdf_test(backend, algorithm, params):
305 ikm = params[0]
306 salt = params[1]
307 info = params[2]
308 length = params[3]
309 expected_okm = params[4]
310
311 okm = hkdf_derive(
312 binascii.unhexlify(ikm),
313 length,
314 binascii.unhexlify(salt),
315 binascii.unhexlify(info),
316 algorithm,
317 backend=backend
318 )
319
320 assert binascii.hexlify(okm) == expected_okm
321
322
323def generate_hkdf_test(param_loader, path, file_names, algorithm):
324 all_params = _load_all_params(path, file_names, param_loader)
325
326 @pytest.mark.parametrize("params", all_params)
327 def test_hkdf(self, backend, params):
328 hkdf_test(backend, algorithm, params)
329
330 return test_hkdf