4fe10e74f5a4dca9fff5d9a6a596a91e1e8355c0
[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 <debug.h>
24 #include <utils/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 tested++;
208 failed = TRUE;
209 crypter = create(alg, vector->key_size);
210 if (!crypter)
211 {
212 DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
213 encryption_algorithm_names, alg, plugin_name,
214 BITS_PER_BYTE * vector->key_size);
215 continue;
216 }
217
218 key = chunk_create(vector->key, crypter->get_key_size(crypter));
219 if (!crypter->set_key(crypter, key))
220 {
221 goto failure;
222 }
223 iv = chunk_create(vector->iv, crypter->get_iv_size(crypter));
224
225 /* allocated encryption */
226 plain = chunk_create(vector->plain, vector->len);
227 if (!crypter->encrypt(crypter, plain, iv, &cipher))
228 {
229 goto failure;
230 }
231 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
232 {
233 goto failure;
234 }
235 /* inline decryption */
236 if (!crypter->decrypt(crypter, cipher, iv, NULL))
237 {
238 goto failure;
239 }
240 if (!memeq(vector->plain, cipher.ptr, cipher.len))
241 {
242 goto failure;
243 }
244 /* allocated decryption */
245 if (!crypter->decrypt(crypter,
246 chunk_create(vector->cipher, vector->len), iv, &plain))
247 {
248 goto failure;
249 }
250 if (!memeq(vector->plain, plain.ptr, plain.len))
251 {
252 goto failure;
253 }
254 /* inline encryption */
255 if (!crypter->encrypt(crypter, plain, iv, NULL))
256 {
257 goto failure;
258 }
259 if (!memeq(vector->cipher, plain.ptr, plain.len))
260 {
261 goto failure;
262 }
263
264 failed = FALSE;
265 failure:
266 crypter->destroy(crypter);
267 chunk_free(&cipher);
268 chunk_free(&plain);
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 chunk_free(&plain);
455 if (failed)
456 {
457 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
458 encryption_algorithm_names, alg, plugin_name, get_name(vector));
459 break;
460 }
461 }
462 enumerator->destroy(enumerator);
463 if (!tested)
464 {
465 if (failed)
466 {
467 DBG1(DBG_LIB,"disable %N[%s]: no key size supported",
468 encryption_algorithm_names, alg, plugin_name);
469 return FALSE;
470 }
471 else
472 {
473 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
474 this->required ? "disabled" : "enabled ",
475 encryption_algorithm_names, alg, plugin_name);
476 return !this->required;
477 }
478 }
479 if (!failed)
480 {
481 if (speed)
482 {
483 *speed = bench_aead(this, alg, create);
484 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
485 encryption_algorithm_names, alg, plugin_name, tested, *speed);
486 }
487 else
488 {
489 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
490 encryption_algorithm_names, alg, plugin_name, tested);
491 }
492 }
493 return !failed;
494 }
495
496 /**
497 * Benchmark a signer
498 */
499 static u_int bench_signer(private_crypto_tester_t *this,
500 integrity_algorithm_t alg, signer_constructor_t create)
501 {
502 signer_t *signer;
503
504 signer = create(alg);
505 if (signer)
506 {
507 char key[signer->get_key_size(signer)];
508 char mac[signer->get_block_size(signer)];
509 chunk_t buf;
510 struct timespec start;
511 u_int runs;
512
513 memset(key, 0x12, sizeof(key));
514 if (!signer->set_key(signer, chunk_from_thing(key)))
515 {
516 return 0;
517 }
518
519 buf = chunk_alloc(this->bench_size);
520 memset(buf.ptr, 0x34, buf.len);
521
522 runs = 0;
523 start_timing(&start);
524 while (end_timing(&start) < this->bench_time)
525 {
526 if (signer->get_signature(signer, buf, mac))
527 {
528 runs++;
529 }
530 if (signer->verify_signature(signer, buf, chunk_from_thing(mac)))
531 {
532 runs++;
533 }
534 }
535 free(buf.ptr);
536 signer->destroy(signer);
537
538 return runs;
539 }
540 return 0;
541 }
542
543 METHOD(crypto_tester_t, test_signer, bool,
544 private_crypto_tester_t *this, integrity_algorithm_t alg,
545 signer_constructor_t create, u_int *speed, const char *plugin_name)
546 {
547 enumerator_t *enumerator;
548 signer_test_vector_t *vector;
549 bool failed = FALSE;
550 u_int tested = 0;
551
552 enumerator = this->signer->create_enumerator(this->signer);
553 while (enumerator->enumerate(enumerator, &vector))
554 {
555 signer_t *signer;
556 chunk_t key, data, mac = chunk_empty;
557
558 if (vector->alg != alg)
559 {
560 continue;
561 }
562
563 tested++;
564 failed = TRUE;
565 signer = create(alg);
566 if (!signer)
567 {
568 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
569 integrity_algorithm_names, alg, plugin_name);
570 break;
571 }
572
573 key = chunk_create(vector->key, signer->get_key_size(signer));
574 if (!signer->set_key(signer, key))
575 {
576 goto failure;
577 }
578 /* allocated signature */
579 data = chunk_create(vector->data, vector->len);
580 if (!signer->allocate_signature(signer, data, &mac))
581 {
582 goto failure;
583 }
584 if (mac.len != signer->get_block_size(signer))
585 {
586 goto failure;
587 }
588 if (!memeq(vector->mac, mac.ptr, mac.len))
589 {
590 goto failure;
591 }
592 /* signature to existing buffer */
593 memset(mac.ptr, 0, mac.len);
594 if (!signer->get_signature(signer, data, mac.ptr))
595 {
596 goto failure;
597 }
598 if (!memeq(vector->mac, mac.ptr, mac.len))
599 {
600 goto failure;
601 }
602 /* signature verification, good case */
603 if (!signer->verify_signature(signer, data, mac))
604 {
605 goto failure;
606 }
607 /* signature verification, bad case */
608 *(mac.ptr + mac.len - 1) += 1;
609 if (signer->verify_signature(signer, data, mac))
610 {
611 goto failure;
612 }
613 /* signature to existing buffer, using append mode */
614 if (data.len > 2)
615 {
616 if (!signer->allocate_signature(signer,
617 chunk_create(data.ptr, 1), NULL))
618 {
619 goto failure;
620 }
621 if (!signer->get_signature(signer,
622 chunk_create(data.ptr + 1, 1), NULL))
623 {
624 goto failure;
625 }
626 if (!signer->verify_signature(signer, chunk_skip(data, 2),
627 chunk_create(vector->mac, mac.len)))
628 {
629 goto failure;
630 }
631 }
632
633 failed = FALSE;
634 failure:
635 signer->destroy(signer);
636 chunk_free(&mac);
637 if (failed)
638 {
639 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
640 integrity_algorithm_names, alg, plugin_name, get_name(vector));
641 break;
642 }
643 }
644 enumerator->destroy(enumerator);
645 if (!tested)
646 {
647 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
648 this->required ? "disabled" : "enabled ",
649 integrity_algorithm_names, alg, plugin_name);
650 return !this->required;
651 }
652 if (!failed)
653 {
654 if (speed)
655 {
656 *speed = bench_signer(this, alg, create);
657 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
658 integrity_algorithm_names, alg, plugin_name, tested, *speed);
659 }
660 else
661 {
662 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
663 integrity_algorithm_names, alg, plugin_name, tested);
664 }
665 }
666 return !failed;
667 }
668
669 /**
670 * Benchmark a hasher
671 */
672 static u_int bench_hasher(private_crypto_tester_t *this,
673 hash_algorithm_t alg, hasher_constructor_t create)
674 {
675 hasher_t *hasher;
676
677 hasher = create(alg);
678 if (hasher)
679 {
680 char hash[hasher->get_hash_size(hasher)];
681 chunk_t buf;
682 struct timespec start;
683 u_int runs;
684
685 buf = chunk_alloc(this->bench_size);
686 memset(buf.ptr, 0x34, buf.len);
687
688 runs = 0;
689 start_timing(&start);
690 while (end_timing(&start) < this->bench_time)
691 {
692 if (hasher->get_hash(hasher, buf, hash))
693 {
694 runs++;
695 }
696 }
697 free(buf.ptr);
698 hasher->destroy(hasher);
699
700 return runs;
701 }
702 return 0;
703 }
704
705 METHOD(crypto_tester_t, test_hasher, bool,
706 private_crypto_tester_t *this, hash_algorithm_t alg,
707 hasher_constructor_t create, u_int *speed, const char *plugin_name)
708 {
709 enumerator_t *enumerator;
710 hasher_test_vector_t *vector;
711 bool failed = FALSE;
712 u_int tested = 0;
713
714 enumerator = this->hasher->create_enumerator(this->hasher);
715 while (enumerator->enumerate(enumerator, &vector))
716 {
717 hasher_t *hasher;
718 chunk_t data, hash;
719
720 if (vector->alg != alg)
721 {
722 continue;
723 }
724
725 tested++;
726 failed = TRUE;
727 hasher = create(alg);
728 if (!hasher)
729 {
730 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
731 hash_algorithm_names, alg, plugin_name);
732 break;
733 }
734
735 /* allocated hash */
736 data = chunk_create(vector->data, vector->len);
737 if (!hasher->allocate_hash(hasher, data, &hash))
738 {
739 goto failure;
740 }
741 if (hash.len != hasher->get_hash_size(hasher))
742 {
743 goto failure;
744 }
745 if (!memeq(vector->hash, hash.ptr, hash.len))
746 {
747 goto failure;
748 }
749 /* hash to existing buffer */
750 memset(hash.ptr, 0, hash.len);
751 if (!hasher->get_hash(hasher, data, hash.ptr))
752 {
753 goto failure;
754 }
755 if (!memeq(vector->hash, hash.ptr, hash.len))
756 {
757 goto failure;
758 }
759 /* hasher to existing buffer, using append mode */
760 if (data.len > 2)
761 {
762 memset(hash.ptr, 0, hash.len);
763 if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL))
764 {
765 goto failure;
766 }
767 if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL))
768 {
769 goto failure;
770 }
771 if (!hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr))
772 {
773 goto failure;
774 }
775 if (!memeq(vector->hash, hash.ptr, hash.len))
776 {
777 goto failure;
778 }
779 }
780
781 failed = FALSE;
782 failure:
783 hasher->destroy(hasher);
784 chunk_free(&hash);
785 if (failed)
786 {
787 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
788 hash_algorithm_names, alg, plugin_name, get_name(vector));
789 break;
790 }
791 }
792 enumerator->destroy(enumerator);
793 if (!tested)
794 {
795 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
796 this->required ? "disabled" : "enabled ",
797 hash_algorithm_names, alg, plugin_name);
798 return !this->required;
799 }
800 if (!failed)
801 {
802 if (speed)
803 {
804 *speed = bench_hasher(this, alg, create);
805 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
806 hash_algorithm_names, alg, plugin_name, tested, *speed);
807 }
808 else
809 {
810 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
811 hash_algorithm_names, alg, plugin_name, tested);
812 }
813 }
814 return !failed;
815 }
816
817 /**
818 * Benchmark a PRF
819 */
820 static u_int bench_prf(private_crypto_tester_t *this,
821 pseudo_random_function_t alg, prf_constructor_t create)
822 {
823 prf_t *prf;
824
825 prf = create(alg);
826 if (prf)
827 {
828 char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)];
829 chunk_t buf;
830 struct timespec start;
831 u_int runs;
832
833 memset(key, 0x56, prf->get_block_size(prf));
834 if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf))))
835 {
836 prf->destroy(prf);
837 return 0;
838 }
839
840 buf = chunk_alloc(this->bench_size);
841 memset(buf.ptr, 0x34, buf.len);
842
843 runs = 0;
844 start_timing(&start);
845 while (end_timing(&start) < this->bench_time)
846 {
847 if (prf->get_bytes(prf, buf, bytes))
848 {
849 runs++;
850 }
851 }
852 free(buf.ptr);
853 prf->destroy(prf);
854
855 return runs;
856 }
857 return 0;
858 }
859
860 METHOD(crypto_tester_t, test_prf, bool,
861 private_crypto_tester_t *this, pseudo_random_function_t alg,
862 prf_constructor_t create, u_int *speed, const char *plugin_name)
863 {
864 enumerator_t *enumerator;
865 prf_test_vector_t *vector;
866 bool failed = FALSE;
867 u_int tested = 0;
868
869 enumerator = this->prf->create_enumerator(this->prf);
870 while (enumerator->enumerate(enumerator, &vector))
871 {
872 prf_t *prf;
873 chunk_t key, seed, out = chunk_empty;
874
875 if (vector->alg != alg)
876 {
877 continue;
878 }
879
880 tested++;
881 failed = TRUE;
882 prf = create(alg);
883 if (!prf)
884 {
885 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
886 pseudo_random_function_names, alg, plugin_name);
887 break;
888 }
889
890 key = chunk_create(vector->key, vector->key_size);
891 if (!prf->set_key(prf, key))
892 {
893 goto failure;
894 }
895 /* allocated bytes */
896 seed = chunk_create(vector->seed, vector->len);
897 if (!prf->allocate_bytes(prf, seed, &out))
898 {
899 goto failure;
900 }
901 if (out.len != prf->get_block_size(prf))
902 {
903 goto failure;
904 }
905 if (!memeq(vector->out, out.ptr, out.len))
906 {
907 goto failure;
908 }
909 /* bytes to existing buffer */
910 memset(out.ptr, 0, out.len);
911 if (vector->stateful)
912 {
913 if (!prf->set_key(prf, key))
914 {
915 goto failure;
916 }
917 }
918 if (!prf->get_bytes(prf, seed, out.ptr))
919 {
920 goto failure;
921 }
922 if (!memeq(vector->out, out.ptr, out.len))
923 {
924 goto failure;
925 }
926 /* bytes to existing buffer, using append mode */
927 if (seed.len > 2)
928 {
929 memset(out.ptr, 0, out.len);
930 if (vector->stateful)
931 {
932 if (!prf->set_key(prf, key))
933 {
934 goto failure;
935 }
936 }
937 if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL))
938 {
939 goto failure;
940 }
941 if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL))
942 {
943 goto failure;
944 }
945 if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
946 {
947 goto failure;
948 }
949 if (!memeq(vector->out, out.ptr, out.len))
950 {
951 goto failure;
952 }
953 }
954
955 failed = FALSE;
956 failure:
957 prf->destroy(prf);
958 chunk_free(&out);
959 if (failed)
960 {
961 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
962 pseudo_random_function_names, alg, plugin_name, get_name(vector));
963 break;
964 }
965 }
966 enumerator->destroy(enumerator);
967 if (!tested)
968 {
969 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
970 this->required ? "disabled" : "enabled ",
971 pseudo_random_function_names, alg, plugin_name);
972 return !this->required;
973 }
974 if (!failed)
975 {
976 if (speed)
977 {
978 *speed = bench_prf(this, alg, create);
979 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
980 pseudo_random_function_names, alg, plugin_name, tested, *speed);
981 }
982 else
983 {
984 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
985 pseudo_random_function_names, alg, plugin_name, tested);
986 }
987 }
988 return !failed;
989 }
990
991 /**
992 * Benchmark a RNG
993 */
994 static u_int bench_rng(private_crypto_tester_t *this,
995 rng_quality_t quality, rng_constructor_t create)
996 {
997 rng_t *rng;
998
999 rng = create(quality);
1000 if (rng)
1001 {
1002 struct timespec start;
1003 chunk_t buf;
1004 u_int runs;
1005
1006 runs = 0;
1007 buf = chunk_alloc(this->bench_size);
1008 start_timing(&start);
1009 while (end_timing(&start) < this->bench_time)
1010 {
1011 if (!rng->get_bytes(rng, buf.len, buf.ptr))
1012 {
1013 runs = 0;
1014 break;
1015 }
1016 runs++;
1017 }
1018 free(buf.ptr);
1019 rng->destroy(rng);
1020
1021 return runs;
1022 }
1023 return 0;
1024 }
1025
1026 METHOD(crypto_tester_t, test_rng, bool,
1027 private_crypto_tester_t *this, rng_quality_t quality,
1028 rng_constructor_t create, u_int *speed, const char *plugin_name)
1029 {
1030 enumerator_t *enumerator;
1031 rng_test_vector_t *vector;
1032 bool failed = FALSE;
1033 u_int tested = 0;
1034
1035 if (!this->rng_true && quality == RNG_TRUE)
1036 {
1037 DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
1038 rng_quality_names, quality, plugin_name);
1039 return TRUE;
1040 }
1041
1042 enumerator = this->rng->create_enumerator(this->rng);
1043 while (enumerator->enumerate(enumerator, &vector))
1044 {
1045 chunk_t data = chunk_empty;
1046 rng_t *rng;
1047
1048 if (vector->quality != quality)
1049 {
1050 continue;
1051 }
1052
1053 tested++;
1054 failed = TRUE;
1055 rng = create(quality);
1056 if (!rng)
1057 {
1058 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1059 rng_quality_names, quality, plugin_name);
1060 break;
1061 }
1062
1063 /* allocated bytes */
1064 if (!rng->allocate_bytes(rng, vector->len, &data) ||
1065 data.len != vector->len ||
1066 !vector->test(vector->user, data))
1067 {
1068 goto failure;
1069 }
1070 if (!failed)
1071 { /* write bytes into existing buffer */
1072 memset(data.ptr, 0, data.len);
1073 if (!rng->get_bytes(rng, vector->len, data.ptr))
1074 {
1075 goto failure;
1076 }
1077 if (!vector->test(vector->user, data))
1078 {
1079 goto failure;
1080 }
1081 }
1082
1083 failed = FALSE;
1084 failure:
1085 rng->destroy(rng);
1086 chunk_free(&data);
1087 if (failed)
1088 {
1089 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1090 rng_quality_names, quality, plugin_name, get_name(vector));
1091 break;
1092 }
1093 }
1094 enumerator->destroy(enumerator);
1095 if (!tested)
1096 {
1097 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1098 this->required ? ", disabled" : "enabled ",
1099 rng_quality_names, quality, plugin_name);
1100 return !this->required;
1101 }
1102 if (!failed)
1103 {
1104 if (speed)
1105 {
1106 *speed = bench_rng(this, quality, create);
1107 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1108 rng_quality_names, quality, plugin_name, tested, *speed);
1109 }
1110 else
1111 {
1112 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1113 rng_quality_names, quality, plugin_name, tested);
1114 }
1115 }
1116 return !failed;
1117 }
1118
1119 METHOD(crypto_tester_t, add_crypter_vector, void,
1120 private_crypto_tester_t *this, crypter_test_vector_t *vector)
1121 {
1122 this->crypter->insert_last(this->crypter, vector);
1123 }
1124
1125 METHOD(crypto_tester_t, add_aead_vector, void,
1126 private_crypto_tester_t *this, aead_test_vector_t *vector)
1127 {
1128 this->aead->insert_last(this->aead, vector);
1129 }
1130
1131 METHOD(crypto_tester_t, add_signer_vector, void,
1132 private_crypto_tester_t *this, signer_test_vector_t *vector)
1133 {
1134 this->signer->insert_last(this->signer, vector);
1135 }
1136
1137 METHOD(crypto_tester_t, add_hasher_vector, void,
1138 private_crypto_tester_t *this, hasher_test_vector_t *vector)
1139 {
1140 this->hasher->insert_last(this->hasher, vector);
1141 }
1142
1143 METHOD(crypto_tester_t, add_prf_vector, void,
1144 private_crypto_tester_t *this, prf_test_vector_t *vector)
1145 {
1146 this->prf->insert_last(this->prf, vector);
1147 }
1148
1149 METHOD(crypto_tester_t, add_rng_vector, void,
1150 private_crypto_tester_t *this, rng_test_vector_t *vector)
1151 {
1152 this->rng->insert_last(this->rng, vector);
1153 }
1154
1155 METHOD(crypto_tester_t, destroy, void,
1156 private_crypto_tester_t *this)
1157 {
1158 this->crypter->destroy(this->crypter);
1159 this->aead->destroy(this->aead);
1160 this->signer->destroy(this->signer);
1161 this->hasher->destroy(this->hasher);
1162 this->prf->destroy(this->prf);
1163 this->rng->destroy(this->rng);
1164 free(this);
1165 }
1166
1167 /**
1168 * See header
1169 */
1170 crypto_tester_t *crypto_tester_create()
1171 {
1172 private_crypto_tester_t *this;
1173
1174 INIT(this,
1175 .public = {
1176 .test_crypter = _test_crypter,
1177 .test_aead = _test_aead,
1178 .test_signer = _test_signer,
1179 .test_hasher = _test_hasher,
1180 .test_prf = _test_prf,
1181 .test_rng = _test_rng,
1182 .add_crypter_vector = _add_crypter_vector,
1183 .add_aead_vector = _add_aead_vector,
1184 .add_signer_vector = _add_signer_vector,
1185 .add_hasher_vector = _add_hasher_vector,
1186 .add_prf_vector = _add_prf_vector,
1187 .add_rng_vector = _add_rng_vector,
1188 .destroy = _destroy,
1189 },
1190 .crypter = linked_list_create(),
1191 .aead = linked_list_create(),
1192 .signer = linked_list_create(),
1193 .hasher = linked_list_create(),
1194 .prf = linked_list_create(),
1195 .rng = linked_list_create(),
1196
1197 .required = lib->settings->get_bool(lib->settings,
1198 "libstrongswan.crypto_test.required", FALSE),
1199 .rng_true = lib->settings->get_bool(lib->settings,
1200 "libstrongswan.crypto_test.rng_true", FALSE),
1201 .bench_time = lib->settings->get_int(lib->settings,
1202 "libstrongswan.crypto_test.bench_time", 50),
1203 .bench_size = lib->settings->get_int(lib->settings,
1204 "libstrongswan.crypto_test.bench_size", 1024),
1205 );
1206
1207 /* enforce a block size of 16, should be fine for all algorithms */
1208 this->bench_size = this->bench_size / 16 * 16;
1209
1210 return &this->public;
1211 }
1212