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