Moved data structures to new collections subfolder
[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 <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 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, with a reset */
750 memset(hash.ptr, 0, hash.len);
751 if (!hasher->get_hash(hasher, data, NULL))
752 {
753 goto failure;
754 }
755 if (!hasher->reset(hasher))
756 {
757 goto failure;
758 }
759 if (!hasher->get_hash(hasher, data, hash.ptr))
760 {
761 goto failure;
762 }
763 if (!memeq(vector->hash, hash.ptr, hash.len))
764 {
765 goto failure;
766 }
767 /* hasher to existing buffer, using append mode */
768 if (data.len > 2)
769 {
770 memset(hash.ptr, 0, hash.len);
771 if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL))
772 {
773 goto failure;
774 }
775 if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL))
776 {
777 goto failure;
778 }
779 if (!hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr))
780 {
781 goto failure;
782 }
783 if (!memeq(vector->hash, hash.ptr, hash.len))
784 {
785 goto failure;
786 }
787 }
788
789 failed = FALSE;
790 failure:
791 hasher->destroy(hasher);
792 chunk_free(&hash);
793 if (failed)
794 {
795 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
796 hash_algorithm_names, alg, plugin_name, get_name(vector));
797 break;
798 }
799 }
800 enumerator->destroy(enumerator);
801 if (!tested)
802 {
803 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
804 this->required ? "disabled" : "enabled ",
805 hash_algorithm_names, alg, plugin_name);
806 return !this->required;
807 }
808 if (!failed)
809 {
810 if (speed)
811 {
812 *speed = bench_hasher(this, alg, create);
813 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
814 hash_algorithm_names, alg, plugin_name, tested, *speed);
815 }
816 else
817 {
818 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
819 hash_algorithm_names, alg, plugin_name, tested);
820 }
821 }
822 return !failed;
823 }
824
825 /**
826 * Benchmark a PRF
827 */
828 static u_int bench_prf(private_crypto_tester_t *this,
829 pseudo_random_function_t alg, prf_constructor_t create)
830 {
831 prf_t *prf;
832
833 prf = create(alg);
834 if (prf)
835 {
836 char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)];
837 chunk_t buf;
838 struct timespec start;
839 u_int runs;
840
841 memset(key, 0x56, prf->get_block_size(prf));
842 if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf))))
843 {
844 prf->destroy(prf);
845 return 0;
846 }
847
848 buf = chunk_alloc(this->bench_size);
849 memset(buf.ptr, 0x34, buf.len);
850
851 runs = 0;
852 start_timing(&start);
853 while (end_timing(&start) < this->bench_time)
854 {
855 if (prf->get_bytes(prf, buf, bytes))
856 {
857 runs++;
858 }
859 }
860 free(buf.ptr);
861 prf->destroy(prf);
862
863 return runs;
864 }
865 return 0;
866 }
867
868 METHOD(crypto_tester_t, test_prf, bool,
869 private_crypto_tester_t *this, pseudo_random_function_t alg,
870 prf_constructor_t create, u_int *speed, const char *plugin_name)
871 {
872 enumerator_t *enumerator;
873 prf_test_vector_t *vector;
874 bool failed = FALSE;
875 u_int tested = 0;
876
877 enumerator = this->prf->create_enumerator(this->prf);
878 while (enumerator->enumerate(enumerator, &vector))
879 {
880 prf_t *prf;
881 chunk_t key, seed, out = chunk_empty;
882
883 if (vector->alg != alg)
884 {
885 continue;
886 }
887
888 tested++;
889 failed = TRUE;
890 prf = create(alg);
891 if (!prf)
892 {
893 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
894 pseudo_random_function_names, alg, plugin_name);
895 break;
896 }
897
898 key = chunk_create(vector->key, vector->key_size);
899 if (!prf->set_key(prf, key))
900 {
901 goto failure;
902 }
903 /* allocated bytes */
904 seed = chunk_create(vector->seed, vector->len);
905 if (!prf->allocate_bytes(prf, seed, &out))
906 {
907 goto failure;
908 }
909 if (out.len != prf->get_block_size(prf))
910 {
911 goto failure;
912 }
913 if (!memeq(vector->out, out.ptr, out.len))
914 {
915 goto failure;
916 }
917 /* bytes to existing buffer */
918 memset(out.ptr, 0, out.len);
919 if (vector->stateful)
920 {
921 if (!prf->set_key(prf, key))
922 {
923 goto failure;
924 }
925 }
926 if (!prf->get_bytes(prf, seed, out.ptr))
927 {
928 goto failure;
929 }
930 if (!memeq(vector->out, out.ptr, out.len))
931 {
932 goto failure;
933 }
934 /* bytes to existing buffer, using append mode */
935 if (seed.len > 2)
936 {
937 memset(out.ptr, 0, out.len);
938 if (vector->stateful)
939 {
940 if (!prf->set_key(prf, key))
941 {
942 goto failure;
943 }
944 }
945 if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL))
946 {
947 goto failure;
948 }
949 if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL))
950 {
951 goto failure;
952 }
953 if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
954 {
955 goto failure;
956 }
957 if (!memeq(vector->out, out.ptr, out.len))
958 {
959 goto failure;
960 }
961 }
962
963 failed = FALSE;
964 failure:
965 prf->destroy(prf);
966 chunk_free(&out);
967 if (failed)
968 {
969 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
970 pseudo_random_function_names, alg, plugin_name, get_name(vector));
971 break;
972 }
973 }
974 enumerator->destroy(enumerator);
975 if (!tested)
976 {
977 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
978 this->required ? "disabled" : "enabled ",
979 pseudo_random_function_names, alg, plugin_name);
980 return !this->required;
981 }
982 if (!failed)
983 {
984 if (speed)
985 {
986 *speed = bench_prf(this, alg, create);
987 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
988 pseudo_random_function_names, alg, plugin_name, tested, *speed);
989 }
990 else
991 {
992 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
993 pseudo_random_function_names, alg, plugin_name, tested);
994 }
995 }
996 return !failed;
997 }
998
999 /**
1000 * Benchmark a RNG
1001 */
1002 static u_int bench_rng(private_crypto_tester_t *this,
1003 rng_quality_t quality, rng_constructor_t create)
1004 {
1005 rng_t *rng;
1006
1007 rng = create(quality);
1008 if (rng)
1009 {
1010 struct timespec start;
1011 chunk_t buf;
1012 u_int runs;
1013
1014 runs = 0;
1015 buf = chunk_alloc(this->bench_size);
1016 start_timing(&start);
1017 while (end_timing(&start) < this->bench_time)
1018 {
1019 if (!rng->get_bytes(rng, buf.len, buf.ptr))
1020 {
1021 runs = 0;
1022 break;
1023 }
1024 runs++;
1025 }
1026 free(buf.ptr);
1027 rng->destroy(rng);
1028
1029 return runs;
1030 }
1031 return 0;
1032 }
1033
1034 METHOD(crypto_tester_t, test_rng, bool,
1035 private_crypto_tester_t *this, rng_quality_t quality,
1036 rng_constructor_t create, u_int *speed, const char *plugin_name)
1037 {
1038 enumerator_t *enumerator;
1039 rng_test_vector_t *vector;
1040 bool failed = FALSE;
1041 u_int tested = 0;
1042
1043 if (!this->rng_true && quality == RNG_TRUE)
1044 {
1045 DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
1046 rng_quality_names, quality, plugin_name);
1047 return TRUE;
1048 }
1049
1050 enumerator = this->rng->create_enumerator(this->rng);
1051 while (enumerator->enumerate(enumerator, &vector))
1052 {
1053 chunk_t data = chunk_empty;
1054 rng_t *rng;
1055
1056 if (vector->quality != quality)
1057 {
1058 continue;
1059 }
1060
1061 tested++;
1062 failed = TRUE;
1063 rng = create(quality);
1064 if (!rng)
1065 {
1066 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1067 rng_quality_names, quality, plugin_name);
1068 break;
1069 }
1070
1071 /* allocated bytes */
1072 if (!rng->allocate_bytes(rng, vector->len, &data) ||
1073 data.len != vector->len ||
1074 !vector->test(vector->user, data))
1075 {
1076 goto failure;
1077 }
1078 /* write bytes into existing buffer */
1079 memset(data.ptr, 0, data.len);
1080 if (!rng->get_bytes(rng, vector->len, data.ptr))
1081 {
1082 goto failure;
1083 }
1084 if (!vector->test(vector->user, data))
1085 {
1086 goto failure;
1087 }
1088
1089 failed = FALSE;
1090 failure:
1091 rng->destroy(rng);
1092 chunk_free(&data);
1093 if (failed)
1094 {
1095 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1096 rng_quality_names, quality, plugin_name, get_name(vector));
1097 break;
1098 }
1099 }
1100 enumerator->destroy(enumerator);
1101 if (!tested)
1102 {
1103 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1104 this->required ? ", disabled" : "enabled ",
1105 rng_quality_names, quality, plugin_name);
1106 return !this->required;
1107 }
1108 if (!failed)
1109 {
1110 if (speed)
1111 {
1112 *speed = bench_rng(this, quality, create);
1113 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1114 rng_quality_names, quality, plugin_name, tested, *speed);
1115 }
1116 else
1117 {
1118 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1119 rng_quality_names, quality, plugin_name, tested);
1120 }
1121 }
1122 return !failed;
1123 }
1124
1125 METHOD(crypto_tester_t, add_crypter_vector, void,
1126 private_crypto_tester_t *this, crypter_test_vector_t *vector)
1127 {
1128 this->crypter->insert_last(this->crypter, vector);
1129 }
1130
1131 METHOD(crypto_tester_t, add_aead_vector, void,
1132 private_crypto_tester_t *this, aead_test_vector_t *vector)
1133 {
1134 this->aead->insert_last(this->aead, vector);
1135 }
1136
1137 METHOD(crypto_tester_t, add_signer_vector, void,
1138 private_crypto_tester_t *this, signer_test_vector_t *vector)
1139 {
1140 this->signer->insert_last(this->signer, vector);
1141 }
1142
1143 METHOD(crypto_tester_t, add_hasher_vector, void,
1144 private_crypto_tester_t *this, hasher_test_vector_t *vector)
1145 {
1146 this->hasher->insert_last(this->hasher, vector);
1147 }
1148
1149 METHOD(crypto_tester_t, add_prf_vector, void,
1150 private_crypto_tester_t *this, prf_test_vector_t *vector)
1151 {
1152 this->prf->insert_last(this->prf, vector);
1153 }
1154
1155 METHOD(crypto_tester_t, add_rng_vector, void,
1156 private_crypto_tester_t *this, rng_test_vector_t *vector)
1157 {
1158 this->rng->insert_last(this->rng, vector);
1159 }
1160
1161 METHOD(crypto_tester_t, destroy, void,
1162 private_crypto_tester_t *this)
1163 {
1164 this->crypter->destroy(this->crypter);
1165 this->aead->destroy(this->aead);
1166 this->signer->destroy(this->signer);
1167 this->hasher->destroy(this->hasher);
1168 this->prf->destroy(this->prf);
1169 this->rng->destroy(this->rng);
1170 free(this);
1171 }
1172
1173 /**
1174 * See header
1175 */
1176 crypto_tester_t *crypto_tester_create()
1177 {
1178 private_crypto_tester_t *this;
1179
1180 INIT(this,
1181 .public = {
1182 .test_crypter = _test_crypter,
1183 .test_aead = _test_aead,
1184 .test_signer = _test_signer,
1185 .test_hasher = _test_hasher,
1186 .test_prf = _test_prf,
1187 .test_rng = _test_rng,
1188 .add_crypter_vector = _add_crypter_vector,
1189 .add_aead_vector = _add_aead_vector,
1190 .add_signer_vector = _add_signer_vector,
1191 .add_hasher_vector = _add_hasher_vector,
1192 .add_prf_vector = _add_prf_vector,
1193 .add_rng_vector = _add_rng_vector,
1194 .destroy = _destroy,
1195 },
1196 .crypter = linked_list_create(),
1197 .aead = linked_list_create(),
1198 .signer = linked_list_create(),
1199 .hasher = linked_list_create(),
1200 .prf = linked_list_create(),
1201 .rng = linked_list_create(),
1202
1203 .required = lib->settings->get_bool(lib->settings,
1204 "libstrongswan.crypto_test.required", FALSE),
1205 .rng_true = lib->settings->get_bool(lib->settings,
1206 "libstrongswan.crypto_test.rng_true", FALSE),
1207 .bench_time = lib->settings->get_int(lib->settings,
1208 "libstrongswan.crypto_test.bench_time", 50),
1209 .bench_size = lib->settings->get_int(lib->settings,
1210 "libstrongswan.crypto_test.bench_size", 1024),
1211 );
1212
1213 /* enforce a block size of 16, should be fine for all algorithms */
1214 this->bench_size = this->bench_size / 16 * 16;
1215
1216 return &this->public;
1217 }
1218