15ed17381da64a3e8c2c874a4cbc5251fe784396
[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 if (alg != PRF_FIPS_SHA1_160)
924 {
925 /* do partial append mode and check if key gets set correctly */
926 if (!prf->get_bytes(prf, seed, NULL))
927 {
928 goto failure;
929 }
930 if (!prf->set_key(prf, key))
931 {
932 goto failure;
933 }
934 }
935 /* allocated bytes */
936 if (!prf->allocate_bytes(prf, seed, &out))
937 {
938 goto failure;
939 }
940 if (out.len != prf->get_block_size(prf))
941 {
942 goto failure;
943 }
944 if (!memeq(vector->out, out.ptr, out.len))
945 {
946 goto failure;
947 }
948 /* bytes to existing buffer */
949 memset(out.ptr, 0, out.len);
950 if (vector->stateful)
951 {
952 if (!prf->set_key(prf, key))
953 {
954 goto failure;
955 }
956 }
957 if (!prf->get_bytes(prf, seed, out.ptr))
958 {
959 goto failure;
960 }
961 if (!memeq(vector->out, out.ptr, out.len))
962 {
963 goto failure;
964 }
965 /* bytes to existing buffer, using append mode */
966 if (alg != PRF_FIPS_SHA1_160 && seed.len > 2)
967 {
968 memset(out.ptr, 0, out.len);
969 if (vector->stateful)
970 {
971 if (!prf->set_key(prf, key))
972 {
973 goto failure;
974 }
975 }
976 if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL))
977 {
978 goto failure;
979 }
980 if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL))
981 {
982 goto failure;
983 }
984 if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
985 {
986 goto failure;
987 }
988 if (!memeq(vector->out, out.ptr, out.len))
989 {
990 goto failure;
991 }
992 }
993
994 failed = FALSE;
995 failure:
996 prf->destroy(prf);
997 chunk_free(&out);
998 if (failed)
999 {
1000 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1001 pseudo_random_function_names, alg, plugin_name, get_name(vector));
1002 break;
1003 }
1004 }
1005 enumerator->destroy(enumerator);
1006 if (!tested)
1007 {
1008 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1009 this->required ? "disabled" : "enabled ",
1010 pseudo_random_function_names, alg, plugin_name);
1011 return !this->required;
1012 }
1013 if (!failed)
1014 {
1015 if (speed)
1016 {
1017 *speed = bench_prf(this, alg, create);
1018 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1019 pseudo_random_function_names, alg, plugin_name, tested, *speed);
1020 }
1021 else
1022 {
1023 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1024 pseudo_random_function_names, alg, plugin_name, tested);
1025 }
1026 }
1027 return !failed;
1028 }
1029
1030 /**
1031 * Benchmark a RNG
1032 */
1033 static u_int bench_rng(private_crypto_tester_t *this,
1034 rng_quality_t quality, rng_constructor_t create)
1035 {
1036 rng_t *rng;
1037
1038 rng = create(quality);
1039 if (rng)
1040 {
1041 struct timespec start;
1042 chunk_t buf;
1043 u_int runs;
1044
1045 runs = 0;
1046 buf = chunk_alloc(this->bench_size);
1047 start_timing(&start);
1048 while (end_timing(&start) < this->bench_time)
1049 {
1050 if (!rng->get_bytes(rng, buf.len, buf.ptr))
1051 {
1052 runs = 0;
1053 break;
1054 }
1055 runs++;
1056 }
1057 free(buf.ptr);
1058 rng->destroy(rng);
1059
1060 return runs;
1061 }
1062 return 0;
1063 }
1064
1065 METHOD(crypto_tester_t, test_rng, bool,
1066 private_crypto_tester_t *this, rng_quality_t quality,
1067 rng_constructor_t create, u_int *speed, const char *plugin_name)
1068 {
1069 enumerator_t *enumerator;
1070 rng_test_vector_t *vector;
1071 bool failed = FALSE;
1072 u_int tested = 0;
1073
1074 if (!this->rng_true && quality == RNG_TRUE)
1075 {
1076 DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
1077 rng_quality_names, quality, plugin_name);
1078 return TRUE;
1079 }
1080
1081 enumerator = this->rng->create_enumerator(this->rng);
1082 while (enumerator->enumerate(enumerator, &vector))
1083 {
1084 chunk_t data = chunk_empty;
1085 rng_t *rng;
1086
1087 if (vector->quality != quality)
1088 {
1089 continue;
1090 }
1091
1092 tested++;
1093 failed = TRUE;
1094 rng = create(quality);
1095 if (!rng)
1096 {
1097 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1098 rng_quality_names, quality, plugin_name);
1099 break;
1100 }
1101
1102 /* allocated bytes */
1103 if (!rng->allocate_bytes(rng, vector->len, &data) ||
1104 data.len != vector->len ||
1105 !vector->test(vector->user, data))
1106 {
1107 goto failure;
1108 }
1109 /* write bytes into existing buffer */
1110 memset(data.ptr, 0, data.len);
1111 if (!rng->get_bytes(rng, vector->len, data.ptr))
1112 {
1113 goto failure;
1114 }
1115 if (!vector->test(vector->user, data))
1116 {
1117 goto failure;
1118 }
1119
1120 failed = FALSE;
1121 failure:
1122 rng->destroy(rng);
1123 chunk_free(&data);
1124 if (failed)
1125 {
1126 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1127 rng_quality_names, quality, plugin_name, get_name(vector));
1128 break;
1129 }
1130 }
1131 enumerator->destroy(enumerator);
1132 if (!tested)
1133 {
1134 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1135 this->required ? ", disabled" : "enabled ",
1136 rng_quality_names, quality, plugin_name);
1137 return !this->required;
1138 }
1139 if (!failed)
1140 {
1141 if (speed)
1142 {
1143 *speed = bench_rng(this, quality, create);
1144 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1145 rng_quality_names, quality, plugin_name, tested, *speed);
1146 }
1147 else
1148 {
1149 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1150 rng_quality_names, quality, plugin_name, tested);
1151 }
1152 }
1153 return !failed;
1154 }
1155
1156 METHOD(crypto_tester_t, add_crypter_vector, void,
1157 private_crypto_tester_t *this, crypter_test_vector_t *vector)
1158 {
1159 this->crypter->insert_last(this->crypter, vector);
1160 }
1161
1162 METHOD(crypto_tester_t, add_aead_vector, void,
1163 private_crypto_tester_t *this, aead_test_vector_t *vector)
1164 {
1165 this->aead->insert_last(this->aead, vector);
1166 }
1167
1168 METHOD(crypto_tester_t, add_signer_vector, void,
1169 private_crypto_tester_t *this, signer_test_vector_t *vector)
1170 {
1171 this->signer->insert_last(this->signer, vector);
1172 }
1173
1174 METHOD(crypto_tester_t, add_hasher_vector, void,
1175 private_crypto_tester_t *this, hasher_test_vector_t *vector)
1176 {
1177 this->hasher->insert_last(this->hasher, vector);
1178 }
1179
1180 METHOD(crypto_tester_t, add_prf_vector, void,
1181 private_crypto_tester_t *this, prf_test_vector_t *vector)
1182 {
1183 this->prf->insert_last(this->prf, vector);
1184 }
1185
1186 METHOD(crypto_tester_t, add_rng_vector, void,
1187 private_crypto_tester_t *this, rng_test_vector_t *vector)
1188 {
1189 this->rng->insert_last(this->rng, vector);
1190 }
1191
1192 METHOD(crypto_tester_t, destroy, void,
1193 private_crypto_tester_t *this)
1194 {
1195 this->crypter->destroy(this->crypter);
1196 this->aead->destroy(this->aead);
1197 this->signer->destroy(this->signer);
1198 this->hasher->destroy(this->hasher);
1199 this->prf->destroy(this->prf);
1200 this->rng->destroy(this->rng);
1201 free(this);
1202 }
1203
1204 /**
1205 * See header
1206 */
1207 crypto_tester_t *crypto_tester_create()
1208 {
1209 private_crypto_tester_t *this;
1210
1211 INIT(this,
1212 .public = {
1213 .test_crypter = _test_crypter,
1214 .test_aead = _test_aead,
1215 .test_signer = _test_signer,
1216 .test_hasher = _test_hasher,
1217 .test_prf = _test_prf,
1218 .test_rng = _test_rng,
1219 .add_crypter_vector = _add_crypter_vector,
1220 .add_aead_vector = _add_aead_vector,
1221 .add_signer_vector = _add_signer_vector,
1222 .add_hasher_vector = _add_hasher_vector,
1223 .add_prf_vector = _add_prf_vector,
1224 .add_rng_vector = _add_rng_vector,
1225 .destroy = _destroy,
1226 },
1227 .crypter = linked_list_create(),
1228 .aead = linked_list_create(),
1229 .signer = linked_list_create(),
1230 .hasher = linked_list_create(),
1231 .prf = linked_list_create(),
1232 .rng = linked_list_create(),
1233
1234 .required = lib->settings->get_bool(lib->settings,
1235 "%s.crypto_test.required", FALSE, lib->ns),
1236 .rng_true = lib->settings->get_bool(lib->settings,
1237 "%s.crypto_test.rng_true", FALSE, lib->ns),
1238 .bench_time = lib->settings->get_int(lib->settings,
1239 "%s.crypto_test.bench_time", 50, lib->ns),
1240 .bench_size = lib->settings->get_int(lib->settings,
1241 "%s.crypto_test.bench_size", 1024, lib->ns),
1242 );
1243
1244 /* enforce a block size of 16, should be fine for all algorithms */
1245 this->bench_size = this->bench_size / 16 * 16;
1246
1247 return &this->public;
1248 }