ikev2: Recreate a CHILD_SA that got a hard lifetime expire without rekeying
[strongswan.git] / src / libstrongswan / crypto / crypto_tester.c
1 /*
2 * Copyright (C) 2009-2010 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2010 revosec AG
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #define _GNU_SOURCE
18 #include <dlfcn.h>
19 #include <time.h>
20
21 #include "crypto_tester.h"
22
23 #include <utils/debug.h>
24 #include <collections/linked_list.h>
25
26 typedef struct private_crypto_tester_t private_crypto_tester_t;
27
28 /**
29 * Private data of an crypto_tester_t object.
30 */
31 struct private_crypto_tester_t {
32
33 /**
34 * Public crypto_tester_t interface.
35 */
36 crypto_tester_t public;
37
38 /**
39 * List of crypter test vectors
40 */
41 linked_list_t *crypter;
42
43 /**
44 * List of aead test vectors
45 */
46 linked_list_t *aead;
47
48 /**
49 * List of signer test vectors
50 */
51 linked_list_t *signer;
52
53 /**
54 * List of hasher test vectors
55 */
56 linked_list_t *hasher;
57
58 /**
59 * List of PRF test vectors
60 */
61 linked_list_t *prf;
62
63 /**
64 * List of RNG test vectors
65 */
66 linked_list_t *rng;
67
68 /**
69 * Is a test vector required to pass a test?
70 */
71 bool required;
72
73 /**
74 * should we run RNG_TRUE tests? Enough entropy?
75 */
76 bool rng_true;
77
78 /**
79 * time we test each algorithm
80 */
81 int bench_time;
82
83 /**
84 * size of buffer we use for benchmarking
85 */
86 int bench_size;
87 };
88
89 /**
90 * Get the name of a test vector, if available
91 */
92 static const char* get_name(void *sym)
93 {
94 #ifdef HAVE_DLADDR
95 Dl_info dli;
96
97 if (dladdr(sym, &dli))
98 {
99 return dli.dli_sname;
100 }
101 #endif
102 return "unknown";
103 }
104
105 #ifdef CLOCK_THREAD_CPUTIME_ID
106
107 /**
108 * Start a benchmark timer
109 */
110 static void start_timing(struct timespec *start)
111 {
112 clock_gettime(CLOCK_THREAD_CPUTIME_ID, start);
113 }
114
115 /**
116 * End a benchmark timer, return ms
117 */
118 static u_int end_timing(struct timespec *start)
119 {
120 struct timespec end;
121
122 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
123 return (end.tv_nsec - start->tv_nsec) / 1000000 +
124 (end.tv_sec - start->tv_sec) * 1000;
125 }
126
127 #else /* CLOCK_THREAD_CPUTIME_ID */
128
129 /* Make benchmarking a no-op if CLOCK_THREAD_CPUTIME_ID is not available */
130 #define start_timing(start) ((start)->tv_sec = 0, (start)->tv_nsec = 0)
131 #define end_timing(...) (this->bench_time)
132
133 #endif /* CLOCK_THREAD_CPUTIME_ID */
134
135 /**
136 * Benchmark a crypter
137 */
138 static u_int bench_crypter(private_crypto_tester_t *this,
139 encryption_algorithm_t alg, crypter_constructor_t create)
140 {
141 crypter_t *crypter;
142
143 crypter = create(alg, 0);
144 if (crypter)
145 {
146 char iv[crypter->get_iv_size(crypter)];
147 char key[crypter->get_key_size(crypter)];
148 chunk_t buf;
149 struct timespec start;
150 u_int runs;
151
152 memset(iv, 0x56, sizeof(iv));
153 memset(key, 0x12, sizeof(key));
154 if (!crypter->set_key(crypter, chunk_from_thing(key)))
155 {
156 return 0;
157 }
158
159 buf = chunk_alloc(this->bench_size);
160 memset(buf.ptr, 0x34, buf.len);
161
162 runs = 0;
163 start_timing(&start);
164 while (end_timing(&start) < this->bench_time)
165 {
166 if (crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL))
167 {
168 runs++;
169 }
170 if (crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL))
171 {
172 runs++;
173 }
174 }
175 free(buf.ptr);
176 crypter->destroy(crypter);
177
178 return runs;
179 }
180 return 0;
181 }
182
183 METHOD(crypto_tester_t, test_crypter, bool,
184 private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
185 crypter_constructor_t create, u_int *speed, const char *plugin_name)
186 {
187 enumerator_t *enumerator;
188 crypter_test_vector_t *vector;
189 bool failed = FALSE;
190 u_int tested = 0;
191
192 enumerator = this->crypter->create_enumerator(this->crypter);
193 while (enumerator->enumerate(enumerator, &vector))
194 {
195 crypter_t *crypter;
196 chunk_t key, iv, plain = chunk_empty, cipher = chunk_empty;
197
198 if (vector->alg != alg)
199 {
200 continue;
201 }
202 if (key_size && key_size != vector->key_size)
203 { /* test only vectors with a specific key size, if key size given */
204 continue;
205 }
206
207 crypter = create(alg, vector->key_size);
208 if (!crypter)
209 { /* key size not supported */
210 continue;
211 }
212 tested++;
213 failed = TRUE;
214
215 key = chunk_create(vector->key, crypter->get_key_size(crypter));
216 if (!crypter->set_key(crypter, key))
217 {
218 goto failure;
219 }
220 iv = chunk_create(vector->iv, crypter->get_iv_size(crypter));
221
222 /* allocated encryption */
223 plain = chunk_create(vector->plain, vector->len);
224 if (!crypter->encrypt(crypter, plain, iv, &cipher))
225 {
226 goto failure;
227 }
228 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
229 {
230 goto failure;
231 }
232 /* inline decryption */
233 if (!crypter->decrypt(crypter, cipher, iv, NULL))
234 {
235 goto failure;
236 }
237 if (!memeq(vector->plain, cipher.ptr, cipher.len))
238 {
239 goto failure;
240 }
241 /* allocated decryption */
242 if (!crypter->decrypt(crypter,
243 chunk_create(vector->cipher, vector->len), iv, &plain))
244 {
245 goto failure;
246 }
247 if (!memeq(vector->plain, plain.ptr, plain.len))
248 {
249 goto failure;
250 }
251 /* inline encryption */
252 if (!crypter->encrypt(crypter, plain, iv, NULL))
253 {
254 goto failure;
255 }
256 if (!memeq(vector->cipher, plain.ptr, plain.len))
257 {
258 goto failure;
259 }
260
261 failed = FALSE;
262 failure:
263 crypter->destroy(crypter);
264 chunk_free(&cipher);
265 if (plain.ptr != vector->plain)
266 {
267 chunk_free(&plain);
268 }
269 if (failed)
270 {
271 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
272 encryption_algorithm_names, alg, plugin_name, get_name(vector));
273 break;
274 }
275 }
276 enumerator->destroy(enumerator);
277 if (!tested)
278 {
279 if (failed)
280 {
281 DBG1(DBG_LIB,"disable %N[%s]: no key size supported",
282 encryption_algorithm_names, alg, plugin_name);
283 return FALSE;
284 }
285 else
286 {
287 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
288 this->required ? "disabled" : "enabled ",
289 encryption_algorithm_names, alg, plugin_name);
290 return !this->required;
291 }
292 }
293 if (!failed)
294 {
295 if (speed)
296 {
297 *speed = bench_crypter(this, alg, create);
298 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
299 encryption_algorithm_names, alg, plugin_name, tested, *speed);
300 }
301 else
302 {
303 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
304 encryption_algorithm_names, alg, plugin_name, tested);
305 }
306 }
307 return !failed;
308 }
309
310 /**
311 * Benchmark an aead transform
312 */
313 static u_int bench_aead(private_crypto_tester_t *this,
314 encryption_algorithm_t alg, aead_constructor_t create)
315 {
316 aead_t *aead;
317
318 aead = create(alg, 0);
319 if (aead)
320 {
321 char iv[aead->get_iv_size(aead)];
322 char key[aead->get_key_size(aead)];
323 char assoc[4];
324 chunk_t buf;
325 struct timespec start;
326 u_int runs;
327 size_t icv;
328
329 memset(iv, 0x56, sizeof(iv));
330 memset(key, 0x12, sizeof(key));
331 memset(assoc, 0x78, sizeof(assoc));
332 if (!aead->set_key(aead, chunk_from_thing(key)))
333 {
334 return 0;
335 }
336 icv = aead->get_icv_size(aead);
337
338 buf = chunk_alloc(this->bench_size + icv);
339 memset(buf.ptr, 0x34, buf.len);
340 buf.len -= icv;
341
342 runs = 0;
343 start_timing(&start);
344 while (end_timing(&start) < this->bench_time)
345 {
346 if (aead->encrypt(aead, buf, chunk_from_thing(assoc),
347 chunk_from_thing(iv), NULL))
348 {
349 runs += 2;
350 }
351 if (aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv),
352 chunk_from_thing(assoc), chunk_from_thing(iv), NULL))
353 {
354 runs += 2;
355 }
356 }
357 free(buf.ptr);
358 aead->destroy(aead);
359
360 return runs;
361 }
362 return 0;
363 }
364
365 METHOD(crypto_tester_t, test_aead, bool,
366 private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
367 aead_constructor_t create, u_int *speed, const char *plugin_name)
368 {
369 enumerator_t *enumerator;
370 aead_test_vector_t *vector;
371 bool failed = FALSE;
372 u_int tested = 0;
373
374 enumerator = this->aead->create_enumerator(this->aead);
375 while (enumerator->enumerate(enumerator, &vector))
376 {
377 aead_t *aead;
378 chunk_t key, iv, assoc, plain = chunk_empty, cipher = chunk_empty;
379 size_t icv;
380
381 if (vector->alg != alg)
382 {
383 continue;
384 }
385 if (key_size && key_size != vector->key_size)
386 { /* test only vectors with a specific key size, if key size given */
387 continue;
388 }
389
390 tested++;
391 failed = TRUE;
392 aead = create(alg, vector->key_size);
393 if (!aead)
394 {
395 DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
396 encryption_algorithm_names, alg, plugin_name,
397 BITS_PER_BYTE * vector->key_size);
398 continue;
399 }
400
401 key = chunk_create(vector->key, aead->get_key_size(aead));
402 if (!aead->set_key(aead, key))
403 {
404 goto failure;
405 }
406 iv = chunk_create(vector->iv, aead->get_iv_size(aead));
407 assoc = chunk_create(vector->adata, vector->alen);
408 icv = aead->get_icv_size(aead);
409
410 /* allocated encryption */
411 plain = chunk_create(vector->plain, vector->len);
412 if (!aead->encrypt(aead, plain, assoc, iv, &cipher))
413 {
414 goto failure;
415 }
416 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
417 {
418 goto failure;
419 }
420 /* inline decryption */
421 if (!aead->decrypt(aead, cipher, assoc, iv, NULL))
422 {
423 goto failure;
424 }
425 if (!memeq(vector->plain, cipher.ptr, cipher.len - icv))
426 {
427 goto failure;
428 }
429 /* allocated decryption */
430 if (!aead->decrypt(aead, chunk_create(vector->cipher, vector->len + icv),
431 assoc, iv, &plain))
432 {
433 goto failure;
434 }
435 if (!memeq(vector->plain, plain.ptr, plain.len))
436 {
437 goto failure;
438 }
439 plain.ptr = realloc(plain.ptr, plain.len + icv);
440 /* inline encryption */
441 if (!aead->encrypt(aead, plain, assoc, iv, NULL))
442 {
443 goto failure;
444 }
445 if (!memeq(vector->cipher, plain.ptr, plain.len + icv))
446 {
447 goto failure;
448 }
449
450 failed = FALSE;
451 failure:
452 aead->destroy(aead);
453 chunk_free(&cipher);
454 if (plain.ptr != vector->plain)
455 {
456 chunk_free(&plain);
457 }
458 if (failed)
459 {
460 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
461 encryption_algorithm_names, alg, plugin_name, get_name(vector));
462 break;
463 }
464 }
465 enumerator->destroy(enumerator);
466 if (!tested)
467 {
468 if (failed)
469 {
470 DBG1(DBG_LIB,"disable %N[%s]: no key size supported",
471 encryption_algorithm_names, alg, plugin_name);
472 return FALSE;
473 }
474 else
475 {
476 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
477 this->required ? "disabled" : "enabled ",
478 encryption_algorithm_names, alg, plugin_name);
479 return !this->required;
480 }
481 }
482 if (!failed)
483 {
484 if (speed)
485 {
486 *speed = bench_aead(this, alg, create);
487 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
488 encryption_algorithm_names, alg, plugin_name, tested, *speed);
489 }
490 else
491 {
492 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
493 encryption_algorithm_names, alg, plugin_name, tested);
494 }
495 }
496 return !failed;
497 }
498
499 /**
500 * Benchmark a signer
501 */
502 static u_int bench_signer(private_crypto_tester_t *this,
503 integrity_algorithm_t alg, signer_constructor_t create)
504 {
505 signer_t *signer;
506
507 signer = create(alg);
508 if (signer)
509 {
510 char key[signer->get_key_size(signer)];
511 char mac[signer->get_block_size(signer)];
512 chunk_t buf;
513 struct timespec start;
514 u_int runs;
515
516 memset(key, 0x12, sizeof(key));
517 if (!signer->set_key(signer, chunk_from_thing(key)))
518 {
519 return 0;
520 }
521
522 buf = chunk_alloc(this->bench_size);
523 memset(buf.ptr, 0x34, buf.len);
524
525 runs = 0;
526 start_timing(&start);
527 while (end_timing(&start) < this->bench_time)
528 {
529 if (signer->get_signature(signer, buf, mac))
530 {
531 runs++;
532 }
533 if (signer->verify_signature(signer, buf, chunk_from_thing(mac)))
534 {
535 runs++;
536 }
537 }
538 free(buf.ptr);
539 signer->destroy(signer);
540
541 return runs;
542 }
543 return 0;
544 }
545
546 METHOD(crypto_tester_t, test_signer, bool,
547 private_crypto_tester_t *this, integrity_algorithm_t alg,
548 signer_constructor_t create, u_int *speed, const char *plugin_name)
549 {
550 enumerator_t *enumerator;
551 signer_test_vector_t *vector;
552 bool failed = FALSE;
553 u_int tested = 0;
554
555 enumerator = this->signer->create_enumerator(this->signer);
556 while (enumerator->enumerate(enumerator, &vector))
557 {
558 signer_t *signer;
559 chunk_t key, data, mac = chunk_empty;
560
561 if (vector->alg != alg)
562 {
563 continue;
564 }
565
566 tested++;
567 failed = TRUE;
568 signer = create(alg);
569 if (!signer)
570 {
571 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
572 integrity_algorithm_names, alg, plugin_name);
573 break;
574 }
575
576 key = chunk_create(vector->key, signer->get_key_size(signer));
577 if (!signer->set_key(signer, key))
578 {
579 goto failure;
580 }
581 /* allocated signature */
582 data = chunk_create(vector->data, vector->len);
583 if (!signer->allocate_signature(signer, data, &mac))
584 {
585 goto failure;
586 }
587 if (mac.len != signer->get_block_size(signer))
588 {
589 goto failure;
590 }
591 if (!memeq(vector->mac, mac.ptr, mac.len))
592 {
593 goto failure;
594 }
595 /* signature to existing buffer */
596 memset(mac.ptr, 0, mac.len);
597 if (!signer->get_signature(signer, data, mac.ptr))
598 {
599 goto failure;
600 }
601 if (!memeq(vector->mac, mac.ptr, mac.len))
602 {
603 goto failure;
604 }
605 /* signature verification, good case */
606 if (!signer->verify_signature(signer, data, mac))
607 {
608 goto failure;
609 }
610 /* signature verification, bad case */
611 *(mac.ptr + mac.len - 1) += 1;
612 if (signer->verify_signature(signer, data, mac))
613 {
614 goto failure;
615 }
616 /* signature to existing buffer, using append mode */
617 if (data.len > 2)
618 {
619 if (!signer->allocate_signature(signer,
620 chunk_create(data.ptr, 1), NULL))
621 {
622 goto failure;
623 }
624 if (!signer->get_signature(signer,
625 chunk_create(data.ptr + 1, 1), NULL))
626 {
627 goto failure;
628 }
629 if (!signer->verify_signature(signer, chunk_skip(data, 2),
630 chunk_create(vector->mac, mac.len)))
631 {
632 goto failure;
633 }
634 }
635
636 failed = FALSE;
637 failure:
638 signer->destroy(signer);
639 chunk_free(&mac);
640 if (failed)
641 {
642 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
643 integrity_algorithm_names, alg, plugin_name, get_name(vector));
644 break;
645 }
646 }
647 enumerator->destroy(enumerator);
648 if (!tested)
649 {
650 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
651 this->required ? "disabled" : "enabled ",
652 integrity_algorithm_names, alg, plugin_name);
653 return !this->required;
654 }
655 if (!failed)
656 {
657 if (speed)
658 {
659 *speed = bench_signer(this, alg, create);
660 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
661 integrity_algorithm_names, alg, plugin_name, tested, *speed);
662 }
663 else
664 {
665 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
666 integrity_algorithm_names, alg, plugin_name, tested);
667 }
668 }
669 return !failed;
670 }
671
672 /**
673 * Benchmark a hasher
674 */
675 static u_int bench_hasher(private_crypto_tester_t *this,
676 hash_algorithm_t alg, hasher_constructor_t create)
677 {
678 hasher_t *hasher;
679
680 hasher = create(alg);
681 if (hasher)
682 {
683 char hash[hasher->get_hash_size(hasher)];
684 chunk_t buf;
685 struct timespec start;
686 u_int runs;
687
688 buf = chunk_alloc(this->bench_size);
689 memset(buf.ptr, 0x34, buf.len);
690
691 runs = 0;
692 start_timing(&start);
693 while (end_timing(&start) < this->bench_time)
694 {
695 if (hasher->get_hash(hasher, buf, hash))
696 {
697 runs++;
698 }
699 }
700 free(buf.ptr);
701 hasher->destroy(hasher);
702
703 return runs;
704 }
705 return 0;
706 }
707
708 METHOD(crypto_tester_t, test_hasher, bool,
709 private_crypto_tester_t *this, hash_algorithm_t alg,
710 hasher_constructor_t create, u_int *speed, const char *plugin_name)
711 {
712 enumerator_t *enumerator;
713 hasher_test_vector_t *vector;
714 bool failed = FALSE;
715 u_int tested = 0;
716
717 enumerator = this->hasher->create_enumerator(this->hasher);
718 while (enumerator->enumerate(enumerator, &vector))
719 {
720 hasher_t *hasher;
721 chunk_t data, hash;
722
723 if (vector->alg != alg)
724 {
725 continue;
726 }
727
728 tested++;
729 failed = TRUE;
730 hasher = create(alg);
731 if (!hasher)
732 {
733 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
734 hash_algorithm_names, alg, plugin_name);
735 break;
736 }
737
738 /* allocated hash */
739 data = chunk_create(vector->data, vector->len);
740 if (!hasher->allocate_hash(hasher, data, &hash))
741 {
742 goto failure;
743 }
744 if (hash.len != hasher->get_hash_size(hasher))
745 {
746 goto failure;
747 }
748 if (!memeq(vector->hash, hash.ptr, hash.len))
749 {
750 goto failure;
751 }
752 /* hash to existing buffer, with a reset */
753 memset(hash.ptr, 0, hash.len);
754 if (!hasher->get_hash(hasher, data, NULL))
755 {
756 goto failure;
757 }
758 if (!hasher->reset(hasher))
759 {
760 goto failure;
761 }
762 if (!hasher->get_hash(hasher, data, hash.ptr))
763 {
764 goto failure;
765 }
766 if (!memeq(vector->hash, hash.ptr, hash.len))
767 {
768 goto failure;
769 }
770 /* hasher to existing buffer, using append mode */
771 if (data.len > 2)
772 {
773 memset(hash.ptr, 0, hash.len);
774 if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL))
775 {
776 goto failure;
777 }
778 if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL))
779 {
780 goto failure;
781 }
782 if (!hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr))
783 {
784 goto failure;
785 }
786 if (!memeq(vector->hash, hash.ptr, hash.len))
787 {
788 goto failure;
789 }
790 }
791
792 failed = FALSE;
793 failure:
794 hasher->destroy(hasher);
795 chunk_free(&hash);
796 if (failed)
797 {
798 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
799 hash_algorithm_names, alg, plugin_name, get_name(vector));
800 break;
801 }
802 }
803 enumerator->destroy(enumerator);
804 if (!tested)
805 {
806 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
807 this->required ? "disabled" : "enabled ",
808 hash_algorithm_names, alg, plugin_name);
809 return !this->required;
810 }
811 if (!failed)
812 {
813 if (speed)
814 {
815 *speed = bench_hasher(this, alg, create);
816 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
817 hash_algorithm_names, alg, plugin_name, tested, *speed);
818 }
819 else
820 {
821 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
822 hash_algorithm_names, alg, plugin_name, tested);
823 }
824 }
825 return !failed;
826 }
827
828 /**
829 * Benchmark a PRF
830 */
831 static u_int bench_prf(private_crypto_tester_t *this,
832 pseudo_random_function_t alg, prf_constructor_t create)
833 {
834 prf_t *prf;
835
836 prf = create(alg);
837 if (prf)
838 {
839 char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)];
840 chunk_t buf;
841 struct timespec start;
842 u_int runs;
843
844 memset(key, 0x56, prf->get_block_size(prf));
845 if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf))))
846 {
847 prf->destroy(prf);
848 return 0;
849 }
850
851 buf = chunk_alloc(this->bench_size);
852 memset(buf.ptr, 0x34, buf.len);
853
854 runs = 0;
855 start_timing(&start);
856 while (end_timing(&start) < this->bench_time)
857 {
858 if (prf->get_bytes(prf, buf, bytes))
859 {
860 runs++;
861 }
862 }
863 free(buf.ptr);
864 prf->destroy(prf);
865
866 return runs;
867 }
868 return 0;
869 }
870
871 METHOD(crypto_tester_t, test_prf, bool,
872 private_crypto_tester_t *this, pseudo_random_function_t alg,
873 prf_constructor_t create, u_int *speed, const char *plugin_name)
874 {
875 enumerator_t *enumerator;
876 prf_test_vector_t *vector;
877 bool failed = FALSE;
878 u_int tested = 0;
879
880 enumerator = this->prf->create_enumerator(this->prf);
881 while (enumerator->enumerate(enumerator, &vector))
882 {
883 prf_t *prf;
884 chunk_t key, seed, out = chunk_empty;
885
886 if (vector->alg != alg)
887 {
888 continue;
889 }
890
891 tested++;
892 failed = TRUE;
893 prf = create(alg);
894 if (!prf)
895 {
896 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
897 pseudo_random_function_names, alg, plugin_name);
898 break;
899 }
900
901 key = chunk_create(vector->key, vector->key_size);
902 if (!prf->set_key(prf, key))
903 {
904 goto failure;
905 }
906 /* allocated bytes */
907 seed = chunk_create(vector->seed, vector->len);
908 if (!prf->allocate_bytes(prf, seed, &out))
909 {
910 goto failure;
911 }
912 if (out.len != prf->get_block_size(prf))
913 {
914 goto failure;
915 }
916 if (!memeq(vector->out, out.ptr, out.len))
917 {
918 goto failure;
919 }
920 /* bytes to existing buffer */
921 memset(out.ptr, 0, out.len);
922 if (vector->stateful)
923 {
924 if (!prf->set_key(prf, key))
925 {
926 goto failure;
927 }
928 }
929 if (!prf->get_bytes(prf, seed, out.ptr))
930 {
931 goto failure;
932 }
933 if (!memeq(vector->out, out.ptr, out.len))
934 {
935 goto failure;
936 }
937 /* bytes to existing buffer, using append mode */
938 if (seed.len > 2)
939 {
940 memset(out.ptr, 0, out.len);
941 if (vector->stateful)
942 {
943 if (!prf->set_key(prf, key))
944 {
945 goto failure;
946 }
947 }
948 if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL))
949 {
950 goto failure;
951 }
952 if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL))
953 {
954 goto failure;
955 }
956 if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
957 {
958 goto failure;
959 }
960 if (!memeq(vector->out, out.ptr, out.len))
961 {
962 goto failure;
963 }
964 }
965
966 failed = FALSE;
967 failure:
968 prf->destroy(prf);
969 chunk_free(&out);
970 if (failed)
971 {
972 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
973 pseudo_random_function_names, alg, plugin_name, get_name(vector));
974 break;
975 }
976 }
977 enumerator->destroy(enumerator);
978 if (!tested)
979 {
980 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
981 this->required ? "disabled" : "enabled ",
982 pseudo_random_function_names, alg, plugin_name);
983 return !this->required;
984 }
985 if (!failed)
986 {
987 if (speed)
988 {
989 *speed = bench_prf(this, alg, create);
990 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
991 pseudo_random_function_names, alg, plugin_name, tested, *speed);
992 }
993 else
994 {
995 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
996 pseudo_random_function_names, alg, plugin_name, tested);
997 }
998 }
999 return !failed;
1000 }
1001
1002 /**
1003 * Benchmark a RNG
1004 */
1005 static u_int bench_rng(private_crypto_tester_t *this,
1006 rng_quality_t quality, rng_constructor_t create)
1007 {
1008 rng_t *rng;
1009
1010 rng = create(quality);
1011 if (rng)
1012 {
1013 struct timespec start;
1014 chunk_t buf;
1015 u_int runs;
1016
1017 runs = 0;
1018 buf = chunk_alloc(this->bench_size);
1019 start_timing(&start);
1020 while (end_timing(&start) < this->bench_time)
1021 {
1022 if (!rng->get_bytes(rng, buf.len, buf.ptr))
1023 {
1024 runs = 0;
1025 break;
1026 }
1027 runs++;
1028 }
1029 free(buf.ptr);
1030 rng->destroy(rng);
1031
1032 return runs;
1033 }
1034 return 0;
1035 }
1036
1037 METHOD(crypto_tester_t, test_rng, bool,
1038 private_crypto_tester_t *this, rng_quality_t quality,
1039 rng_constructor_t create, u_int *speed, const char *plugin_name)
1040 {
1041 enumerator_t *enumerator;
1042 rng_test_vector_t *vector;
1043 bool failed = FALSE;
1044 u_int tested = 0;
1045
1046 if (!this->rng_true && quality == RNG_TRUE)
1047 {
1048 DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
1049 rng_quality_names, quality, plugin_name);
1050 return TRUE;
1051 }
1052
1053 enumerator = this->rng->create_enumerator(this->rng);
1054 while (enumerator->enumerate(enumerator, &vector))
1055 {
1056 chunk_t data = chunk_empty;
1057 rng_t *rng;
1058
1059 if (vector->quality != quality)
1060 {
1061 continue;
1062 }
1063
1064 tested++;
1065 failed = TRUE;
1066 rng = create(quality);
1067 if (!rng)
1068 {
1069 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1070 rng_quality_names, quality, plugin_name);
1071 break;
1072 }
1073
1074 /* allocated bytes */
1075 if (!rng->allocate_bytes(rng, vector->len, &data) ||
1076 data.len != vector->len ||
1077 !vector->test(vector->user, data))
1078 {
1079 goto failure;
1080 }
1081 /* write bytes into existing buffer */
1082 memset(data.ptr, 0, data.len);
1083 if (!rng->get_bytes(rng, vector->len, data.ptr))
1084 {
1085 goto failure;
1086 }
1087 if (!vector->test(vector->user, data))
1088 {
1089 goto failure;
1090 }
1091
1092 failed = FALSE;
1093 failure:
1094 rng->destroy(rng);
1095 chunk_free(&data);
1096 if (failed)
1097 {
1098 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1099 rng_quality_names, quality, plugin_name, get_name(vector));
1100 break;
1101 }
1102 }
1103 enumerator->destroy(enumerator);
1104 if (!tested)
1105 {
1106 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1107 this->required ? ", disabled" : "enabled ",
1108 rng_quality_names, quality, plugin_name);
1109 return !this->required;
1110 }
1111 if (!failed)
1112 {
1113 if (speed)
1114 {
1115 *speed = bench_rng(this, quality, create);
1116 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1117 rng_quality_names, quality, plugin_name, tested, *speed);
1118 }
1119 else
1120 {
1121 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1122 rng_quality_names, quality, plugin_name, tested);
1123 }
1124 }
1125 return !failed;
1126 }
1127
1128 METHOD(crypto_tester_t, add_crypter_vector, void,
1129 private_crypto_tester_t *this, crypter_test_vector_t *vector)
1130 {
1131 this->crypter->insert_last(this->crypter, vector);
1132 }
1133
1134 METHOD(crypto_tester_t, add_aead_vector, void,
1135 private_crypto_tester_t *this, aead_test_vector_t *vector)
1136 {
1137 this->aead->insert_last(this->aead, vector);
1138 }
1139
1140 METHOD(crypto_tester_t, add_signer_vector, void,
1141 private_crypto_tester_t *this, signer_test_vector_t *vector)
1142 {
1143 this->signer->insert_last(this->signer, vector);
1144 }
1145
1146 METHOD(crypto_tester_t, add_hasher_vector, void,
1147 private_crypto_tester_t *this, hasher_test_vector_t *vector)
1148 {
1149 this->hasher->insert_last(this->hasher, vector);
1150 }
1151
1152 METHOD(crypto_tester_t, add_prf_vector, void,
1153 private_crypto_tester_t *this, prf_test_vector_t *vector)
1154 {
1155 this->prf->insert_last(this->prf, vector);
1156 }
1157
1158 METHOD(crypto_tester_t, add_rng_vector, void,
1159 private_crypto_tester_t *this, rng_test_vector_t *vector)
1160 {
1161 this->rng->insert_last(this->rng, vector);
1162 }
1163
1164 METHOD(crypto_tester_t, destroy, void,
1165 private_crypto_tester_t *this)
1166 {
1167 this->crypter->destroy(this->crypter);
1168 this->aead->destroy(this->aead);
1169 this->signer->destroy(this->signer);
1170 this->hasher->destroy(this->hasher);
1171 this->prf->destroy(this->prf);
1172 this->rng->destroy(this->rng);
1173 free(this);
1174 }
1175
1176 /**
1177 * See header
1178 */
1179 crypto_tester_t *crypto_tester_create()
1180 {
1181 private_crypto_tester_t *this;
1182
1183 INIT(this,
1184 .public = {
1185 .test_crypter = _test_crypter,
1186 .test_aead = _test_aead,
1187 .test_signer = _test_signer,
1188 .test_hasher = _test_hasher,
1189 .test_prf = _test_prf,
1190 .test_rng = _test_rng,
1191 .add_crypter_vector = _add_crypter_vector,
1192 .add_aead_vector = _add_aead_vector,
1193 .add_signer_vector = _add_signer_vector,
1194 .add_hasher_vector = _add_hasher_vector,
1195 .add_prf_vector = _add_prf_vector,
1196 .add_rng_vector = _add_rng_vector,
1197 .destroy = _destroy,
1198 },
1199 .crypter = linked_list_create(),
1200 .aead = linked_list_create(),
1201 .signer = linked_list_create(),
1202 .hasher = linked_list_create(),
1203 .prf = linked_list_create(),
1204 .rng = linked_list_create(),
1205
1206 .required = lib->settings->get_bool(lib->settings,
1207 "%s.crypto_test.required", FALSE, lib->ns),
1208 .rng_true = lib->settings->get_bool(lib->settings,
1209 "%s.crypto_test.rng_true", FALSE, lib->ns),
1210 .bench_time = lib->settings->get_int(lib->settings,
1211 "%s.crypto_test.bench_time", 50, lib->ns),
1212 .bench_size = lib->settings->get_int(lib->settings,
1213 "%s.crypto_test.bench_size", 1024, lib->ns),
1214 );
1215
1216 /* enforce a block size of 16, should be fine for all algorithms */
1217 this->bench_size = this->bench_size / 16 * 16;
1218
1219 return &this->public;
1220 }
1221