Add a return value to hasher_t.get_hash()
[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 <debug.h>
24 #include <utils/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, plain, cipher, iv;
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 crypter = create(alg, vector->key_size);
207 if (!crypter)
208 {
209 DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
210 encryption_algorithm_names, alg, plugin_name,
211 BITS_PER_BYTE * vector->key_size);
212 failed = TRUE;
213 continue;
214 }
215
216 failed = FALSE;
217 tested++;
218
219 key = chunk_create(vector->key, crypter->get_key_size(crypter));
220 if (!crypter->set_key(crypter, key))
221 {
222 failed = TRUE;
223 }
224 iv = chunk_create(vector->iv, crypter->get_iv_size(crypter));
225
226 /* allocated encryption */
227 plain = chunk_create(vector->plain, vector->len);
228 if (!crypter->encrypt(crypter, plain, iv, &cipher))
229 {
230 failed = TRUE;
231 }
232 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
233 {
234 failed = TRUE;
235 }
236 /* inline decryption */
237 if (!crypter->decrypt(crypter, cipher, iv, NULL))
238 {
239 failed = TRUE;
240 }
241 if (!memeq(vector->plain, cipher.ptr, cipher.len))
242 {
243 failed = TRUE;
244 }
245 free(cipher.ptr);
246 /* allocated decryption */
247 cipher = chunk_create(vector->cipher, vector->len);
248 if (!crypter->decrypt(crypter, cipher, iv, &plain))
249 {
250 failed = TRUE;
251 }
252 if (!memeq(vector->plain, plain.ptr, plain.len))
253 {
254 failed = TRUE;
255 }
256 /* inline encryption */
257 if (!crypter->encrypt(crypter, plain, iv, NULL))
258 {
259 failed = TRUE;
260 }
261 if (!memeq(vector->cipher, plain.ptr, plain.len))
262 {
263 failed = TRUE;
264 }
265 free(plain.ptr);
266
267 crypter->destroy(crypter);
268 if (failed)
269 {
270 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
271 encryption_algorithm_names, alg, plugin_name, get_name(vector));
272 break;
273 }
274 }
275 enumerator->destroy(enumerator);
276 if (!tested)
277 {
278 if (failed)
279 {
280 DBG1(DBG_LIB,"disable %N[%s]: no key size supported",
281 encryption_algorithm_names, alg, plugin_name);
282 return FALSE;
283 }
284 else
285 {
286 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
287 this->required ? "disabled" : "enabled ",
288 encryption_algorithm_names, alg, plugin_name);
289 return !this->required;
290 }
291 }
292 if (!failed)
293 {
294 if (speed)
295 {
296 *speed = bench_crypter(this, alg, create);
297 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
298 encryption_algorithm_names, alg, plugin_name, tested, *speed);
299 }
300 else
301 {
302 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
303 encryption_algorithm_names, alg, plugin_name, tested);
304 }
305 }
306 return !failed;
307 }
308
309 /**
310 * Benchmark an aead transform
311 */
312 static u_int bench_aead(private_crypto_tester_t *this,
313 encryption_algorithm_t alg, aead_constructor_t create)
314 {
315 aead_t *aead;
316
317 aead = create(alg, 0);
318 if (aead)
319 {
320 char iv[aead->get_iv_size(aead)];
321 char key[aead->get_key_size(aead)];
322 char assoc[4];
323 chunk_t buf;
324 struct timespec start;
325 u_int runs;
326 size_t icv;
327
328 memset(iv, 0x56, sizeof(iv));
329 memset(key, 0x12, sizeof(key));
330 memset(assoc, 0x78, sizeof(assoc));
331 if (!aead->set_key(aead, chunk_from_thing(key)))
332 {
333 return 0;
334 }
335 icv = aead->get_icv_size(aead);
336
337 buf = chunk_alloc(this->bench_size + icv);
338 memset(buf.ptr, 0x34, buf.len);
339 buf.len -= icv;
340
341 runs = 0;
342 start_timing(&start);
343 while (end_timing(&start) < this->bench_time)
344 {
345 if (aead->encrypt(aead, buf, chunk_from_thing(assoc),
346 chunk_from_thing(iv), NULL))
347 {
348 runs += 2;
349 }
350 if (aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv),
351 chunk_from_thing(assoc), chunk_from_thing(iv), NULL))
352 {
353 runs += 2;
354 }
355 }
356 free(buf.ptr);
357 aead->destroy(aead);
358
359 return runs;
360 }
361 return 0;
362 }
363
364 METHOD(crypto_tester_t, test_aead, bool,
365 private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
366 aead_constructor_t create, u_int *speed, const char *plugin_name)
367 {
368 enumerator_t *enumerator;
369 aead_test_vector_t *vector;
370 bool failed = FALSE;
371 u_int tested = 0;
372
373 enumerator = this->aead->create_enumerator(this->aead);
374 while (enumerator->enumerate(enumerator, &vector))
375 {
376 aead_t *aead;
377 chunk_t key, plain, cipher, iv, assoc;
378 size_t icv;
379
380 if (vector->alg != alg)
381 {
382 continue;
383 }
384 if (key_size && key_size != vector->key_size)
385 { /* test only vectors with a specific key size, if key size given */
386 continue;
387 }
388 aead = create(alg, vector->key_size);
389 if (!aead)
390 {
391 DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
392 encryption_algorithm_names, alg, plugin_name,
393 BITS_PER_BYTE * vector->key_size);
394 failed = TRUE;
395 continue;
396 }
397
398 failed = FALSE;
399 tested++;
400
401 key = chunk_create(vector->key, aead->get_key_size(aead));
402 if (!aead->set_key(aead, key))
403 {
404 failed = TRUE;
405 }
406 iv = chunk_create(vector->iv, aead->get_iv_size(aead));
407 assoc = chunk_create(vector->adata, vector->alen);
408 icv = aead->get_icv_size(aead);
409
410 /* allocated encryption */
411 plain = chunk_create(vector->plain, vector->len);
412 if (!aead->encrypt(aead, plain, assoc, iv, &cipher))
413 {
414 failed = TRUE;
415 }
416 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
417 {
418 failed = TRUE;
419 }
420 /* inline decryption */
421 if (!aead->decrypt(aead, cipher, assoc, iv, NULL))
422 {
423 failed = TRUE;
424 }
425 if (!memeq(vector->plain, cipher.ptr, cipher.len - icv))
426 {
427 failed = TRUE;
428 }
429 free(cipher.ptr);
430 /* allocated decryption */
431 cipher = chunk_create(vector->cipher, vector->len + icv);
432 if (!aead->decrypt(aead, cipher, assoc, iv, &plain))
433 {
434 plain = chunk_empty;
435 failed = TRUE;
436 }
437 else if (!memeq(vector->plain, plain.ptr, plain.len))
438 {
439 failed = TRUE;
440 }
441 plain.ptr = realloc(plain.ptr, plain.len + icv);
442 /* inline encryption */
443 if (!aead->encrypt(aead, plain, assoc, iv, NULL))
444 {
445 failed = TRUE;
446 }
447 if (!memeq(vector->cipher, plain.ptr, plain.len + icv))
448 {
449 failed = TRUE;
450 }
451 free(plain.ptr);
452
453 aead->destroy(aead);
454 if (failed)
455 {
456 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
457 encryption_algorithm_names, alg, plugin_name, get_name(vector));
458 break;
459 }
460 }
461 enumerator->destroy(enumerator);
462 if (!tested)
463 {
464 if (failed)
465 {
466 DBG1(DBG_LIB,"disable %N[%s]: no key size supported",
467 encryption_algorithm_names, alg, plugin_name);
468 return FALSE;
469 }
470 else
471 {
472 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
473 this->required ? "disabled" : "enabled ",
474 encryption_algorithm_names, alg, plugin_name);
475 return !this->required;
476 }
477 }
478 if (!failed)
479 {
480 if (speed)
481 {
482 *speed = bench_aead(this, alg, create);
483 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
484 encryption_algorithm_names, alg, plugin_name, tested, *speed);
485 }
486 else
487 {
488 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
489 encryption_algorithm_names, alg, plugin_name, tested);
490 }
491 }
492 return !failed;
493 }
494
495 /**
496 * Benchmark a signer
497 */
498 static u_int bench_signer(private_crypto_tester_t *this,
499 integrity_algorithm_t alg, signer_constructor_t create)
500 {
501 signer_t *signer;
502
503 signer = create(alg);
504 if (signer)
505 {
506 char key[signer->get_key_size(signer)];
507 char mac[signer->get_block_size(signer)];
508 chunk_t buf;
509 struct timespec start;
510 u_int runs;
511
512 memset(key, 0x12, sizeof(key));
513 if (!signer->set_key(signer, chunk_from_thing(key)))
514 {
515 return 0;
516 }
517
518 buf = chunk_alloc(this->bench_size);
519 memset(buf.ptr, 0x34, buf.len);
520
521 runs = 0;
522 start_timing(&start);
523 while (end_timing(&start) < this->bench_time)
524 {
525 if (signer->get_signature(signer, buf, mac))
526 {
527 runs++;
528 }
529 if (signer->verify_signature(signer, buf, chunk_from_thing(mac)))
530 {
531 runs++;
532 }
533 }
534 free(buf.ptr);
535 signer->destroy(signer);
536
537 return runs;
538 }
539 return 0;
540 }
541
542 METHOD(crypto_tester_t, test_signer, bool,
543 private_crypto_tester_t *this, integrity_algorithm_t alg,
544 signer_constructor_t create, u_int *speed, const char *plugin_name)
545 {
546 enumerator_t *enumerator;
547 signer_test_vector_t *vector;
548 bool failed = FALSE;
549 u_int tested = 0;
550
551 enumerator = this->signer->create_enumerator(this->signer);
552 while (enumerator->enumerate(enumerator, &vector))
553 {
554 signer_t *signer;
555 chunk_t key, data, mac;
556
557 if (vector->alg != alg)
558 {
559 continue;
560 }
561
562 tested++;
563 signer = create(alg);
564 if (!signer)
565 {
566 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
567 integrity_algorithm_names, alg, plugin_name);
568 failed = TRUE;
569 break;
570 }
571
572 failed = FALSE;
573
574 key = chunk_create(vector->key, signer->get_key_size(signer));
575 if (!signer->set_key(signer, key))
576 {
577 failed = TRUE;
578 }
579 /* allocated signature */
580 data = chunk_create(vector->data, vector->len);
581 if (!signer->allocate_signature(signer, data, &mac))
582 {
583 failed = TRUE;
584 }
585 if (mac.len != signer->get_block_size(signer))
586 {
587 failed = TRUE;
588 }
589 if (!memeq(vector->mac, mac.ptr, mac.len))
590 {
591 failed = TRUE;
592 }
593 /* signature to existing buffer */
594 memset(mac.ptr, 0, mac.len);
595 if (!signer->get_signature(signer, data, mac.ptr))
596 {
597 failed = TRUE;
598 }
599 if (!memeq(vector->mac, mac.ptr, mac.len))
600 {
601 failed = TRUE;
602 }
603 /* signature verification, good case */
604 if (!signer->verify_signature(signer, data, mac))
605 {
606 failed = TRUE;
607 }
608 /* signature verification, bad case */
609 *(mac.ptr + mac.len - 1) += 1;
610 if (signer->verify_signature(signer, data, mac))
611 {
612 failed = TRUE;
613 }
614 /* signature to existing buffer, using append mode */
615 if (data.len > 2)
616 {
617 if (!signer->allocate_signature(signer,
618 chunk_create(data.ptr, 1), NULL))
619 {
620 failed = TRUE;
621 }
622 if (!signer->get_signature(signer,
623 chunk_create(data.ptr + 1, 1), NULL))
624 {
625 failed = TRUE;
626 }
627 if (!signer->verify_signature(signer, chunk_skip(data, 2),
628 chunk_create(vector->mac, mac.len)))
629 {
630 failed = TRUE;
631 }
632 }
633 free(mac.ptr);
634
635 signer->destroy(signer);
636 if (failed)
637 {
638 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
639 integrity_algorithm_names, alg, plugin_name, get_name(vector));
640 break;
641 }
642 }
643 enumerator->destroy(enumerator);
644 if (!tested)
645 {
646 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
647 this->required ? "disabled" : "enabled ",
648 integrity_algorithm_names, alg, plugin_name);
649 return !this->required;
650 }
651 if (!failed)
652 {
653 if (speed)
654 {
655 *speed = bench_signer(this, alg, create);
656 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
657 integrity_algorithm_names, alg, plugin_name, tested, *speed);
658 }
659 else
660 {
661 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
662 integrity_algorithm_names, alg, plugin_name, tested);
663 }
664 }
665 return !failed;
666 }
667
668 /**
669 * Benchmark a hasher
670 */
671 static u_int bench_hasher(private_crypto_tester_t *this,
672 hash_algorithm_t alg, hasher_constructor_t create)
673 {
674 hasher_t *hasher;
675
676 hasher = create(alg);
677 if (hasher)
678 {
679 char hash[hasher->get_hash_size(hasher)];
680 chunk_t buf;
681 struct timespec start;
682 u_int runs;
683
684 buf = chunk_alloc(this->bench_size);
685 memset(buf.ptr, 0x34, buf.len);
686
687 runs = 0;
688 start_timing(&start);
689 while (end_timing(&start) < this->bench_time)
690 {
691 if (hasher->get_hash(hasher, buf, hash))
692 {
693 runs++;
694 }
695 }
696 free(buf.ptr);
697 hasher->destroy(hasher);
698
699 return runs;
700 }
701 return 0;
702 }
703
704 METHOD(crypto_tester_t, test_hasher, bool,
705 private_crypto_tester_t *this, hash_algorithm_t alg,
706 hasher_constructor_t create, u_int *speed, const char *plugin_name)
707 {
708 enumerator_t *enumerator;
709 hasher_test_vector_t *vector;
710 bool failed = FALSE;
711 u_int tested = 0;
712
713 enumerator = this->hasher->create_enumerator(this->hasher);
714 while (enumerator->enumerate(enumerator, &vector))
715 {
716 hasher_t *hasher;
717 chunk_t data, hash;
718
719 if (vector->alg != alg)
720 {
721 continue;
722 }
723
724 tested++;
725 hasher = create(alg);
726 if (!hasher)
727 {
728 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
729 hash_algorithm_names, alg, plugin_name);
730 failed = TRUE;
731 break;
732 }
733
734 failed = FALSE;
735
736 /* allocated hash */
737 data = chunk_create(vector->data, vector->len);
738 hasher->allocate_hash(hasher, data, &hash);
739 if (hash.len != hasher->get_hash_size(hasher))
740 {
741 failed = TRUE;
742 }
743 if (!memeq(vector->hash, hash.ptr, hash.len))
744 {
745 failed = TRUE;
746 }
747 /* hash to existing buffer */
748 memset(hash.ptr, 0, hash.len);
749 if (!hasher->get_hash(hasher, data, hash.ptr))
750 {
751 failed = TRUE;
752 }
753 if (!memeq(vector->hash, hash.ptr, hash.len))
754 {
755 failed = TRUE;
756 }
757 /* hasher to existing buffer, using append mode */
758 if (data.len > 2)
759 {
760 memset(hash.ptr, 0, hash.len);
761 hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL);
762 if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL) ||
763 !hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr) ||
764 !memeq(vector->hash, hash.ptr, hash.len))
765 {
766 failed = TRUE;
767 }
768 }
769 free(hash.ptr);
770
771 hasher->destroy(hasher);
772 if (failed)
773 {
774 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
775 hash_algorithm_names, alg, plugin_name, get_name(vector));
776 break;
777 }
778 }
779 enumerator->destroy(enumerator);
780 if (!tested)
781 {
782 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
783 this->required ? "disabled" : "enabled ",
784 hash_algorithm_names, alg, plugin_name);
785 return !this->required;
786 }
787 if (!failed)
788 {
789 if (speed)
790 {
791 *speed = bench_hasher(this, alg, create);
792 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
793 hash_algorithm_names, alg, plugin_name, tested, *speed);
794 }
795 else
796 {
797 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
798 hash_algorithm_names, alg, plugin_name, tested);
799 }
800 }
801 return !failed;
802 }
803
804 /**
805 * Benchmark a PRF
806 */
807 static u_int bench_prf(private_crypto_tester_t *this,
808 pseudo_random_function_t alg, prf_constructor_t create)
809 {
810 prf_t *prf;
811
812 prf = create(alg);
813 if (prf)
814 {
815 char bytes[prf->get_block_size(prf)];
816 chunk_t buf;
817 struct timespec start;
818 u_int runs;
819
820 buf = chunk_alloc(this->bench_size);
821 memset(buf.ptr, 0x34, buf.len);
822
823 runs = 0;
824 start_timing(&start);
825 while (end_timing(&start) < this->bench_time)
826 {
827 if (prf->get_bytes(prf, buf, bytes))
828 {
829 runs++;
830 }
831 }
832 free(buf.ptr);
833 prf->destroy(prf);
834
835 return runs;
836 }
837 return 0;
838 }
839
840 METHOD(crypto_tester_t, test_prf, bool,
841 private_crypto_tester_t *this, pseudo_random_function_t alg,
842 prf_constructor_t create, u_int *speed, const char *plugin_name)
843 {
844 enumerator_t *enumerator;
845 prf_test_vector_t *vector;
846 bool failed = FALSE;
847 u_int tested = 0;
848
849 enumerator = this->prf->create_enumerator(this->prf);
850 while (enumerator->enumerate(enumerator, &vector))
851 {
852 prf_t *prf;
853 chunk_t key, seed, out;
854
855 if (vector->alg != alg)
856 {
857 continue;
858 }
859
860 tested++;
861 prf = create(alg);
862 if (!prf)
863 {
864 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
865 pseudo_random_function_names, alg, plugin_name);
866 failed = TRUE;
867 break;
868 }
869
870 failed = FALSE;
871
872 key = chunk_create(vector->key, vector->key_size);
873 if (!prf->set_key(prf, key))
874 {
875 failed = TRUE;
876 }
877
878 /* allocated bytes */
879 seed = chunk_create(vector->seed, vector->len);
880 if (!prf->allocate_bytes(prf, seed, &out))
881 {
882 failed = TRUE;
883 }
884 if (out.len != prf->get_block_size(prf))
885 {
886 failed = TRUE;
887 }
888 if (!memeq(vector->out, out.ptr, out.len))
889 {
890 failed = TRUE;
891 }
892 /* bytes to existing buffer */
893 memset(out.ptr, 0, out.len);
894 if (vector->stateful)
895 {
896 if (!prf->set_key(prf, key))
897 {
898 failed = TRUE;
899 }
900 }
901 if (!prf->get_bytes(prf, seed, out.ptr))
902 {
903 failed = TRUE;
904 }
905 if (!memeq(vector->out, out.ptr, out.len))
906 {
907 failed = TRUE;
908 }
909 /* bytes to existing buffer, using append mode */
910 if (seed.len > 2)
911 {
912 memset(out.ptr, 0, out.len);
913 if (vector->stateful)
914 {
915 if (!prf->set_key(prf, key))
916 {
917 failed = TRUE;
918 }
919 }
920 if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL) ||
921 !prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL) ||
922 !prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
923 {
924 failed = TRUE;
925 }
926 if (!memeq(vector->out, out.ptr, out.len))
927 {
928 failed = TRUE;
929 }
930 }
931 free(out.ptr);
932
933 prf->destroy(prf);
934 if (failed)
935 {
936 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
937 pseudo_random_function_names, alg, plugin_name, get_name(vector));
938 break;
939 }
940 }
941 enumerator->destroy(enumerator);
942 if (!tested)
943 {
944 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
945 this->required ? "disabled" : "enabled ",
946 pseudo_random_function_names, alg, plugin_name);
947 return !this->required;
948 }
949 if (!failed)
950 {
951 if (speed)
952 {
953 *speed = bench_prf(this, alg, create);
954 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
955 pseudo_random_function_names, alg, plugin_name, tested, *speed);
956 }
957 else
958 {
959 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
960 pseudo_random_function_names, alg, plugin_name, tested);
961 }
962 }
963 return !failed;
964 }
965
966 /**
967 * Benchmark a RNG
968 */
969 static u_int bench_rng(private_crypto_tester_t *this,
970 rng_quality_t quality, rng_constructor_t create)
971 {
972 rng_t *rng;
973
974 rng = create(quality);
975 if (rng)
976 {
977 struct timespec start;
978 chunk_t buf;
979 u_int runs;
980
981 runs = 0;
982 buf = chunk_alloc(this->bench_size);
983 start_timing(&start);
984 while (end_timing(&start) < this->bench_time)
985 {
986 if (!rng->get_bytes(rng, buf.len, buf.ptr))
987 {
988 runs = 0;
989 break;
990 }
991 runs++;
992 }
993 free(buf.ptr);
994 rng->destroy(rng);
995
996 return runs;
997 }
998 return 0;
999 }
1000
1001 METHOD(crypto_tester_t, test_rng, bool,
1002 private_crypto_tester_t *this, rng_quality_t quality,
1003 rng_constructor_t create, u_int *speed, const char *plugin_name)
1004 {
1005 enumerator_t *enumerator;
1006 rng_test_vector_t *vector;
1007 bool failed = FALSE;
1008 u_int tested = 0;
1009
1010 if (!this->rng_true && quality == RNG_TRUE)
1011 {
1012 DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
1013 rng_quality_names, quality, plugin_name);
1014 return TRUE;
1015 }
1016
1017 enumerator = this->rng->create_enumerator(this->rng);
1018 while (enumerator->enumerate(enumerator, &vector))
1019 {
1020 chunk_t data = chunk_empty;
1021 rng_t *rng;
1022
1023 if (vector->quality != quality)
1024 {
1025 continue;
1026 }
1027
1028 tested++;
1029 rng = create(quality);
1030 if (!rng)
1031 {
1032 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1033 rng_quality_names, quality, plugin_name);
1034 failed = TRUE;
1035 break;
1036 }
1037
1038 failed = FALSE;
1039
1040 /* allocated bytes */
1041 if (!rng->allocate_bytes(rng, vector->len, &data) ||
1042 data.len != vector->len ||
1043 !vector->test(vector->user, data))
1044 {
1045 failed = TRUE;
1046 }
1047 if (!failed)
1048 { /* write bytes into existing buffer */
1049 memset(data.ptr, 0, data.len);
1050 if (!rng->get_bytes(rng, vector->len, data.ptr) ||
1051 !vector->test(vector->user, data))
1052 {
1053 failed = TRUE;
1054 }
1055 }
1056 free(data.ptr);
1057 rng->destroy(rng);
1058 if (failed)
1059 {
1060 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1061 rng_quality_names, quality, plugin_name, get_name(vector));
1062 break;
1063 }
1064 }
1065 enumerator->destroy(enumerator);
1066 if (!tested)
1067 {
1068 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1069 this->required ? ", disabled" : "enabled ",
1070 rng_quality_names, quality, plugin_name);
1071 return !this->required;
1072 }
1073 if (!failed)
1074 {
1075 if (speed)
1076 {
1077 *speed = bench_rng(this, quality, create);
1078 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1079 rng_quality_names, quality, plugin_name, tested, *speed);
1080 }
1081 else
1082 {
1083 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1084 rng_quality_names, quality, plugin_name, tested);
1085 }
1086 }
1087 return !failed;
1088 }
1089
1090 METHOD(crypto_tester_t, add_crypter_vector, void,
1091 private_crypto_tester_t *this, crypter_test_vector_t *vector)
1092 {
1093 this->crypter->insert_last(this->crypter, vector);
1094 }
1095
1096 METHOD(crypto_tester_t, add_aead_vector, void,
1097 private_crypto_tester_t *this, aead_test_vector_t *vector)
1098 {
1099 this->aead->insert_last(this->aead, vector);
1100 }
1101
1102 METHOD(crypto_tester_t, add_signer_vector, void,
1103 private_crypto_tester_t *this, signer_test_vector_t *vector)
1104 {
1105 this->signer->insert_last(this->signer, vector);
1106 }
1107
1108 METHOD(crypto_tester_t, add_hasher_vector, void,
1109 private_crypto_tester_t *this, hasher_test_vector_t *vector)
1110 {
1111 this->hasher->insert_last(this->hasher, vector);
1112 }
1113
1114 METHOD(crypto_tester_t, add_prf_vector, void,
1115 private_crypto_tester_t *this, prf_test_vector_t *vector)
1116 {
1117 this->prf->insert_last(this->prf, vector);
1118 }
1119
1120 METHOD(crypto_tester_t, add_rng_vector, void,
1121 private_crypto_tester_t *this, rng_test_vector_t *vector)
1122 {
1123 this->rng->insert_last(this->rng, vector);
1124 }
1125
1126 METHOD(crypto_tester_t, destroy, void,
1127 private_crypto_tester_t *this)
1128 {
1129 this->crypter->destroy(this->crypter);
1130 this->aead->destroy(this->aead);
1131 this->signer->destroy(this->signer);
1132 this->hasher->destroy(this->hasher);
1133 this->prf->destroy(this->prf);
1134 this->rng->destroy(this->rng);
1135 free(this);
1136 }
1137
1138 /**
1139 * See header
1140 */
1141 crypto_tester_t *crypto_tester_create()
1142 {
1143 private_crypto_tester_t *this;
1144
1145 INIT(this,
1146 .public = {
1147 .test_crypter = _test_crypter,
1148 .test_aead = _test_aead,
1149 .test_signer = _test_signer,
1150 .test_hasher = _test_hasher,
1151 .test_prf = _test_prf,
1152 .test_rng = _test_rng,
1153 .add_crypter_vector = _add_crypter_vector,
1154 .add_aead_vector = _add_aead_vector,
1155 .add_signer_vector = _add_signer_vector,
1156 .add_hasher_vector = _add_hasher_vector,
1157 .add_prf_vector = _add_prf_vector,
1158 .add_rng_vector = _add_rng_vector,
1159 .destroy = _destroy,
1160 },
1161 .crypter = linked_list_create(),
1162 .aead = linked_list_create(),
1163 .signer = linked_list_create(),
1164 .hasher = linked_list_create(),
1165 .prf = linked_list_create(),
1166 .rng = linked_list_create(),
1167
1168 .required = lib->settings->get_bool(lib->settings,
1169 "libstrongswan.crypto_test.required", FALSE),
1170 .rng_true = lib->settings->get_bool(lib->settings,
1171 "libstrongswan.crypto_test.rng_true", FALSE),
1172 .bench_time = lib->settings->get_int(lib->settings,
1173 "libstrongswan.crypto_test.bench_time", 50),
1174 .bench_size = lib->settings->get_int(lib->settings,
1175 "libstrongswan.crypto_test.bench_size", 1024),
1176 );
1177
1178 /* enforce a block size of 16, should be fine for all algorithms */
1179 this->bench_size = this->bench_size / 16 * 16;
1180
1181 return &this->public;
1182 }
1183