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