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