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