948d30618b4c87f2dd74f13d8676f0227f085f28
[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 if (!hasher->allocate_hash(hasher, data, &hash))
739 {
740 failed = TRUE;
741 }
742 if (hash.len != hasher->get_hash_size(hasher))
743 {
744 failed = TRUE;
745 }
746 if (!memeq(vector->hash, hash.ptr, hash.len))
747 {
748 failed = TRUE;
749 }
750 /* hash to existing buffer */
751 memset(hash.ptr, 0, hash.len);
752 if (!hasher->get_hash(hasher, data, hash.ptr))
753 {
754 failed = TRUE;
755 }
756 if (!memeq(vector->hash, hash.ptr, hash.len))
757 {
758 failed = TRUE;
759 }
760 /* hasher to existing buffer, using append mode */
761 if (data.len > 2)
762 {
763 memset(hash.ptr, 0, hash.len);
764 if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL) ||
765 !hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL) ||
766 !hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr) ||
767 !memeq(vector->hash, hash.ptr, hash.len))
768 {
769 failed = TRUE;
770 }
771 }
772 free(hash.ptr);
773
774 hasher->destroy(hasher);
775 if (failed)
776 {
777 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
778 hash_algorithm_names, alg, plugin_name, get_name(vector));
779 break;
780 }
781 }
782 enumerator->destroy(enumerator);
783 if (!tested)
784 {
785 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
786 this->required ? "disabled" : "enabled ",
787 hash_algorithm_names, alg, plugin_name);
788 return !this->required;
789 }
790 if (!failed)
791 {
792 if (speed)
793 {
794 *speed = bench_hasher(this, alg, create);
795 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
796 hash_algorithm_names, alg, plugin_name, tested, *speed);
797 }
798 else
799 {
800 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
801 hash_algorithm_names, alg, plugin_name, tested);
802 }
803 }
804 return !failed;
805 }
806
807 /**
808 * Benchmark a PRF
809 */
810 static u_int bench_prf(private_crypto_tester_t *this,
811 pseudo_random_function_t alg, prf_constructor_t create)
812 {
813 prf_t *prf;
814
815 prf = create(alg);
816 if (prf)
817 {
818 char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)];
819 chunk_t buf;
820 struct timespec start;
821 u_int runs;
822
823 memset(key, 0x56, prf->get_block_size(prf));
824 if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf))))
825 {
826 prf->destroy(prf);
827 return 0;
828 }
829
830 buf = chunk_alloc(this->bench_size);
831 memset(buf.ptr, 0x34, buf.len);
832
833 runs = 0;
834 start_timing(&start);
835 while (end_timing(&start) < this->bench_time)
836 {
837 if (prf->get_bytes(prf, buf, bytes))
838 {
839 runs++;
840 }
841 }
842 free(buf.ptr);
843 prf->destroy(prf);
844
845 return runs;
846 }
847 return 0;
848 }
849
850 METHOD(crypto_tester_t, test_prf, bool,
851 private_crypto_tester_t *this, pseudo_random_function_t alg,
852 prf_constructor_t create, u_int *speed, const char *plugin_name)
853 {
854 enumerator_t *enumerator;
855 prf_test_vector_t *vector;
856 bool failed = FALSE;
857 u_int tested = 0;
858
859 enumerator = this->prf->create_enumerator(this->prf);
860 while (enumerator->enumerate(enumerator, &vector))
861 {
862 prf_t *prf;
863 chunk_t key, seed, out;
864
865 if (vector->alg != alg)
866 {
867 continue;
868 }
869
870 tested++;
871 prf = create(alg);
872 if (!prf)
873 {
874 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
875 pseudo_random_function_names, alg, plugin_name);
876 failed = TRUE;
877 break;
878 }
879
880 failed = FALSE;
881
882 key = chunk_create(vector->key, vector->key_size);
883 if (!prf->set_key(prf, key))
884 {
885 failed = TRUE;
886 }
887
888 /* allocated bytes */
889 seed = chunk_create(vector->seed, vector->len);
890 if (!prf->allocate_bytes(prf, seed, &out))
891 {
892 failed = TRUE;
893 }
894 if (out.len != prf->get_block_size(prf))
895 {
896 failed = TRUE;
897 }
898 if (!memeq(vector->out, out.ptr, out.len))
899 {
900 failed = TRUE;
901 }
902 /* bytes to existing buffer */
903 memset(out.ptr, 0, out.len);
904 if (vector->stateful)
905 {
906 if (!prf->set_key(prf, key))
907 {
908 failed = TRUE;
909 }
910 }
911 if (!prf->get_bytes(prf, seed, out.ptr))
912 {
913 failed = TRUE;
914 }
915 if (!memeq(vector->out, out.ptr, out.len))
916 {
917 failed = TRUE;
918 }
919 /* bytes to existing buffer, using append mode */
920 if (seed.len > 2)
921 {
922 memset(out.ptr, 0, out.len);
923 if (vector->stateful)
924 {
925 if (!prf->set_key(prf, key))
926 {
927 failed = TRUE;
928 }
929 }
930 if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL) ||
931 !prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL) ||
932 !prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
933 {
934 failed = TRUE;
935 }
936 if (!memeq(vector->out, out.ptr, out.len))
937 {
938 failed = TRUE;
939 }
940 }
941 free(out.ptr);
942
943 prf->destroy(prf);
944 if (failed)
945 {
946 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
947 pseudo_random_function_names, alg, plugin_name, get_name(vector));
948 break;
949 }
950 }
951 enumerator->destroy(enumerator);
952 if (!tested)
953 {
954 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
955 this->required ? "disabled" : "enabled ",
956 pseudo_random_function_names, alg, plugin_name);
957 return !this->required;
958 }
959 if (!failed)
960 {
961 if (speed)
962 {
963 *speed = bench_prf(this, alg, create);
964 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
965 pseudo_random_function_names, alg, plugin_name, tested, *speed);
966 }
967 else
968 {
969 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
970 pseudo_random_function_names, alg, plugin_name, tested);
971 }
972 }
973 return !failed;
974 }
975
976 /**
977 * Benchmark a RNG
978 */
979 static u_int bench_rng(private_crypto_tester_t *this,
980 rng_quality_t quality, rng_constructor_t create)
981 {
982 rng_t *rng;
983
984 rng = create(quality);
985 if (rng)
986 {
987 struct timespec start;
988 chunk_t buf;
989 u_int runs;
990
991 runs = 0;
992 buf = chunk_alloc(this->bench_size);
993 start_timing(&start);
994 while (end_timing(&start) < this->bench_time)
995 {
996 if (!rng->get_bytes(rng, buf.len, buf.ptr))
997 {
998 runs = 0;
999 break;
1000 }
1001 runs++;
1002 }
1003 free(buf.ptr);
1004 rng->destroy(rng);
1005
1006 return runs;
1007 }
1008 return 0;
1009 }
1010
1011 METHOD(crypto_tester_t, test_rng, bool,
1012 private_crypto_tester_t *this, rng_quality_t quality,
1013 rng_constructor_t create, u_int *speed, const char *plugin_name)
1014 {
1015 enumerator_t *enumerator;
1016 rng_test_vector_t *vector;
1017 bool failed = FALSE;
1018 u_int tested = 0;
1019
1020 if (!this->rng_true && quality == RNG_TRUE)
1021 {
1022 DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
1023 rng_quality_names, quality, plugin_name);
1024 return TRUE;
1025 }
1026
1027 enumerator = this->rng->create_enumerator(this->rng);
1028 while (enumerator->enumerate(enumerator, &vector))
1029 {
1030 chunk_t data = chunk_empty;
1031 rng_t *rng;
1032
1033 if (vector->quality != quality)
1034 {
1035 continue;
1036 }
1037
1038 tested++;
1039 rng = create(quality);
1040 if (!rng)
1041 {
1042 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1043 rng_quality_names, quality, plugin_name);
1044 failed = TRUE;
1045 break;
1046 }
1047
1048 failed = FALSE;
1049
1050 /* allocated bytes */
1051 if (!rng->allocate_bytes(rng, vector->len, &data) ||
1052 data.len != vector->len ||
1053 !vector->test(vector->user, data))
1054 {
1055 failed = TRUE;
1056 }
1057 if (!failed)
1058 { /* write bytes into existing buffer */
1059 memset(data.ptr, 0, data.len);
1060 if (!rng->get_bytes(rng, vector->len, data.ptr) ||
1061 !vector->test(vector->user, data))
1062 {
1063 failed = TRUE;
1064 }
1065 }
1066 free(data.ptr);
1067 rng->destroy(rng);
1068 if (failed)
1069 {
1070 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1071 rng_quality_names, quality, plugin_name, get_name(vector));
1072 break;
1073 }
1074 }
1075 enumerator->destroy(enumerator);
1076 if (!tested)
1077 {
1078 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1079 this->required ? ", disabled" : "enabled ",
1080 rng_quality_names, quality, plugin_name);
1081 return !this->required;
1082 }
1083 if (!failed)
1084 {
1085 if (speed)
1086 {
1087 *speed = bench_rng(this, quality, create);
1088 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1089 rng_quality_names, quality, plugin_name, tested, *speed);
1090 }
1091 else
1092 {
1093 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1094 rng_quality_names, quality, plugin_name, tested);
1095 }
1096 }
1097 return !failed;
1098 }
1099
1100 METHOD(crypto_tester_t, add_crypter_vector, void,
1101 private_crypto_tester_t *this, crypter_test_vector_t *vector)
1102 {
1103 this->crypter->insert_last(this->crypter, vector);
1104 }
1105
1106 METHOD(crypto_tester_t, add_aead_vector, void,
1107 private_crypto_tester_t *this, aead_test_vector_t *vector)
1108 {
1109 this->aead->insert_last(this->aead, vector);
1110 }
1111
1112 METHOD(crypto_tester_t, add_signer_vector, void,
1113 private_crypto_tester_t *this, signer_test_vector_t *vector)
1114 {
1115 this->signer->insert_last(this->signer, vector);
1116 }
1117
1118 METHOD(crypto_tester_t, add_hasher_vector, void,
1119 private_crypto_tester_t *this, hasher_test_vector_t *vector)
1120 {
1121 this->hasher->insert_last(this->hasher, vector);
1122 }
1123
1124 METHOD(crypto_tester_t, add_prf_vector, void,
1125 private_crypto_tester_t *this, prf_test_vector_t *vector)
1126 {
1127 this->prf->insert_last(this->prf, vector);
1128 }
1129
1130 METHOD(crypto_tester_t, add_rng_vector, void,
1131 private_crypto_tester_t *this, rng_test_vector_t *vector)
1132 {
1133 this->rng->insert_last(this->rng, vector);
1134 }
1135
1136 METHOD(crypto_tester_t, destroy, void,
1137 private_crypto_tester_t *this)
1138 {
1139 this->crypter->destroy(this->crypter);
1140 this->aead->destroy(this->aead);
1141 this->signer->destroy(this->signer);
1142 this->hasher->destroy(this->hasher);
1143 this->prf->destroy(this->prf);
1144 this->rng->destroy(this->rng);
1145 free(this);
1146 }
1147
1148 /**
1149 * See header
1150 */
1151 crypto_tester_t *crypto_tester_create()
1152 {
1153 private_crypto_tester_t *this;
1154
1155 INIT(this,
1156 .public = {
1157 .test_crypter = _test_crypter,
1158 .test_aead = _test_aead,
1159 .test_signer = _test_signer,
1160 .test_hasher = _test_hasher,
1161 .test_prf = _test_prf,
1162 .test_rng = _test_rng,
1163 .add_crypter_vector = _add_crypter_vector,
1164 .add_aead_vector = _add_aead_vector,
1165 .add_signer_vector = _add_signer_vector,
1166 .add_hasher_vector = _add_hasher_vector,
1167 .add_prf_vector = _add_prf_vector,
1168 .add_rng_vector = _add_rng_vector,
1169 .destroy = _destroy,
1170 },
1171 .crypter = linked_list_create(),
1172 .aead = linked_list_create(),
1173 .signer = linked_list_create(),
1174 .hasher = linked_list_create(),
1175 .prf = linked_list_create(),
1176 .rng = linked_list_create(),
1177
1178 .required = lib->settings->get_bool(lib->settings,
1179 "libstrongswan.crypto_test.required", FALSE),
1180 .rng_true = lib->settings->get_bool(lib->settings,
1181 "libstrongswan.crypto_test.rng_true", FALSE),
1182 .bench_time = lib->settings->get_int(lib->settings,
1183 "libstrongswan.crypto_test.bench_time", 50),
1184 .bench_size = lib->settings->get_int(lib->settings,
1185 "libstrongswan.crypto_test.bench_size", 1024),
1186 );
1187
1188 /* enforce a block size of 16, should be fine for all algorithms */
1189 this->bench_size = this->bench_size / 16 * 16;
1190
1191 return &this->public;
1192 }
1193