xof: Defined Extended Output Functions
[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 XOF test vectors
67 */
68 linked_list_t *xof;
69
70 /**
71 * List of RNG test vectors
72 */
73 linked_list_t *rng;
74
75 /**
76 * List of Diffie-Hellman test vectors
77 */
78 linked_list_t *dh;
79
80 /**
81 * Is a test vector required to pass a test?
82 */
83 bool required;
84
85 /**
86 * should we run RNG_TRUE tests? Enough entropy?
87 */
88 bool rng_true;
89
90 /**
91 * time we test each algorithm
92 */
93 int bench_time;
94
95 /**
96 * size of buffer we use for benchmarking
97 */
98 int bench_size;
99 };
100
101 /**
102 * Get the name of a test vector, if available
103 */
104 static const char* get_name(void *sym)
105 {
106 #ifdef HAVE_DLADDR
107 Dl_info dli;
108
109 if (dladdr(sym, &dli))
110 {
111 return dli.dli_sname;
112 }
113 #endif
114 return "unknown";
115 }
116
117 #if defined(CLOCK_THREAD_CPUTIME_ID) && defined(HAVE_CLOCK_GETTIME)
118
119 /**
120 * Start a benchmark timer
121 */
122 static void start_timing(struct timespec *start)
123 {
124 clock_gettime(CLOCK_THREAD_CPUTIME_ID, start);
125 }
126
127 /**
128 * End a benchmark timer, return ms
129 */
130 static u_int end_timing(struct timespec *start)
131 {
132 struct timespec end;
133
134 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
135 return (end.tv_nsec - start->tv_nsec) / 1000000 +
136 (end.tv_sec - start->tv_sec) * 1000;
137 }
138
139 #else /* CLOCK_THREAD_CPUTIME_ID */
140
141 /* Make benchmarking a no-op if CLOCK_THREAD_CPUTIME_ID is not available */
142 #define start_timing(start) ((start)->tv_sec = 0, (start)->tv_nsec = 0)
143 #define end_timing(...) (this->bench_time)
144
145 #endif /* CLOCK_THREAD_CPUTIME_ID */
146
147 /**
148 * Benchmark a crypter
149 */
150 static u_int bench_crypter(private_crypto_tester_t *this,
151 encryption_algorithm_t alg, crypter_constructor_t create, size_t key_size)
152 {
153 crypter_t *crypter;
154
155 crypter = create(alg, key_size);
156 if (crypter)
157 {
158 char iv[crypter->get_iv_size(crypter)];
159 char key[crypter->get_key_size(crypter)];
160 chunk_t buf;
161 struct timespec start;
162 u_int runs;
163
164 memset(iv, 0x56, sizeof(iv));
165 memset(key, 0x12, sizeof(key));
166 if (!crypter->set_key(crypter, chunk_from_thing(key)))
167 {
168 return 0;
169 }
170
171 buf = chunk_alloc(this->bench_size);
172 memset(buf.ptr, 0x34, buf.len);
173
174 runs = 0;
175 start_timing(&start);
176 while (end_timing(&start) < this->bench_time)
177 {
178 if (crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL))
179 {
180 runs++;
181 }
182 if (crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL))
183 {
184 runs++;
185 }
186 }
187 free(buf.ptr);
188 crypter->destroy(crypter);
189
190 return runs;
191 }
192 return 0;
193 }
194
195 METHOD(crypto_tester_t, test_crypter, bool,
196 private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
197 crypter_constructor_t create, u_int *speed, const char *plugin_name)
198 {
199 enumerator_t *enumerator;
200 crypter_test_vector_t *vector;
201 bool failed = FALSE;
202 u_int tested = 0;
203
204 enumerator = this->crypter->create_enumerator(this->crypter);
205 while (enumerator->enumerate(enumerator, &vector))
206 {
207 crypter_t *crypter;
208 chunk_t key, iv, plain = chunk_empty, cipher = chunk_empty;
209
210 if (vector->alg != alg)
211 {
212 continue;
213 }
214 if (key_size && key_size != vector->key_size)
215 { /* test only vectors with a specific key size, if key size given */
216 continue;
217 }
218
219 crypter = create(alg, vector->key_size);
220 if (!crypter)
221 { /* key size not supported */
222 continue;
223 }
224 tested++;
225 failed = TRUE;
226
227 key = chunk_create(vector->key, crypter->get_key_size(crypter));
228 if (!crypter->set_key(crypter, key))
229 {
230 goto failure;
231 }
232 iv = chunk_create(vector->iv, crypter->get_iv_size(crypter));
233
234 /* allocated encryption */
235 plain = chunk_create(vector->plain, vector->len);
236 if (!crypter->encrypt(crypter, plain, iv, &cipher))
237 {
238 goto failure;
239 }
240 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
241 {
242 goto failure;
243 }
244 /* inline decryption */
245 if (!crypter->decrypt(crypter, cipher, iv, NULL))
246 {
247 goto failure;
248 }
249 if (!memeq(vector->plain, cipher.ptr, cipher.len))
250 {
251 goto failure;
252 }
253 /* allocated decryption */
254 if (!crypter->decrypt(crypter,
255 chunk_create(vector->cipher, vector->len), iv, &plain))
256 {
257 goto failure;
258 }
259 if (!memeq(vector->plain, plain.ptr, plain.len))
260 {
261 goto failure;
262 }
263 /* inline encryption */
264 if (!crypter->encrypt(crypter, plain, iv, NULL))
265 {
266 goto failure;
267 }
268 if (!memeq(vector->cipher, plain.ptr, plain.len))
269 {
270 goto failure;
271 }
272
273 failed = FALSE;
274 failure:
275 crypter->destroy(crypter);
276 chunk_free(&cipher);
277 if (plain.ptr != vector->plain)
278 {
279 chunk_free(&plain);
280 }
281 if (failed)
282 {
283 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
284 encryption_algorithm_names, alg, plugin_name, get_name(vector));
285 break;
286 }
287 }
288 enumerator->destroy(enumerator);
289 if (!tested)
290 {
291 if (failed)
292 {
293 DBG1(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
294 encryption_algorithm_names, alg, plugin_name, key_size);
295 return FALSE;
296 }
297 else
298 {
299 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
300 this->required ? "disabled" : "enabled ",
301 encryption_algorithm_names, alg, plugin_name);
302 return !this->required;
303 }
304 }
305 if (!failed)
306 {
307 if (speed)
308 {
309 *speed = bench_crypter(this, alg, create, key_size);
310 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points "
311 "(%zd bit key)", encryption_algorithm_names, alg,
312 plugin_name, tested, *speed, key_size * 8);
313 }
314 else
315 {
316 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
317 encryption_algorithm_names, alg, plugin_name, tested);
318 }
319 }
320 return !failed;
321 }
322
323 /**
324 * Benchmark an aead transform
325 */
326 static u_int bench_aead(private_crypto_tester_t *this,
327 encryption_algorithm_t alg, aead_constructor_t create, size_t key_size)
328 {
329 aead_t *aead;
330
331 aead = create(alg, key_size, 0);
332 if (aead)
333 {
334 char iv[aead->get_iv_size(aead)];
335 char key[aead->get_key_size(aead)];
336 char assoc[4];
337 chunk_t buf;
338 struct timespec start;
339 u_int runs;
340 size_t icv;
341
342 memset(iv, 0x56, sizeof(iv));
343 memset(key, 0x12, sizeof(key));
344 memset(assoc, 0x78, sizeof(assoc));
345 if (!aead->set_key(aead, chunk_from_thing(key)))
346 {
347 return 0;
348 }
349 icv = aead->get_icv_size(aead);
350
351 buf = chunk_alloc(this->bench_size + icv);
352 memset(buf.ptr, 0x34, buf.len);
353 buf.len -= icv;
354
355 runs = 0;
356 start_timing(&start);
357 while (end_timing(&start) < this->bench_time)
358 {
359 if (aead->encrypt(aead, buf, chunk_from_thing(assoc),
360 chunk_from_thing(iv), NULL))
361 {
362 runs += 2;
363 }
364 if (aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv),
365 chunk_from_thing(assoc), chunk_from_thing(iv), NULL))
366 {
367 runs += 2;
368 }
369 }
370 free(buf.ptr);
371 aead->destroy(aead);
372
373 return runs;
374 }
375 return 0;
376 }
377
378 METHOD(crypto_tester_t, test_aead, bool,
379 private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
380 size_t salt_size, aead_constructor_t create,
381 u_int *speed, const char *plugin_name)
382 {
383 enumerator_t *enumerator;
384 aead_test_vector_t *vector;
385 bool failed = FALSE;
386 u_int tested = 0;
387
388 enumerator = this->aead->create_enumerator(this->aead);
389 while (enumerator->enumerate(enumerator, &vector))
390 {
391 aead_t *aead;
392 chunk_t key, iv, assoc, plain = chunk_empty, cipher = chunk_empty;
393 size_t icv;
394
395 if (vector->alg != alg)
396 {
397 continue;
398 }
399 if (key_size && key_size != vector->key_size)
400 { /* test only vectors with a specific key size, if key size given */
401 continue;
402 }
403 if (salt_size && salt_size != vector->salt_size)
404 {
405 continue;
406 }
407
408 tested++;
409 failed = TRUE;
410 aead = create(alg, vector->key_size, vector->salt_size);
411 if (!aead)
412 {
413 DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
414 encryption_algorithm_names, alg, plugin_name,
415 BITS_PER_BYTE * vector->key_size);
416 continue;
417 }
418
419 key = chunk_create(vector->key, aead->get_key_size(aead));
420 if (!aead->set_key(aead, key))
421 {
422 goto failure;
423 }
424 iv = chunk_create(vector->iv, aead->get_iv_size(aead));
425 assoc = chunk_create(vector->adata, vector->alen);
426 icv = aead->get_icv_size(aead);
427
428 /* allocated encryption */
429 plain = chunk_create(vector->plain, vector->len);
430 if (!aead->encrypt(aead, plain, assoc, iv, &cipher))
431 {
432 goto failure;
433 }
434 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
435 {
436 goto failure;
437 }
438 /* inline decryption */
439 if (!aead->decrypt(aead, cipher, assoc, iv, NULL))
440 {
441 goto failure;
442 }
443 if (!memeq(vector->plain, cipher.ptr, cipher.len - icv))
444 {
445 goto failure;
446 }
447 /* allocated decryption */
448 if (!aead->decrypt(aead, chunk_create(vector->cipher, vector->len + icv),
449 assoc, iv, &plain))
450 {
451 goto failure;
452 }
453 if (!memeq(vector->plain, plain.ptr, plain.len))
454 {
455 goto failure;
456 }
457 plain.ptr = realloc(plain.ptr, plain.len + icv);
458 /* inline encryption */
459 if (!aead->encrypt(aead, plain, assoc, iv, NULL))
460 {
461 goto failure;
462 }
463 if (!memeq(vector->cipher, plain.ptr, plain.len + icv))
464 {
465 goto failure;
466 }
467
468 failed = FALSE;
469 failure:
470 aead->destroy(aead);
471 chunk_free(&cipher);
472 if (plain.ptr != vector->plain)
473 {
474 chunk_free(&plain);
475 }
476 if (failed)
477 {
478 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
479 encryption_algorithm_names, alg, plugin_name, get_name(vector));
480 break;
481 }
482 }
483 enumerator->destroy(enumerator);
484 if (!tested)
485 {
486 if (failed)
487 {
488 DBG1(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
489 encryption_algorithm_names, alg, plugin_name, key_size);
490 return FALSE;
491 }
492 else
493 {
494 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
495 this->required ? "disabled" : "enabled ",
496 encryption_algorithm_names, alg, plugin_name);
497 return !this->required;
498 }
499 }
500 if (!failed)
501 {
502 if (speed)
503 {
504 *speed = bench_aead(this, alg, create, key_size);
505 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points "
506 "(%zd bit key)", encryption_algorithm_names, alg,
507 plugin_name, tested, *speed, key_size * 8);
508 }
509 else
510 {
511 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
512 encryption_algorithm_names, alg, plugin_name, tested);
513 }
514 }
515 return !failed;
516 }
517
518 /**
519 * Benchmark a signer
520 */
521 static u_int bench_signer(private_crypto_tester_t *this,
522 integrity_algorithm_t alg, signer_constructor_t create)
523 {
524 signer_t *signer;
525
526 signer = create(alg);
527 if (signer)
528 {
529 char key[signer->get_key_size(signer)];
530 char mac[signer->get_block_size(signer)];
531 chunk_t buf;
532 struct timespec start;
533 u_int runs;
534
535 memset(key, 0x12, sizeof(key));
536 if (!signer->set_key(signer, chunk_from_thing(key)))
537 {
538 return 0;
539 }
540
541 buf = chunk_alloc(this->bench_size);
542 memset(buf.ptr, 0x34, buf.len);
543
544 runs = 0;
545 start_timing(&start);
546 while (end_timing(&start) < this->bench_time)
547 {
548 if (signer->get_signature(signer, buf, mac))
549 {
550 runs++;
551 }
552 if (signer->verify_signature(signer, buf, chunk_from_thing(mac)))
553 {
554 runs++;
555 }
556 }
557 free(buf.ptr);
558 signer->destroy(signer);
559
560 return runs;
561 }
562 return 0;
563 }
564
565 METHOD(crypto_tester_t, test_signer, bool,
566 private_crypto_tester_t *this, integrity_algorithm_t alg,
567 signer_constructor_t create, u_int *speed, const char *plugin_name)
568 {
569 enumerator_t *enumerator;
570 signer_test_vector_t *vector;
571 bool failed = FALSE;
572 u_int tested = 0;
573
574 enumerator = this->signer->create_enumerator(this->signer);
575 while (enumerator->enumerate(enumerator, &vector))
576 {
577 signer_t *signer;
578 chunk_t key, data, mac = chunk_empty;
579
580 if (vector->alg != alg)
581 {
582 continue;
583 }
584
585 tested++;
586 failed = TRUE;
587 signer = create(alg);
588 if (!signer)
589 {
590 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
591 integrity_algorithm_names, alg, plugin_name);
592 break;
593 }
594
595 data = chunk_create(vector->data, vector->len);
596 key = chunk_create(vector->key, signer->get_key_size(signer));
597 if (!signer->set_key(signer, key))
598 {
599 goto failure;
600 }
601 /* do partial append mode and check if key gets set correctly */
602 if (!signer->get_signature(signer, data, NULL))
603 {
604 goto failure;
605 }
606 if (!signer->set_key(signer, key))
607 {
608 goto failure;
609 }
610 /* allocated signature */
611 if (!signer->allocate_signature(signer, data, &mac))
612 {
613 goto failure;
614 }
615 if (mac.len != signer->get_block_size(signer))
616 {
617 goto failure;
618 }
619 if (!memeq(vector->mac, mac.ptr, mac.len))
620 {
621 goto failure;
622 }
623 /* signature to existing buffer */
624 memset(mac.ptr, 0, mac.len);
625 if (!signer->get_signature(signer, data, mac.ptr))
626 {
627 goto failure;
628 }
629 if (!memeq(vector->mac, mac.ptr, mac.len))
630 {
631 goto failure;
632 }
633 /* signature verification, good case */
634 if (!signer->verify_signature(signer, data, mac))
635 {
636 goto failure;
637 }
638 /* signature verification, bad case */
639 *(mac.ptr + mac.len - 1) += 1;
640 if (signer->verify_signature(signer, data, mac))
641 {
642 goto failure;
643 }
644 /* signature to existing buffer, using append mode */
645 if (data.len > 2)
646 {
647 if (!signer->allocate_signature(signer,
648 chunk_create(data.ptr, 1), NULL))
649 {
650 goto failure;
651 }
652 if (!signer->get_signature(signer,
653 chunk_create(data.ptr + 1, 1), NULL))
654 {
655 goto failure;
656 }
657 if (!signer->verify_signature(signer, chunk_skip(data, 2),
658 chunk_create(vector->mac, mac.len)))
659 {
660 goto failure;
661 }
662 }
663
664 failed = FALSE;
665 failure:
666 signer->destroy(signer);
667 chunk_free(&mac);
668 if (failed)
669 {
670 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
671 integrity_algorithm_names, alg, plugin_name, get_name(vector));
672 break;
673 }
674 }
675 enumerator->destroy(enumerator);
676 if (!tested)
677 {
678 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
679 this->required ? "disabled" : "enabled ",
680 integrity_algorithm_names, alg, plugin_name);
681 return !this->required;
682 }
683 if (!failed)
684 {
685 if (speed)
686 {
687 *speed = bench_signer(this, alg, create);
688 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
689 integrity_algorithm_names, alg, plugin_name, tested, *speed);
690 }
691 else
692 {
693 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
694 integrity_algorithm_names, alg, plugin_name, tested);
695 }
696 }
697 return !failed;
698 }
699
700 /**
701 * Benchmark a hasher
702 */
703 static u_int bench_hasher(private_crypto_tester_t *this,
704 hash_algorithm_t alg, hasher_constructor_t create)
705 {
706 hasher_t *hasher;
707
708 hasher = create(alg);
709 if (hasher)
710 {
711 char hash[hasher->get_hash_size(hasher)];
712 chunk_t buf;
713 struct timespec start;
714 u_int runs;
715
716 buf = chunk_alloc(this->bench_size);
717 memset(buf.ptr, 0x34, buf.len);
718
719 runs = 0;
720 start_timing(&start);
721 while (end_timing(&start) < this->bench_time)
722 {
723 if (hasher->get_hash(hasher, buf, hash))
724 {
725 runs++;
726 }
727 }
728 free(buf.ptr);
729 hasher->destroy(hasher);
730
731 return runs;
732 }
733 return 0;
734 }
735
736 METHOD(crypto_tester_t, test_hasher, bool,
737 private_crypto_tester_t *this, hash_algorithm_t alg,
738 hasher_constructor_t create, u_int *speed, const char *plugin_name)
739 {
740 enumerator_t *enumerator;
741 hasher_test_vector_t *vector;
742 bool failed = FALSE;
743 u_int tested = 0;
744
745 enumerator = this->hasher->create_enumerator(this->hasher);
746 while (enumerator->enumerate(enumerator, &vector))
747 {
748 hasher_t *hasher;
749 chunk_t data, hash;
750
751 if (vector->alg != alg)
752 {
753 continue;
754 }
755
756 tested++;
757 failed = TRUE;
758 hasher = create(alg);
759 if (!hasher)
760 {
761 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
762 hash_algorithm_names, alg, plugin_name);
763 break;
764 }
765
766 /* allocated hash */
767 data = chunk_create(vector->data, vector->len);
768 if (!hasher->allocate_hash(hasher, data, &hash))
769 {
770 goto failure;
771 }
772 if (hash.len != hasher->get_hash_size(hasher))
773 {
774 goto failure;
775 }
776 if (!memeq(vector->hash, hash.ptr, hash.len))
777 {
778 goto failure;
779 }
780 /* hash to existing buffer, with a reset */
781 memset(hash.ptr, 0, hash.len);
782 if (!hasher->get_hash(hasher, data, NULL))
783 {
784 goto failure;
785 }
786 if (!hasher->reset(hasher))
787 {
788 goto failure;
789 }
790 if (!hasher->get_hash(hasher, data, hash.ptr))
791 {
792 goto failure;
793 }
794 if (!memeq(vector->hash, hash.ptr, hash.len))
795 {
796 goto failure;
797 }
798 /* hasher to existing buffer, using append mode */
799 if (data.len > 2)
800 {
801 memset(hash.ptr, 0, hash.len);
802 if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL))
803 {
804 goto failure;
805 }
806 if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL))
807 {
808 goto failure;
809 }
810 if (!hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr))
811 {
812 goto failure;
813 }
814 if (!memeq(vector->hash, hash.ptr, hash.len))
815 {
816 goto failure;
817 }
818 }
819
820 failed = FALSE;
821 failure:
822 hasher->destroy(hasher);
823 chunk_free(&hash);
824 if (failed)
825 {
826 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
827 hash_algorithm_names, alg, plugin_name, get_name(vector));
828 break;
829 }
830 }
831 enumerator->destroy(enumerator);
832 if (!tested)
833 {
834 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
835 this->required ? "disabled" : "enabled ",
836 hash_algorithm_names, alg, plugin_name);
837 return !this->required;
838 }
839 if (!failed)
840 {
841 if (speed)
842 {
843 *speed = bench_hasher(this, alg, create);
844 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
845 hash_algorithm_names, alg, plugin_name, tested, *speed);
846 }
847 else
848 {
849 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
850 hash_algorithm_names, alg, plugin_name, tested);
851 }
852 }
853 return !failed;
854 }
855
856 /**
857 * Benchmark a PRF
858 */
859 static u_int bench_prf(private_crypto_tester_t *this,
860 pseudo_random_function_t alg, prf_constructor_t create)
861 {
862 prf_t *prf;
863
864 prf = create(alg);
865 if (prf)
866 {
867 char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)];
868 chunk_t buf;
869 struct timespec start;
870 u_int runs;
871
872 memset(key, 0x56, prf->get_block_size(prf));
873 if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf))))
874 {
875 prf->destroy(prf);
876 return 0;
877 }
878
879 buf = chunk_alloc(this->bench_size);
880 memset(buf.ptr, 0x34, buf.len);
881
882 runs = 0;
883 start_timing(&start);
884 while (end_timing(&start) < this->bench_time)
885 {
886 if (prf->get_bytes(prf, buf, bytes))
887 {
888 runs++;
889 }
890 }
891 free(buf.ptr);
892 prf->destroy(prf);
893
894 return runs;
895 }
896 return 0;
897 }
898
899 METHOD(crypto_tester_t, test_prf, bool,
900 private_crypto_tester_t *this, pseudo_random_function_t alg,
901 prf_constructor_t create, u_int *speed, const char *plugin_name)
902 {
903 enumerator_t *enumerator;
904 prf_test_vector_t *vector;
905 bool failed = FALSE;
906 u_int tested = 0;
907
908 enumerator = this->prf->create_enumerator(this->prf);
909 while (enumerator->enumerate(enumerator, &vector))
910 {
911 prf_t *prf;
912 chunk_t key, seed, out = chunk_empty;
913
914 if (vector->alg != alg)
915 {
916 continue;
917 }
918
919 tested++;
920 failed = TRUE;
921 prf = create(alg);
922 if (!prf)
923 {
924 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
925 pseudo_random_function_names, alg, plugin_name);
926 break;
927 }
928
929 seed = chunk_create(vector->seed, vector->len);
930 key = chunk_create(vector->key, vector->key_size);
931 if (!prf->set_key(prf, key))
932 {
933 goto failure;
934 }
935 if (alg != PRF_FIPS_SHA1_160)
936 {
937 /* do partial append mode and check if key gets set correctly */
938 if (!prf->get_bytes(prf, seed, NULL))
939 {
940 goto failure;
941 }
942 if (!prf->set_key(prf, key))
943 {
944 goto failure;
945 }
946 }
947 /* allocated bytes */
948 if (!prf->allocate_bytes(prf, seed, &out))
949 {
950 goto failure;
951 }
952 if (out.len != prf->get_block_size(prf))
953 {
954 goto failure;
955 }
956 if (!memeq(vector->out, out.ptr, out.len))
957 {
958 goto failure;
959 }
960 /* bytes to existing buffer */
961 memset(out.ptr, 0, out.len);
962 if (vector->stateful)
963 {
964 if (!prf->set_key(prf, key))
965 {
966 goto failure;
967 }
968 }
969 if (!prf->get_bytes(prf, seed, out.ptr))
970 {
971 goto failure;
972 }
973 if (!memeq(vector->out, out.ptr, out.len))
974 {
975 goto failure;
976 }
977 /* bytes to existing buffer, using append mode */
978 if (alg != PRF_FIPS_SHA1_160 && seed.len > 2)
979 {
980 memset(out.ptr, 0, out.len);
981 if (vector->stateful)
982 {
983 if (!prf->set_key(prf, key))
984 {
985 goto failure;
986 }
987 }
988 if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL))
989 {
990 goto failure;
991 }
992 if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL))
993 {
994 goto failure;
995 }
996 if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
997 {
998 goto failure;
999 }
1000 if (!memeq(vector->out, out.ptr, out.len))
1001 {
1002 goto failure;
1003 }
1004 }
1005
1006 failed = FALSE;
1007 failure:
1008 prf->destroy(prf);
1009 chunk_free(&out);
1010 if (failed)
1011 {
1012 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1013 pseudo_random_function_names, alg, plugin_name, get_name(vector));
1014 break;
1015 }
1016 }
1017 enumerator->destroy(enumerator);
1018 if (!tested)
1019 {
1020 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1021 this->required ? "disabled" : "enabled ",
1022 pseudo_random_function_names, alg, plugin_name);
1023 return !this->required;
1024 }
1025 if (!failed)
1026 {
1027 if (speed)
1028 {
1029 *speed = bench_prf(this, alg, create);
1030 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1031 pseudo_random_function_names, alg, plugin_name, tested, *speed);
1032 }
1033 else
1034 {
1035 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1036 pseudo_random_function_names, alg, plugin_name, tested);
1037 }
1038 }
1039 return !failed;
1040 }
1041
1042 /**
1043 * Benchmark an XOF
1044 */
1045 static u_int bench_xof(private_crypto_tester_t *this,
1046 ext_out_function_t alg, xof_constructor_t create)
1047 {
1048 xof_t *xof;
1049
1050 xof = create(alg);
1051 if (xof)
1052 {
1053 char seed[xof->get_seed_size(xof)];
1054 char bytes[xof->get_block_size(xof)];
1055 struct timespec start;
1056 u_int runs;
1057
1058 memset(seed, 0x56, xof->get_seed_size(xof));
1059 if (!xof->set_seed(xof, chunk_create(seed, xof->get_seed_size(xof))))
1060 {
1061 xof->destroy(xof);
1062 return 0;
1063 }
1064
1065 runs = 0;
1066 start_timing(&start);
1067 while (end_timing(&start) < this->bench_time)
1068 {
1069 if (xof->get_bytes(xof, xof->get_block_size(xof), bytes))
1070 {
1071 runs++;
1072 }
1073 }
1074 xof->destroy(xof);
1075
1076 return runs;
1077 }
1078 return 0;
1079 }
1080
1081 METHOD(crypto_tester_t, test_xof, bool,
1082 private_crypto_tester_t *this, ext_out_function_t alg,
1083 xof_constructor_t create, u_int *speed, const char *plugin_name)
1084 {
1085 enumerator_t *enumerator;
1086 xof_test_vector_t *vector;
1087 bool failed = FALSE;
1088 u_int tested = 0;
1089
1090 enumerator = this->xof->create_enumerator(this->xof);
1091 while (enumerator->enumerate(enumerator, &vector))
1092 {
1093 xof_t *xof;
1094 chunk_t seed, out = chunk_empty;
1095
1096 if (vector->alg != alg)
1097 {
1098 continue;
1099 }
1100
1101 tested++;
1102 failed = TRUE;
1103 xof = create(alg);
1104 if (!xof)
1105 {
1106 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1107 ext_out_function_names, alg, plugin_name);
1108 break;
1109 }
1110
1111 seed = chunk_create(vector->seed, vector->len);
1112 if (!xof->set_seed(xof, seed))
1113 {
1114 goto failure;
1115 }
1116 /* allocated bytes */
1117 if (!xof->allocate_bytes(xof, vector->out_len, &out))
1118 {
1119 goto failure;
1120 }
1121 if (out.len != vector->out_len)
1122 {
1123 goto failure;
1124 }
1125 if (!memeq(vector->out, out.ptr, out.len))
1126 {
1127 goto failure;
1128 }
1129 /* bytes to existing buffer */
1130 memset(out.ptr, 0, out.len);
1131 if (!xof->set_seed(xof, seed))
1132 {
1133 goto failure;
1134 }
1135 if (!xof->get_bytes(xof, vector->out_len, out.ptr))
1136 {
1137 goto failure;
1138 }
1139 if (!memeq(vector->out, out.ptr, vector->out_len))
1140 {
1141 goto failure;
1142 }
1143 /* bytes to existing buffer, using append mode */
1144 /* TODO */
1145
1146 failed = FALSE;
1147 failure:
1148 xof->destroy(xof);
1149 chunk_free(&out);
1150 if (failed)
1151 {
1152 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1153 ext_out_function_names, alg, plugin_name, get_name(vector));
1154 break;
1155 }
1156 }
1157 enumerator->destroy(enumerator);
1158 if (!tested)
1159 {
1160 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1161 this->required ? "disabled" : "enabled ",
1162 ext_out_function_names, alg, plugin_name);
1163 return !this->required;
1164 }
1165 if (!failed)
1166 {
1167 if (speed)
1168 {
1169 *speed = bench_xof(this, alg, create);
1170 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1171 ext_out_function_names, alg, plugin_name, tested, *speed);
1172 }
1173 else
1174 {
1175 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1176 ext_out_function_names, alg, plugin_name, tested);
1177 }
1178 }
1179 return !failed;
1180 }
1181
1182 /**
1183 * Benchmark a RNG
1184 */
1185 static u_int bench_rng(private_crypto_tester_t *this,
1186 rng_quality_t quality, rng_constructor_t create)
1187 {
1188 rng_t *rng;
1189
1190 rng = create(quality);
1191 if (rng)
1192 {
1193 struct timespec start;
1194 chunk_t buf;
1195 u_int runs;
1196
1197 runs = 0;
1198 buf = chunk_alloc(this->bench_size);
1199 start_timing(&start);
1200 while (end_timing(&start) < this->bench_time)
1201 {
1202 if (!rng->get_bytes(rng, buf.len, buf.ptr))
1203 {
1204 runs = 0;
1205 break;
1206 }
1207 runs++;
1208 }
1209 free(buf.ptr);
1210 rng->destroy(rng);
1211
1212 return runs;
1213 }
1214 return 0;
1215 }
1216
1217 METHOD(crypto_tester_t, test_rng, bool,
1218 private_crypto_tester_t *this, rng_quality_t quality,
1219 rng_constructor_t create, u_int *speed, const char *plugin_name)
1220 {
1221 enumerator_t *enumerator;
1222 rng_test_vector_t *vector;
1223 bool failed = FALSE;
1224 u_int tested = 0;
1225
1226 if (!this->rng_true && quality == RNG_TRUE)
1227 {
1228 DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
1229 rng_quality_names, quality, plugin_name);
1230 return TRUE;
1231 }
1232
1233 enumerator = this->rng->create_enumerator(this->rng);
1234 while (enumerator->enumerate(enumerator, &vector))
1235 {
1236 chunk_t data = chunk_empty;
1237 rng_t *rng;
1238
1239 if (vector->quality != quality)
1240 {
1241 continue;
1242 }
1243
1244 tested++;
1245 failed = TRUE;
1246 rng = create(quality);
1247 if (!rng)
1248 {
1249 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1250 rng_quality_names, quality, plugin_name);
1251 break;
1252 }
1253
1254 /* allocated bytes */
1255 if (!rng->allocate_bytes(rng, vector->len, &data) ||
1256 data.len != vector->len ||
1257 !vector->test(vector->user, data))
1258 {
1259 goto failure;
1260 }
1261 /* write bytes into existing buffer */
1262 memset(data.ptr, 0, data.len);
1263 if (!rng->get_bytes(rng, vector->len, data.ptr))
1264 {
1265 goto failure;
1266 }
1267 if (!vector->test(vector->user, data))
1268 {
1269 goto failure;
1270 }
1271
1272 failed = FALSE;
1273 failure:
1274 rng->destroy(rng);
1275 chunk_free(&data);
1276 if (failed)
1277 {
1278 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1279 rng_quality_names, quality, plugin_name, get_name(vector));
1280 break;
1281 }
1282 }
1283 enumerator->destroy(enumerator);
1284 if (!tested)
1285 {
1286 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1287 this->required ? ", disabled" : "enabled ",
1288 rng_quality_names, quality, plugin_name);
1289 return !this->required;
1290 }
1291 if (!failed)
1292 {
1293 if (speed)
1294 {
1295 *speed = bench_rng(this, quality, create);
1296 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1297 rng_quality_names, quality, plugin_name, tested, *speed);
1298 }
1299 else
1300 {
1301 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1302 rng_quality_names, quality, plugin_name, tested);
1303 }
1304 }
1305 return !failed;
1306 }
1307
1308 /**
1309 * Benchmark a DH backend
1310 */
1311 static u_int bench_dh(private_crypto_tester_t *this,
1312 diffie_hellman_group_t group, dh_constructor_t create)
1313 {
1314 chunk_t pub = chunk_empty, shared = chunk_empty;
1315 diffie_hellman_t *dh;
1316 struct timespec start;
1317 u_int runs;
1318
1319 runs = 0;
1320 start_timing(&start);
1321 while (end_timing(&start) < this->bench_time)
1322 {
1323 dh = create(group);
1324 if (!dh)
1325 {
1326 return 0;
1327 }
1328 if (dh->get_my_public_value(dh, &pub) &&
1329 dh->set_other_public_value(dh, pub) &&
1330 dh->get_shared_secret(dh, &shared))
1331 {
1332 runs++;
1333 }
1334 chunk_free(&pub);
1335 chunk_free(&shared);
1336 dh->destroy(dh);
1337 }
1338 return runs;
1339 }
1340
1341 METHOD(crypto_tester_t, test_dh, bool,
1342 private_crypto_tester_t *this, diffie_hellman_group_t group,
1343 dh_constructor_t create, u_int *speed, const char *plugin_name)
1344 {
1345 enumerator_t *enumerator;
1346 dh_test_vector_t *v;
1347 bool failed = FALSE;
1348 u_int tested = 0;
1349
1350 enumerator = this->dh->create_enumerator(this->dh);
1351 while (enumerator->enumerate(enumerator, &v))
1352 {
1353 diffie_hellman_t *a, *b;
1354 chunk_t apub, bpub, asec, bsec;
1355
1356 if (v->group != group)
1357 {
1358 continue;
1359 }
1360
1361 a = create(group);
1362 b = create(group);
1363 if (!a || !b)
1364 {
1365 DESTROY_IF(a);
1366 DESTROY_IF(b);
1367 failed = TRUE;
1368 tested++;
1369 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1370 diffie_hellman_group_names, group, plugin_name);
1371 break;
1372 }
1373
1374 if (!a->set_private_value || !b->set_private_value)
1375 { /* does not support testing */
1376 a->destroy(a);
1377 b->destroy(b);
1378 continue;
1379 }
1380 failed = TRUE;
1381 tested++;
1382
1383 apub = bpub = asec = bsec = chunk_empty;
1384
1385 if (!a->set_private_value(a, chunk_create(v->priv_a, v->priv_len)) ||
1386 !b->set_private_value(b, chunk_create(v->priv_b, v->priv_len)))
1387 {
1388 goto failure;
1389 }
1390 if (!a->get_my_public_value(a, &apub) ||
1391 !chunk_equals(apub, chunk_create(v->pub_a, v->pub_len)))
1392 {
1393 goto failure;
1394 }
1395 if (!b->get_my_public_value(b, &bpub) ||
1396 !chunk_equals(bpub, chunk_create(v->pub_b, v->pub_len)))
1397 {
1398 goto failure;
1399 }
1400 if (!a->set_other_public_value(a, bpub) ||
1401 !b->set_other_public_value(b, apub))
1402 {
1403 goto failure;
1404 }
1405 if (!a->get_shared_secret(a, &asec) ||
1406 !chunk_equals(asec, chunk_create(v->shared, v->shared_len)))
1407 {
1408 goto failure;
1409 }
1410 if (!b->get_shared_secret(b, &bsec) ||
1411 !chunk_equals(bsec, chunk_create(v->shared, v->shared_len)))
1412 {
1413 goto failure;
1414 }
1415
1416 failed = FALSE;
1417 failure:
1418 a->destroy(a);
1419 b->destroy(b);
1420 chunk_free(&apub);
1421 chunk_free(&bpub);
1422 chunk_free(&asec);
1423 chunk_free(&bsec);
1424 if (failed)
1425 {
1426 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1427 diffie_hellman_group_names, group, plugin_name, get_name(v));
1428 break;
1429 }
1430 }
1431 enumerator->destroy(enumerator);
1432 if (!tested)
1433 {
1434 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found / untestable",
1435 this->required ? "disabled" : "enabled ",
1436 diffie_hellman_group_names, group, plugin_name);
1437 return !this->required;
1438 }
1439 if (!failed)
1440 {
1441 if (speed)
1442 {
1443 *speed = bench_dh(this, group, create);
1444 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1445 diffie_hellman_group_names, group, plugin_name, tested, *speed);
1446 }
1447 else
1448 {
1449 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1450 diffie_hellman_group_names, group, plugin_name, tested);
1451 }
1452 }
1453 return !failed;
1454 }
1455
1456 METHOD(crypto_tester_t, add_crypter_vector, void,
1457 private_crypto_tester_t *this, crypter_test_vector_t *vector)
1458 {
1459 this->crypter->insert_last(this->crypter, vector);
1460 }
1461
1462 METHOD(crypto_tester_t, add_aead_vector, void,
1463 private_crypto_tester_t *this, aead_test_vector_t *vector)
1464 {
1465 this->aead->insert_last(this->aead, vector);
1466 }
1467
1468 METHOD(crypto_tester_t, add_signer_vector, void,
1469 private_crypto_tester_t *this, signer_test_vector_t *vector)
1470 {
1471 this->signer->insert_last(this->signer, vector);
1472 }
1473
1474 METHOD(crypto_tester_t, add_hasher_vector, void,
1475 private_crypto_tester_t *this, hasher_test_vector_t *vector)
1476 {
1477 this->hasher->insert_last(this->hasher, vector);
1478 }
1479
1480 METHOD(crypto_tester_t, add_prf_vector, void,
1481 private_crypto_tester_t *this, prf_test_vector_t *vector)
1482 {
1483 this->prf->insert_last(this->prf, vector);
1484 }
1485
1486 METHOD(crypto_tester_t, add_xof_vector, void,
1487 private_crypto_tester_t *this, xof_test_vector_t *vector)
1488 {
1489 this->xof->insert_last(this->xof, vector);
1490 }
1491
1492 METHOD(crypto_tester_t, add_rng_vector, void,
1493 private_crypto_tester_t *this, rng_test_vector_t *vector)
1494 {
1495 this->rng->insert_last(this->rng, vector);
1496 }
1497
1498 METHOD(crypto_tester_t, add_dh_vector, void,
1499 private_crypto_tester_t *this, dh_test_vector_t *vector)
1500 {
1501 this->dh->insert_last(this->dh, vector);
1502 }
1503
1504 METHOD(crypto_tester_t, destroy, void,
1505 private_crypto_tester_t *this)
1506 {
1507 this->crypter->destroy(this->crypter);
1508 this->aead->destroy(this->aead);
1509 this->signer->destroy(this->signer);
1510 this->hasher->destroy(this->hasher);
1511 this->prf->destroy(this->prf);
1512 this->xof->destroy(this->xof);
1513 this->rng->destroy(this->rng);
1514 this->dh->destroy(this->dh);
1515 free(this);
1516 }
1517
1518 /**
1519 * See header
1520 */
1521 crypto_tester_t *crypto_tester_create()
1522 {
1523 private_crypto_tester_t *this;
1524
1525 INIT(this,
1526 .public = {
1527 .test_crypter = _test_crypter,
1528 .test_aead = _test_aead,
1529 .test_signer = _test_signer,
1530 .test_hasher = _test_hasher,
1531 .test_prf = _test_prf,
1532 .test_xof = _test_xof,
1533 .test_rng = _test_rng,
1534 .test_dh = _test_dh,
1535 .add_crypter_vector = _add_crypter_vector,
1536 .add_aead_vector = _add_aead_vector,
1537 .add_signer_vector = _add_signer_vector,
1538 .add_hasher_vector = _add_hasher_vector,
1539 .add_prf_vector = _add_prf_vector,
1540 .add_xof_vector = _add_xof_vector,
1541 .add_rng_vector = _add_rng_vector,
1542 .add_dh_vector = _add_dh_vector,
1543 .destroy = _destroy,
1544 },
1545 .crypter = linked_list_create(),
1546 .aead = linked_list_create(),
1547 .signer = linked_list_create(),
1548 .hasher = linked_list_create(),
1549 .prf = linked_list_create(),
1550 .xof = linked_list_create(),
1551 .rng = linked_list_create(),
1552 .dh = linked_list_create(),
1553
1554 .required = lib->settings->get_bool(lib->settings,
1555 "%s.crypto_test.required", FALSE, lib->ns),
1556 .rng_true = lib->settings->get_bool(lib->settings,
1557 "%s.crypto_test.rng_true", FALSE, lib->ns),
1558 .bench_time = lib->settings->get_int(lib->settings,
1559 "%s.crypto_test.bench_time", 50, lib->ns),
1560 .bench_size = lib->settings->get_int(lib->settings,
1561 "%s.crypto_test.bench_size", 1024, lib->ns),
1562 );
1563
1564 /* enforce a block size of 16, should be fine for all algorithms */
1565 this->bench_size = this->bench_size / 16 * 16;
1566
1567 return &this->public;
1568 }