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