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