4b8173402cf854d9b894419b28296eeca134012d
[strongswan.git] / src / libstrongswan / crypto / crypto_tester.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "crypto_tester.h"
17
18 #include <debug.h>
19 #include <utils/linked_list.h>
20
21 typedef struct private_crypto_tester_t private_crypto_tester_t;
22
23 /**
24 * Private data of an crypto_tester_t object.
25 */
26 struct private_crypto_tester_t {
27
28 /**
29 * Public crypto_tester_t interface.
30 */
31 crypto_tester_t public;
32
33 /**
34 * List of crypter test vectors
35 */
36 linked_list_t *crypter;
37
38 /**
39 * List of signer test vectors
40 */
41 linked_list_t *signer;
42
43 /**
44 * List of hasher test vectors
45 */
46 linked_list_t *hasher;
47
48 /**
49 * List of PRF test vectors
50 */
51 linked_list_t *prf;
52
53 /**
54 * List of RNG test vectors
55 */
56 linked_list_t *rng;
57
58 /**
59 * Is a test vector required to pass a test?
60 */
61 bool required;
62
63 /**
64 * should we run RNG_TRUE tests? Enough entropy?
65 */
66 bool rng_true;
67 };
68
69 /**
70 * Implementation of crypto_tester_t.test_crypter
71 */
72 static bool test_crypter(private_crypto_tester_t *this,
73 encryption_algorithm_t alg, size_t key_size, crypter_constructor_t create)
74 {
75 enumerator_t *enumerator;
76 crypter_test_vector_t *vector;
77 bool failed = FALSE;
78 u_int tested = 0;
79
80 enumerator = this->crypter->create_enumerator(this->crypter);
81 while (enumerator->enumerate(enumerator, &vector))
82 {
83 crypter_t *crypter;
84 chunk_t key, plain, cipher, iv;
85
86 if (vector->alg != alg)
87 {
88 continue;
89 }
90 if (key_size && key_size != vector->key_size)
91 { /* test only vectors with a specific key size, if key size given */
92 continue;
93 }
94 crypter = create(alg, vector->key_size);
95 if (!crypter)
96 { /* key size not supported... */
97 continue;
98 }
99
100 failed = FALSE;
101 tested++;
102
103 key = chunk_create(vector->key, crypter->get_key_size(crypter));
104 crypter->set_key(crypter, key);
105 iv = chunk_create(vector->iv, crypter->get_block_size(crypter));
106
107 /* allocated encryption */
108 plain = chunk_create(vector->plain, vector->len);
109 crypter->encrypt(crypter, plain, iv, &cipher);
110 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
111 {
112 failed = TRUE;
113 }
114 /* inline decryption */
115 crypter->decrypt(crypter, cipher, iv, NULL);
116 if (!memeq(vector->plain, cipher.ptr, cipher.len))
117 {
118 failed = TRUE;
119 }
120 free(cipher.ptr);
121 /* allocated decryption */
122 cipher = chunk_create(vector->cipher, vector->len);
123 crypter->decrypt(crypter, cipher, iv, &plain);
124 if (!memeq(vector->plain, plain.ptr, plain.len))
125 {
126 failed = TRUE;
127 }
128 /* inline encryption */
129 crypter->encrypt(crypter, plain, iv, NULL);
130 if (!memeq(vector->cipher, plain.ptr, plain.len))
131 {
132 failed = TRUE;
133 }
134 free(plain.ptr);
135
136 crypter->destroy(crypter);
137 if (failed)
138 {
139 DBG1("test vector %d failed, %N disabled",
140 tested, encryption_algorithm_names, alg);
141 break;
142 }
143 DBG2("%N test vector %d successful",
144 encryption_algorithm_names, alg, tested);
145 }
146 enumerator->destroy(enumerator);
147 if (!tested)
148 {
149 DBG1("no test vectors found for %N%s",
150 encryption_algorithm_names, alg,
151 this->required ? ", disabled" : "");
152 return !this->required;
153 }
154 if (!failed)
155 {
156 DBG2("successfully tested %d test vectors for %N",
157 tested, encryption_algorithm_names, alg);
158 }
159 return !failed;
160 }
161
162 /**
163 * Implementation of crypto_tester_t.test_signer
164 */
165 static bool test_signer(private_crypto_tester_t *this,
166 integrity_algorithm_t alg, signer_constructor_t create)
167 {
168 enumerator_t *enumerator;
169 signer_test_vector_t *vector;
170 bool failed = FALSE;
171 u_int tested = 0;
172
173 enumerator = this->signer->create_enumerator(this->signer);
174 while (enumerator->enumerate(enumerator, &vector))
175 {
176 signer_t *signer;
177 chunk_t key, data, mac;
178
179 if (vector->alg != alg)
180 {
181 continue;
182 }
183
184 tested++;
185 signer = create(alg);
186 if (!signer)
187 {
188 DBG1("creating instance failed, %N disabled",
189 integrity_algorithm_names, alg);
190 failed = TRUE;
191 break;
192 }
193
194 failed = FALSE;
195
196 key = chunk_create(vector->key, signer->get_key_size(signer));
197 signer->set_key(signer, key);
198
199 /* allocated signature */
200 data = chunk_create(vector->data, vector->len);
201 signer->allocate_signature(signer, data, &mac);
202 if (mac.len != signer->get_block_size(signer))
203 {
204 failed = TRUE;
205 }
206 if (!memeq(vector->mac, mac.ptr, mac.len))
207 {
208 failed = TRUE;
209 }
210 /* signature to existing buffer */
211 memset(mac.ptr, 0, mac.len);
212 signer->get_signature(signer, data, mac.ptr);
213 if (!memeq(vector->mac, mac.ptr, mac.len))
214 {
215 failed = TRUE;
216 }
217 /* signature verification, good case */
218 if (!signer->verify_signature(signer, data, mac))
219 {
220 failed = TRUE;
221 }
222 /* signature verification, bad case */
223 *(mac.ptr + mac.len - 1) += 1;
224 if (signer->verify_signature(signer, data, mac))
225 {
226 failed = TRUE;
227 }
228 /* signature to existing buffer, using append mode */
229 if (data.len > 2)
230 {
231 memset(mac.ptr, 0, mac.len);
232 signer->allocate_signature(signer, chunk_create(data.ptr, 1), NULL);
233 signer->get_signature(signer, chunk_create(data.ptr + 1, 1), NULL);
234 signer->get_signature(signer, chunk_skip(data, 2), mac.ptr);
235 if (!memeq(vector->mac, mac.ptr, mac.len))
236 {
237 failed = TRUE;
238 }
239 }
240 free(mac.ptr);
241
242 signer->destroy(signer);
243 if (failed)
244 {
245 DBG1("test vector %d failed, %N disabled",
246 tested, integrity_algorithm_names, alg);
247 break;
248 }
249 DBG2(" %N test vector %d successful",
250 integrity_algorithm_names, alg, tested);
251 }
252 enumerator->destroy(enumerator);
253 if (!tested)
254 {
255 DBG1("no test vectors found for %N%s",
256 integrity_algorithm_names, alg,
257 this->required ? ", disabled" : "");
258 return !this->required;
259 }
260 if (!failed)
261 {
262 DBG2("successfully tested %d test vectors for %N",
263 tested, integrity_algorithm_names, alg);
264 }
265 return !failed;
266 }
267
268 /**
269 * Implementation of hasher_t.test_hasher
270 */
271 static bool test_hasher(private_crypto_tester_t *this, hash_algorithm_t alg,
272 hasher_constructor_t create)
273 {
274 enumerator_t *enumerator;
275 hasher_test_vector_t *vector;
276 bool failed = FALSE;
277 u_int tested = 0;
278
279 enumerator = this->hasher->create_enumerator(this->hasher);
280 while (enumerator->enumerate(enumerator, &vector))
281 {
282 hasher_t *hasher;
283 chunk_t data, hash;
284
285 if (vector->alg != alg)
286 {
287 continue;
288 }
289
290 tested++;
291 hasher = create(alg);
292 if (!hasher)
293 {
294 DBG1("creating instance failed, %N disabled",
295 hash_algorithm_names, alg);
296 failed = TRUE;
297 break;
298 }
299
300 failed = FALSE;
301
302 /* allocated hash */
303 data = chunk_create(vector->data, vector->len);
304 hasher->allocate_hash(hasher, data, &hash);
305 if (hash.len != hasher->get_hash_size(hasher))
306 {
307 failed = TRUE;
308 }
309 if (!memeq(vector->hash, hash.ptr, hash.len))
310 {
311 failed = TRUE;
312 }
313 /* hash to existing buffer */
314 memset(hash.ptr, 0, hash.len);
315 hasher->get_hash(hasher, data, hash.ptr);
316 if (!memeq(vector->hash, hash.ptr, hash.len))
317 {
318 failed = TRUE;
319 }
320 /* hasher to existing buffer, using append mode */
321 if (data.len > 2)
322 {
323 memset(hash.ptr, 0, hash.len);
324 hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL);
325 hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL);
326 hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr);
327 if (!memeq(vector->hash, hash.ptr, hash.len))
328 {
329 failed = TRUE;
330 }
331 }
332 free(hash.ptr);
333
334 hasher->destroy(hasher);
335 if (failed)
336 {
337 DBG1("test vector %d failed, %N disabled",
338 tested, hash_algorithm_names, alg);
339 break;
340 }
341 DBG2("%N test vector %d successful",
342 hash_algorithm_names, alg, tested);
343 }
344 enumerator->destroy(enumerator);
345 if (!tested)
346 {
347 DBG1("no test vectors found for %N%s",
348 hash_algorithm_names, alg,
349 this->required ? ", disabled" : "");
350 return !this->required;
351 }
352 if (!failed)
353 {
354 DBG2("successfully tested %d test vectors for %N",
355 tested, hash_algorithm_names, alg);
356 }
357 return !failed;
358 }
359
360 /**
361 * Implementation of crypto_tester_t.test_prf
362 */
363 static bool test_prf(private_crypto_tester_t *this,
364 pseudo_random_function_t alg, prf_constructor_t create)
365 {
366 enumerator_t *enumerator;
367 prf_test_vector_t *vector;
368 bool failed = FALSE;
369 u_int tested = 0;
370
371 enumerator = this->prf->create_enumerator(this->prf);
372 while (enumerator->enumerate(enumerator, &vector))
373 {
374 prf_t *prf;
375 chunk_t key, seed, out;
376
377 if (vector->alg != alg)
378 {
379 continue;
380 }
381
382 tested++;
383 prf = create(alg);
384 if (!prf)
385 {
386 DBG1("creating instance failed, %N disabled",
387 pseudo_random_function_names, alg);
388 failed = TRUE;
389 break;
390 }
391
392 failed = FALSE;
393
394 key = chunk_create(vector->key, vector->key_size);
395 prf->set_key(prf, key);
396
397 /* allocated bytes */
398 seed = chunk_create(vector->seed, vector->len);
399 prf->allocate_bytes(prf, seed, &out);
400 if (out.len != prf->get_block_size(prf))
401 {
402 failed = TRUE;
403 }
404 if (!memeq(vector->out, out.ptr, out.len))
405 {
406 failed = TRUE;
407 }
408 /* bytes to existing buffer */
409 memset(out.ptr, 0, out.len);
410 prf->get_bytes(prf, seed, out.ptr);
411 if (!memeq(vector->out, out.ptr, out.len))
412 {
413 failed = TRUE;
414 }
415 /* bytes to existing buffer, using append mode */
416 if (seed.len > 2)
417 {
418 memset(out.ptr, 0, out.len);
419 prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL);
420 prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL);
421 prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr);
422 if (!memeq(vector->out, out.ptr, out.len))
423 {
424 failed = TRUE;
425 }
426 }
427 free(out.ptr);
428
429 prf->destroy(prf);
430 if (failed)
431 {
432 DBG1("test vector %d failed, %N disabled",
433 tested, pseudo_random_function_names, alg);
434 break;
435 }
436 DBG2("%N test vector %d successful",
437 pseudo_random_function_names, alg, tested);
438 }
439 enumerator->destroy(enumerator);
440 if (!tested)
441 {
442 DBG1("no test vectors found for %N%s",
443 pseudo_random_function_names, alg,
444 this->required ? ", disabled" : "");
445 return !this->required;
446 }
447 if (!failed)
448 {
449 DBG2("successfully tested %d testvectors for %N",
450 tested, pseudo_random_function_names, alg);
451 }
452 return !failed;
453 }
454
455 /**
456 * Implementation of crypto_tester_t.test_rng
457 */
458 static bool test_rng(private_crypto_tester_t *this, rng_quality_t quality,
459 rng_constructor_t create)
460 {
461 enumerator_t *enumerator;
462 rng_test_vector_t *vector;
463 bool failed = FALSE;
464 u_int tested = 0;
465
466 if (!this->rng_true && quality == RNG_TRUE)
467 {
468 DBG1("skipping %N test, disabled by config", rng_quality_names, quality);
469 return TRUE;
470 }
471
472 enumerator = this->rng->create_enumerator(this->rng);
473 while (enumerator->enumerate(enumerator, &vector))
474 {
475 rng_t *rng;
476 chunk_t data;
477
478 if (vector->quality != quality)
479 {
480 continue;
481 }
482
483 tested++;
484 rng = create(quality);
485 if (!rng)
486 {
487 DBG1("creating instance failed, %N disabled",
488 rng_quality_names, quality);
489 failed = TRUE;
490 break;
491 }
492
493 failed = FALSE;
494
495 /* allocated bytes */
496 rng->allocate_bytes(rng, vector->len, &data);
497 if (data.len != vector->len)
498 {
499 failed = TRUE;
500 }
501 if (!vector->test(vector->user, data))
502 {
503 failed = TRUE;
504 }
505 /* bytes to existing buffer */
506 memset(data.ptr, 0, data.len);
507 rng->get_bytes(rng, vector->len, data.ptr);
508 if (!vector->test(vector->user, data))
509 {
510 failed = TRUE;
511 }
512 free(data.ptr);
513
514 rng->destroy(rng);
515 if (failed)
516 {
517 DBG1("test vector %d failed, %N disabled",
518 tested, rng_quality_names, quality);
519 break;
520 }
521 DBG2("%N test vector %d successful", rng_quality_names, quality, tested);
522 }
523 enumerator->destroy(enumerator);
524 if (!tested)
525 {
526 DBG1("no test vectors found for %N%s",
527 rng_quality_names, quality, this->required ? ", disabled" : "");
528 return !this->required;
529 }
530 if (!failed)
531 {
532 DBG2("successfully tested %d testvectors for %N",
533 tested, rng_quality_names, quality);
534 }
535 return !failed;
536 }
537
538 /**
539 * Implementation of crypter_tester_t.add_crypter_vector
540 */
541 static void add_crypter_vector(private_crypto_tester_t *this,
542 crypter_test_vector_t *vector)
543 {
544 this->crypter->insert_last(this->crypter, vector);
545 }
546
547 /**
548 * Implementation of crypter_tester_t.add_signer_vector
549 */
550 static void add_signer_vector(private_crypto_tester_t *this,
551 signer_test_vector_t *vector)
552 {
553 this->signer->insert_last(this->signer, vector);
554 }
555
556 /**
557 * Implementation of crypter_tester_t.add_hasher_vector
558 */
559 static void add_hasher_vector(private_crypto_tester_t *this,
560 hasher_test_vector_t *vector)
561 {
562 this->hasher->insert_last(this->hasher, vector);
563 }
564
565 /**
566 * Implementation of crypter_tester_t.add_prf_vector
567 */
568 static void add_prf_vector(private_crypto_tester_t *this,
569 prf_test_vector_t *vector)
570 {
571 this->prf->insert_last(this->prf, vector);
572 }
573
574 /**
575 * Implementation of crypter_tester_t.add_rng_vector
576 */
577 static void add_rng_vector(private_crypto_tester_t *this,
578 rng_test_vector_t *vector)
579 {
580 this->rng->insert_last(this->rng, vector);
581 }
582
583 /**
584 * Implementation of crypto_tester_t.destroy.
585 */
586 static void destroy(private_crypto_tester_t *this)
587 {
588 this->crypter->destroy(this->crypter);
589 this->signer->destroy(this->signer);
590 this->hasher->destroy(this->hasher);
591 this->prf->destroy(this->prf);
592 this->rng->destroy(this->rng);
593 free(this);
594 }
595
596 /**
597 * See header
598 */
599 crypto_tester_t *crypto_tester_create()
600 {
601 private_crypto_tester_t *this = malloc_thing(private_crypto_tester_t);
602
603 this->public.test_crypter = (bool(*)(crypto_tester_t*, encryption_algorithm_t alg,size_t key_size, crypter_constructor_t create))test_crypter;
604 this->public.test_signer = (bool(*)(crypto_tester_t*, integrity_algorithm_t alg, signer_constructor_t create))test_signer;
605 this->public.test_hasher = (bool(*)(crypto_tester_t*, hash_algorithm_t alg, hasher_constructor_t create))test_hasher;
606 this->public.test_prf = (bool(*)(crypto_tester_t*, pseudo_random_function_t alg, prf_constructor_t create))test_prf;
607 this->public.test_rng = (bool(*)(crypto_tester_t*, rng_quality_t quality, rng_constructor_t create))test_rng;
608 this->public.add_crypter_vector = (void(*)(crypto_tester_t*, crypter_test_vector_t *vector))add_crypter_vector;
609 this->public.add_signer_vector = (void(*)(crypto_tester_t*, signer_test_vector_t *vector))add_signer_vector;
610 this->public.add_hasher_vector = (void(*)(crypto_tester_t*, hasher_test_vector_t *vector))add_hasher_vector;
611 this->public.add_prf_vector = (void(*)(crypto_tester_t*, prf_test_vector_t *vector))add_prf_vector;
612 this->public.add_rng_vector = (void(*)(crypto_tester_t*, rng_test_vector_t *vector))add_rng_vector;
613 this->public.destroy = (void(*)(crypto_tester_t*))destroy;
614
615 this->crypter = linked_list_create();
616 this->signer = linked_list_create();
617 this->hasher = linked_list_create();
618 this->prf = linked_list_create();
619 this->rng = linked_list_create();
620
621 this->required = lib->settings->get_bool(lib->settings,
622 "libstrongswan.crypto.test.required", FALSE);
623 this->rng_true = lib->settings->get_bool(lib->settings,
624 "libstrongswan.crypto.test.rng_true", FALSE);
625
626 return &this->public;
627 }
628