]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/crypto/crypto_tester.c
Add a return value to hasher_t.allocate_hash()
[thirdparty/strongswan.git] / src / libstrongswan / crypto / crypto_tester.c
CommitLineData
3e889166 1/*
1b0eff58 2 * Copyright (C) 2009-2010 Martin Willi
3e889166 3 * Hochschule fuer Technik Rapperswil
1b0eff58 4 * Copyright (C) 2010 revosec AG
3e889166
MW
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
bfe4d08c
MW
17#define _GNU_SOURCE
18#include <dlfcn.h>
1b0eff58 19#include <time.h>
bfe4d08c 20
3e889166
MW
21#include "crypto_tester.h"
22
23#include <debug.h>
24#include <utils/linked_list.h>
25
26typedef struct private_crypto_tester_t private_crypto_tester_t;
27
28/**
29 * Private data of an crypto_tester_t object.
30 */
31struct private_crypto_tester_t {
7daf5226 32
3e889166
MW
33 /**
34 * Public crypto_tester_t interface.
35 */
36 crypto_tester_t public;
7daf5226 37
3e889166
MW
38 /**
39 * List of crypter test vectors
40 */
41 linked_list_t *crypter;
7daf5226 42
e09a87d6
MW
43 /**
44 * List of aead test vectors
45 */
46 linked_list_t *aead;
47
3e889166
MW
48 /**
49 * List of signer test vectors
50 */
51 linked_list_t *signer;
7daf5226 52
3e889166
MW
53 /**
54 * List of hasher test vectors
55 */
56 linked_list_t *hasher;
7daf5226 57
3e889166
MW
58 /**
59 * List of PRF test vectors
60 */
61 linked_list_t *prf;
7daf5226 62
3e889166
MW
63 /**
64 * List of RNG test vectors
65 */
66 linked_list_t *rng;
7daf5226 67
3e889166
MW
68 /**
69 * Is a test vector required to pass a test?
70 */
71 bool required;
7daf5226 72
3e889166
MW
73 /**
74 * should we run RNG_TRUE tests? Enough entropy?
75 */
76 bool rng_true;
1b0eff58
MW
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;
3e889166
MW
87};
88
bfe4d08c
MW
89/**
90 * Get the name of a test vector, if available
91 */
92static 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
7171d876
TB
105#ifdef CLOCK_THREAD_CPUTIME_ID
106
1b0eff58
MW
107/**
108 * Start a benchmark timer
109 */
110static 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 */
118static 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
7171d876
TB
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
1b0eff58
MW
135/**
136 * Benchmark a crypter
137 */
138static 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));
ce73fc19
MW
154 if (!crypter->set_key(crypter, chunk_from_thing(key)))
155 {
156 return 0;
157 }
1b0eff58
MW
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 {
e35abbe5
MW
166 if (crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL))
167 {
168 runs++;
169 }
3b96189a
MW
170 if (crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL))
171 {
172 runs++;
173 }
1b0eff58
MW
174 }
175 free(buf.ptr);
176 crypter->destroy(crypter);
177
178 return runs;
179 }
180 return 0;
181}
182
aed2bf0b
MW
183METHOD(crypto_tester_t, test_crypter, bool,
184 private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
5932f41f 185 crypter_constructor_t create, u_int *speed, const char *plugin_name)
3e889166
MW
186{
187 enumerator_t *enumerator;
188 crypter_test_vector_t *vector;
189 bool failed = FALSE;
190 u_int tested = 0;
7daf5226 191
3e889166
MW
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;
7daf5226 197
3e889166
MW
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)
c6a043fa
AS
208 {
209 DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
90288c76
AS
210 encryption_algorithm_names, alg, plugin_name,
211 BITS_PER_BYTE * vector->key_size);
d733a3ba 212 failed = TRUE;
3e889166
MW
213 continue;
214 }
7daf5226 215
3e889166
MW
216 failed = FALSE;
217 tested++;
7daf5226 218
3e889166 219 key = chunk_create(vector->key, crypter->get_key_size(crypter));
ce73fc19
MW
220 if (!crypter->set_key(crypter, key))
221 {
222 failed = TRUE;
223 }
3102d866 224 iv = chunk_create(vector->iv, crypter->get_iv_size(crypter));
7daf5226 225
3e889166
MW
226 /* allocated encryption */
227 plain = chunk_create(vector->plain, vector->len);
e35abbe5
MW
228 if (!crypter->encrypt(crypter, plain, iv, &cipher))
229 {
230 failed = TRUE;
231 }
3e889166
MW
232 if (!memeq(vector->cipher, cipher.ptr, cipher.len))
233 {
234 failed = TRUE;
235 }
236 /* inline decryption */
3b96189a
MW
237 if (!crypter->decrypt(crypter, cipher, iv, NULL))
238 {
239 failed = TRUE;
240 }
3e889166
MW
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);
3b96189a
MW
248 if (!crypter->decrypt(crypter, cipher, iv, &plain))
249 {
250 failed = TRUE;
251 }
3e889166
MW
252 if (!memeq(vector->plain, plain.ptr, plain.len))
253 {
254 failed = TRUE;
255 }
256 /* inline encryption */
e35abbe5
MW
257 if (!crypter->encrypt(crypter, plain, iv, NULL))
258 {
259 failed = TRUE;
260 }
3e889166
MW
261 if (!memeq(vector->cipher, plain.ptr, plain.len))
262 {
263 failed = TRUE;
264 }
265 free(plain.ptr);
7daf5226 266
3e889166
MW
267 crypter->destroy(crypter);
268 if (failed)
269 {
5932f41f
AS
270 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
271 encryption_algorithm_names, alg, plugin_name, get_name(vector));
3e889166
MW
272 break;
273 }
3e889166
MW
274 }
275 enumerator->destroy(enumerator);
276 if (!tested)
277 {
d733a3ba
AS
278 if (failed)
279 {
280 DBG1(DBG_LIB,"disable %N[%s]: no key size supported",
281 encryption_algorithm_names, alg, plugin_name);
6dc36a73 282 return FALSE;
d733a3ba
AS
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 }
3e889166
MW
291 }
292 if (!failed)
293 {
1b0eff58
MW
294 if (speed)
295 {
296 *speed = bench_crypter(this, alg, create);
5932f41f 297 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
6dc36a73 298 encryption_algorithm_names, alg, plugin_name, tested, *speed);
1b0eff58
MW
299 }
300 else
301 {
5932f41f
AS
302 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
303 encryption_algorithm_names, alg, plugin_name, tested);
1b0eff58 304 }
3e889166
MW
305 }
306 return !failed;
307}
308
e09a87d6
MW
309/**
310 * Benchmark an aead transform
311 */
312static 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));
ad08730a
MW
331 if (!aead->set_key(aead, chunk_from_thing(key)))
332 {
333 return 0;
334 }
e09a87d6
MW
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 {
e2ed7bfd
MW
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 }
e09a87d6
MW
355 }
356 free(buf.ptr);
357 aead->destroy(aead);
358
359 return runs;
360 }
361 return 0;
362}
363
364METHOD(crypto_tester_t, test_aead, bool,
365 private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
5932f41f 366 aead_constructor_t create, u_int *speed, const char *plugin_name)
e09a87d6
MW
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)
c6a043fa
AS
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);
690d5aed 394 failed = TRUE;
e09a87d6
MW
395 continue;
396 }
397
398 failed = FALSE;
399 tested++;
400
401 key = chunk_create(vector->key, aead->get_key_size(aead));
ad08730a
MW
402 if (!aead->set_key(aead, key))
403 {
404 failed = TRUE;
405 }
e09a87d6
MW
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);
e2ed7bfd
MW
412 if (!aead->encrypt(aead, plain, assoc, iv, &cipher))
413 {
414 failed = TRUE;
415 }
e09a87d6
MW
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 */
e2ed7bfd
MW
443 if (!aead->encrypt(aead, plain, assoc, iv, NULL))
444 {
445 failed = TRUE;
446 }
e09a87d6
MW
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 {
5932f41f
AS
456 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
457 encryption_algorithm_names, alg, plugin_name, get_name(vector));
e09a87d6
MW
458 break;
459 }
460 }
461 enumerator->destroy(enumerator);
462 if (!tested)
463 {
d733a3ba
AS
464 if (failed)
465 {
466 DBG1(DBG_LIB,"disable %N[%s]: no key size supported",
467 encryption_algorithm_names, alg, plugin_name);
6dc36a73 468 return FALSE;
d733a3ba
AS
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 }
e09a87d6
MW
477 }
478 if (!failed)
479 {
480 if (speed)
481 {
482 *speed = bench_aead(this, alg, create);
5932f41f
AS
483 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
484 encryption_algorithm_names, alg, plugin_name, tested, *speed);
e09a87d6
MW
485 }
486 else
487 {
5932f41f
AS
488 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
489 encryption_algorithm_names, alg, plugin_name, tested);
e09a87d6
MW
490 }
491 }
492 return !failed;
493}
494
1b0eff58
MW
495/**
496 * Benchmark a signer
497 */
498static u_int bench_signer(private_crypto_tester_t *this,
1b82fdb2 499 integrity_algorithm_t alg, signer_constructor_t create)
1b0eff58
MW
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));
2d56575d
MW
513 if (!signer->set_key(signer, chunk_from_thing(key)))
514 {
515 return 0;
516 }
1b0eff58
MW
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 {
2e96de60
MW
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 }
1b0eff58
MW
533 }
534 free(buf.ptr);
535 signer->destroy(signer);
536
537 return runs;
538 }
539 return 0;
540}
541
aed2bf0b
MW
542METHOD(crypto_tester_t, test_signer, bool,
543 private_crypto_tester_t *this, integrity_algorithm_t alg,
5932f41f 544 signer_constructor_t create, u_int *speed, const char *plugin_name)
3e889166
MW
545{
546 enumerator_t *enumerator;
547 signer_test_vector_t *vector;
548 bool failed = FALSE;
549 u_int tested = 0;
7daf5226 550
3e889166
MW
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;
7daf5226 556
3e889166
MW
557 if (vector->alg != alg)
558 {
559 continue;
560 }
7daf5226 561
3e889166
MW
562 tested++;
563 signer = create(alg);
564 if (!signer)
565 {
5932f41f
AS
566 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
567 integrity_algorithm_names, alg, plugin_name);
3e889166
MW
568 failed = TRUE;
569 break;
570 }
7daf5226 571
3e889166 572 failed = FALSE;
7daf5226 573
3e889166 574 key = chunk_create(vector->key, signer->get_key_size(signer));
2d56575d
MW
575 if (!signer->set_key(signer, key))
576 {
577 failed = TRUE;
578 }
3e889166
MW
579 /* allocated signature */
580 data = chunk_create(vector->data, vector->len);
cbfbba7d
MW
581 if (!signer->allocate_signature(signer, data, &mac))
582 {
583 failed = TRUE;
584 }
3e889166
MW
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);
2e96de60
MW
595 if (!signer->get_signature(signer, data, mac.ptr))
596 {
597 failed = TRUE;
598 }
3e889166
MW
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 {
cbfbba7d
MW
617 if (!signer->allocate_signature(signer,
618 chunk_create(data.ptr, 1), NULL))
619 {
620 failed = TRUE;
621 }
2e96de60
MW
622 if (!signer->get_signature(signer,
623 chunk_create(data.ptr + 1, 1), NULL))
624 {
625 failed = TRUE;
626 }
6c620d5e
MW
627 if (!signer->verify_signature(signer, chunk_skip(data, 2),
628 chunk_create(vector->mac, mac.len)))
3e889166
MW
629 {
630 failed = TRUE;
631 }
632 }
633 free(mac.ptr);
7daf5226 634
3e889166
MW
635 signer->destroy(signer);
636 if (failed)
637 {
5932f41f
AS
638 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
639 integrity_algorithm_names, alg, plugin_name, get_name(vector));
3e889166
MW
640 break;
641 }
3e889166
MW
642 }
643 enumerator->destroy(enumerator);
644 if (!tested)
645 {
5932f41f 646 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
b07ffa24 647 this->required ? "disabled" : "enabled ",
5932f41f 648 integrity_algorithm_names, alg, plugin_name);
3e889166
MW
649 return !this->required;
650 }
651 if (!failed)
652 {
1b0eff58
MW
653 if (speed)
654 {
655 *speed = bench_signer(this, alg, create);
5932f41f
AS
656 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
657 integrity_algorithm_names, alg, plugin_name, tested, *speed);
1b0eff58
MW
658 }
659 else
660 {
5932f41f
AS
661 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
662 integrity_algorithm_names, alg, plugin_name, tested);
1b0eff58 663 }
3e889166
MW
664 }
665 return !failed;
666}
667
1b0eff58
MW
668/**
669 * Benchmark a hasher
670 */
671static 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 {
8bd6a30a
MW
691 if (hasher->get_hash(hasher, buf, hash))
692 {
693 runs++;
694 }
1b0eff58
MW
695 }
696 free(buf.ptr);
697 hasher->destroy(hasher);
698
699 return runs;
700 }
701 return 0;
702}
703
aed2bf0b
MW
704METHOD(crypto_tester_t, test_hasher, bool,
705 private_crypto_tester_t *this, hash_algorithm_t alg,
5932f41f 706 hasher_constructor_t create, u_int *speed, const char *plugin_name)
3e889166
MW
707{
708 enumerator_t *enumerator;
709 hasher_test_vector_t *vector;
710 bool failed = FALSE;
711 u_int tested = 0;
7daf5226 712
3e889166
MW
713 enumerator = this->hasher->create_enumerator(this->hasher);
714 while (enumerator->enumerate(enumerator, &vector))
715 {
716 hasher_t *hasher;
717 chunk_t data, hash;
7daf5226 718
3e889166
MW
719 if (vector->alg != alg)
720 {
721 continue;
722 }
7daf5226 723
3e889166
MW
724 tested++;
725 hasher = create(alg);
726 if (!hasher)
727 {
5932f41f
AS
728 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
729 hash_algorithm_names, alg, plugin_name);
3e889166
MW
730 failed = TRUE;
731 break;
732 }
7daf5226 733
3e889166 734 failed = FALSE;
7daf5226 735
3e889166
MW
736 /* allocated hash */
737 data = chunk_create(vector->data, vector->len);
87dd205b
MW
738 if (!hasher->allocate_hash(hasher, data, &hash))
739 {
740 failed = TRUE;
741 }
3e889166
MW
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);
8bd6a30a
MW
752 if (!hasher->get_hash(hasher, data, hash.ptr))
753 {
754 failed = TRUE;
755 }
3e889166
MW
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);
87dd205b
MW
764 if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL) ||
765 !hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL) ||
8bd6a30a
MW
766 !hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr) ||
767 !memeq(vector->hash, hash.ptr, hash.len))
3e889166
MW
768 {
769 failed = TRUE;
770 }
771 }
772 free(hash.ptr);
7daf5226 773
3e889166
MW
774 hasher->destroy(hasher);
775 if (failed)
776 {
5932f41f
AS
777 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
778 hash_algorithm_names, alg, plugin_name, get_name(vector));
3e889166
MW
779 break;
780 }
3e889166
MW
781 }
782 enumerator->destroy(enumerator);
783 if (!tested)
784 {
5932f41f 785 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
b07ffa24 786 this->required ? "disabled" : "enabled ",
5932f41f 787 hash_algorithm_names, alg, plugin_name);
3e889166
MW
788 return !this->required;
789 }
790 if (!failed)
791 {
1b0eff58
MW
792 if (speed)
793 {
794 *speed = bench_hasher(this, alg, create);
5932f41f
AS
795 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
796 hash_algorithm_names, alg, plugin_name, tested, *speed);
1b0eff58
MW
797 }
798 else
799 {
5932f41f
AS
800 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
801 hash_algorithm_names, alg, plugin_name, tested);
1b0eff58 802 }
3e889166
MW
803 }
804 return !failed;
805}
806
1b0eff58
MW
807/**
808 * Benchmark a PRF
809 */
810static 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)];
819 chunk_t buf;
820 struct timespec start;
821 u_int runs;
822
823 buf = chunk_alloc(this->bench_size);
824 memset(buf.ptr, 0x34, buf.len);
825
826 runs = 0;
827 start_timing(&start);
828 while (end_timing(&start) < this->bench_time)
829 {
bc474883
MW
830 if (prf->get_bytes(prf, buf, bytes))
831 {
832 runs++;
833 }
1b0eff58
MW
834 }
835 free(buf.ptr);
836 prf->destroy(prf);
837
838 return runs;
839 }
840 return 0;
841}
842
aed2bf0b
MW
843METHOD(crypto_tester_t, test_prf, bool,
844 private_crypto_tester_t *this, pseudo_random_function_t alg,
5932f41f 845 prf_constructor_t create, u_int *speed, const char *plugin_name)
3e889166
MW
846{
847 enumerator_t *enumerator;
848 prf_test_vector_t *vector;
849 bool failed = FALSE;
850 u_int tested = 0;
7daf5226 851
3e889166
MW
852 enumerator = this->prf->create_enumerator(this->prf);
853 while (enumerator->enumerate(enumerator, &vector))
854 {
855 prf_t *prf;
856 chunk_t key, seed, out;
7daf5226 857
3e889166
MW
858 if (vector->alg != alg)
859 {
860 continue;
861 }
7daf5226 862
3e889166
MW
863 tested++;
864 prf = create(alg);
865 if (!prf)
866 {
5932f41f
AS
867 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
868 pseudo_random_function_names, alg, plugin_name);
3e889166
MW
869 failed = TRUE;
870 break;
871 }
7daf5226 872
3e889166 873 failed = FALSE;
7daf5226 874
3e889166 875 key = chunk_create(vector->key, vector->key_size);
f3ca96b2
MW
876 if (!prf->set_key(prf, key))
877 {
878 failed = TRUE;
879 }
7daf5226 880
3e889166
MW
881 /* allocated bytes */
882 seed = chunk_create(vector->seed, vector->len);
ecc080b3
MW
883 if (!prf->allocate_bytes(prf, seed, &out))
884 {
885 failed = TRUE;
886 }
3e889166
MW
887 if (out.len != prf->get_block_size(prf))
888 {
889 failed = TRUE;
890 }
891 if (!memeq(vector->out, out.ptr, out.len))
892 {
893 failed = TRUE;
894 }
895 /* bytes to existing buffer */
896 memset(out.ptr, 0, out.len);
371a54c7
MW
897 if (vector->stateful)
898 {
f3ca96b2
MW
899 if (!prf->set_key(prf, key))
900 {
901 failed = TRUE;
902 }
371a54c7 903 }
bc474883
MW
904 if (!prf->get_bytes(prf, seed, out.ptr))
905 {
906 failed = TRUE;
907 }
3e889166
MW
908 if (!memeq(vector->out, out.ptr, out.len))
909 {
910 failed = TRUE;
911 }
912 /* bytes to existing buffer, using append mode */
913 if (seed.len > 2)
914 {
915 memset(out.ptr, 0, out.len);
371a54c7
MW
916 if (vector->stateful)
917 {
f3ca96b2
MW
918 if (!prf->set_key(prf, key))
919 {
920 failed = TRUE;
921 }
371a54c7 922 }
ecc080b3
MW
923 if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL) ||
924 !prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL) ||
bc474883
MW
925 !prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
926 {
927 failed = TRUE;
928 }
3e889166
MW
929 if (!memeq(vector->out, out.ptr, out.len))
930 {
931 failed = TRUE;
932 }
933 }
934 free(out.ptr);
7daf5226 935
3e889166
MW
936 prf->destroy(prf);
937 if (failed)
938 {
5932f41f
AS
939 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
940 pseudo_random_function_names, alg, plugin_name, get_name(vector));
3e889166
MW
941 break;
942 }
3e889166
MW
943 }
944 enumerator->destroy(enumerator);
945 if (!tested)
946 {
5932f41f 947 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
b07ffa24 948 this->required ? "disabled" : "enabled ",
5932f41f 949 pseudo_random_function_names, alg, plugin_name);
3e889166
MW
950 return !this->required;
951 }
952 if (!failed)
953 {
1b0eff58
MW
954 if (speed)
955 {
956 *speed = bench_prf(this, alg, create);
5932f41f
AS
957 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
958 pseudo_random_function_names, alg, plugin_name, tested, *speed);
1b0eff58
MW
959 }
960 else
961 {
5932f41f
AS
962 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
963 pseudo_random_function_names, alg, plugin_name, tested);
1b0eff58 964 }
3e889166
MW
965 }
966 return !failed;
967}
968
1b0eff58
MW
969/**
970 * Benchmark a RNG
971 */
972static u_int bench_rng(private_crypto_tester_t *this,
973 rng_quality_t quality, rng_constructor_t create)
974{
975 rng_t *rng;
976
977 rng = create(quality);
978 if (rng)
979 {
980 struct timespec start;
981 chunk_t buf;
982 u_int runs;
983
984 runs = 0;
985 buf = chunk_alloc(this->bench_size);
986 start_timing(&start);
987 while (end_timing(&start) < this->bench_time)
988 {
8a8364f2
TB
989 if (!rng->get_bytes(rng, buf.len, buf.ptr))
990 {
991 runs = 0;
992 break;
993 }
1b0eff58
MW
994 runs++;
995 }
996 free(buf.ptr);
997 rng->destroy(rng);
998
999 return runs;
1000 }
1001 return 0;
1002}
1003
aed2bf0b
MW
1004METHOD(crypto_tester_t, test_rng, bool,
1005 private_crypto_tester_t *this, rng_quality_t quality,
5932f41f 1006 rng_constructor_t create, u_int *speed, const char *plugin_name)
3e889166
MW
1007{
1008 enumerator_t *enumerator;
1009 rng_test_vector_t *vector;
1010 bool failed = FALSE;
1011 u_int tested = 0;
7daf5226 1012
3e889166
MW
1013 if (!this->rng_true && quality == RNG_TRUE)
1014 {
5932f41f
AS
1015 DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
1016 rng_quality_names, quality, plugin_name);
3e889166
MW
1017 return TRUE;
1018 }
7daf5226 1019
3e889166
MW
1020 enumerator = this->rng->create_enumerator(this->rng);
1021 while (enumerator->enumerate(enumerator, &vector))
1022 {
8a8364f2 1023 chunk_t data = chunk_empty;
3e889166 1024 rng_t *rng;
7daf5226 1025
3e889166
MW
1026 if (vector->quality != quality)
1027 {
1028 continue;
1029 }
7daf5226 1030
3e889166
MW
1031 tested++;
1032 rng = create(quality);
1033 if (!rng)
1034 {
5932f41f
AS
1035 DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1036 rng_quality_names, quality, plugin_name);
3e889166
MW
1037 failed = TRUE;
1038 break;
1039 }
7daf5226 1040
3e889166 1041 failed = FALSE;
7daf5226 1042
3e889166 1043 /* allocated bytes */
8a8364f2
TB
1044 if (!rng->allocate_bytes(rng, vector->len, &data) ||
1045 data.len != vector->len ||
1046 !vector->test(vector->user, data))
3e889166
MW
1047 {
1048 failed = TRUE;
1049 }
8a8364f2
TB
1050 if (!failed)
1051 { /* write bytes into existing buffer */
1052 memset(data.ptr, 0, data.len);
1053 if (!rng->get_bytes(rng, vector->len, data.ptr) ||
1054 !vector->test(vector->user, data))
1055 {
1056 failed = TRUE;
1057 }
3e889166
MW
1058 }
1059 free(data.ptr);
3e889166
MW
1060 rng->destroy(rng);
1061 if (failed)
1062 {
5932f41f
AS
1063 DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1064 rng_quality_names, quality, plugin_name, get_name(vector));
3e889166
MW
1065 break;
1066 }
3e889166
MW
1067 }
1068 enumerator->destroy(enumerator);
1069 if (!tested)
1070 {
5932f41f 1071 DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
b07ffa24 1072 this->required ? ", disabled" : "enabled ",
5932f41f 1073 rng_quality_names, quality, plugin_name);
3e889166
MW
1074 return !this->required;
1075 }
1076 if (!failed)
1077 {
1b0eff58
MW
1078 if (speed)
1079 {
1080 *speed = bench_rng(this, quality, create);
5932f41f
AS
1081 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
1082 rng_quality_names, quality, plugin_name, tested, *speed);
1b0eff58
MW
1083 }
1084 else
1085 {
5932f41f
AS
1086 DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
1087 rng_quality_names, quality, plugin_name, tested);
1b0eff58 1088 }
3e889166
MW
1089 }
1090 return !failed;
1091}
1092
aed2bf0b
MW
1093METHOD(crypto_tester_t, add_crypter_vector, void,
1094 private_crypto_tester_t *this, crypter_test_vector_t *vector)
3e889166
MW
1095{
1096 this->crypter->insert_last(this->crypter, vector);
1097}
1098
e09a87d6
MW
1099METHOD(crypto_tester_t, add_aead_vector, void,
1100 private_crypto_tester_t *this, aead_test_vector_t *vector)
1101{
1102 this->aead->insert_last(this->aead, vector);
1103}
1104
aed2bf0b
MW
1105METHOD(crypto_tester_t, add_signer_vector, void,
1106 private_crypto_tester_t *this, signer_test_vector_t *vector)
3e889166
MW
1107{
1108 this->signer->insert_last(this->signer, vector);
1109}
1110
aed2bf0b
MW
1111METHOD(crypto_tester_t, add_hasher_vector, void,
1112 private_crypto_tester_t *this, hasher_test_vector_t *vector)
3e889166
MW
1113{
1114 this->hasher->insert_last(this->hasher, vector);
1115}
1116
aed2bf0b
MW
1117METHOD(crypto_tester_t, add_prf_vector, void,
1118 private_crypto_tester_t *this, prf_test_vector_t *vector)
3e889166
MW
1119{
1120 this->prf->insert_last(this->prf, vector);
1121}
1122
aed2bf0b
MW
1123METHOD(crypto_tester_t, add_rng_vector, void,
1124 private_crypto_tester_t *this, rng_test_vector_t *vector)
3e889166
MW
1125{
1126 this->rng->insert_last(this->rng, vector);
1127}
1128
aed2bf0b
MW
1129METHOD(crypto_tester_t, destroy, void,
1130 private_crypto_tester_t *this)
3e889166
MW
1131{
1132 this->crypter->destroy(this->crypter);
e09a87d6 1133 this->aead->destroy(this->aead);
3e889166
MW
1134 this->signer->destroy(this->signer);
1135 this->hasher->destroy(this->hasher);
1136 this->prf->destroy(this->prf);
1137 this->rng->destroy(this->rng);
1138 free(this);
1139}
1140
1141/**
1142 * See header
1143 */
1144crypto_tester_t *crypto_tester_create()
1145{
aed2bf0b
MW
1146 private_crypto_tester_t *this;
1147
1148 INIT(this,
1149 .public = {
1150 .test_crypter = _test_crypter,
e09a87d6 1151 .test_aead = _test_aead,
aed2bf0b
MW
1152 .test_signer = _test_signer,
1153 .test_hasher = _test_hasher,
1154 .test_prf = _test_prf,
1155 .test_rng = _test_rng,
1156 .add_crypter_vector = _add_crypter_vector,
e09a87d6 1157 .add_aead_vector = _add_aead_vector,
aed2bf0b
MW
1158 .add_signer_vector = _add_signer_vector,
1159 .add_hasher_vector = _add_hasher_vector,
1160 .add_prf_vector = _add_prf_vector,
1161 .add_rng_vector = _add_rng_vector,
1162 .destroy = _destroy,
1163 },
1164 .crypter = linked_list_create(),
e09a87d6 1165 .aead = linked_list_create(),
aed2bf0b
MW
1166 .signer = linked_list_create(),
1167 .hasher = linked_list_create(),
1168 .prf = linked_list_create(),
1169 .rng = linked_list_create(),
1170
1171 .required = lib->settings->get_bool(lib->settings,
1172 "libstrongswan.crypto_test.required", FALSE),
1173 .rng_true = lib->settings->get_bool(lib->settings,
1174 "libstrongswan.crypto_test.rng_true", FALSE),
1b0eff58
MW
1175 .bench_time = lib->settings->get_int(lib->settings,
1176 "libstrongswan.crypto_test.bench_time", 50),
1177 .bench_size = lib->settings->get_int(lib->settings,
1178 "libstrongswan.crypto_test.bench_size", 1024),
aed2bf0b 1179 );
7daf5226 1180
1b0eff58
MW
1181 /* enforce a block size of 16, should be fine for all algorithms */
1182 this->bench_size = this->bench_size / 16 * 16;
1183
3e889166
MW
1184 return &this->public;
1185}
1186