Coverage Report

Created: 2026-01-22 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libstrongswan/crypto/crypto_tester.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2009-2010 Martin Willi
3
 * Copyright (C) 2016-2019 Andreas Steffen
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#ifdef HAVE_DLADDR
19
# define _GNU_SOURCE
20
# include <dlfcn.h>
21
#endif
22
#include <time.h>
23
24
#include "crypto_tester.h"
25
26
#include <utils/debug.h>
27
#include <collections/linked_list.h>
28
#include <crypto/rngs/rng_tester.h>
29
30
typedef struct private_crypto_tester_t private_crypto_tester_t;
31
32
/**
33
 * Private data of an crypto_tester_t object.
34
 */
35
struct private_crypto_tester_t {
36
37
  /**
38
   * Public crypto_tester_t interface.
39
   */
40
  crypto_tester_t public;
41
42
  /**
43
   * List of crypter test vectors
44
   */
45
  linked_list_t *crypter;
46
47
  /**
48
   * List of aead test vectors
49
   */
50
  linked_list_t *aead;
51
52
  /**
53
   * List of signer test vectors
54
   */
55
  linked_list_t *signer;
56
57
  /**
58
   * List of hasher test vectors
59
   */
60
  linked_list_t *hasher;
61
62
  /**
63
   * List of PRF test vectors
64
   */
65
  linked_list_t *prf;
66
67
  /**
68
   * List of XOF test vectors
69
   */
70
  linked_list_t *xof;
71
72
  /**
73
   * List of KDF test vectors
74
   */
75
  linked_list_t *kdf;
76
77
  /**
78
   * List of DRBG test vectors
79
   */
80
  linked_list_t *drbg;
81
82
  /**
83
   * List of RNG test vectors
84
   */
85
  linked_list_t *rng;
86
87
  /**
88
   * List of key exchange method test vectors
89
   */
90
  linked_list_t *ke;
91
92
  /**
93
   * Is a test vector required to pass a test?
94
   */
95
  bool required;
96
97
  /**
98
   * should we run RNG_TRUE tests? Enough entropy?
99
   */
100
  bool rng_true;
101
102
  /**
103
   * time we test each algorithm
104
   */
105
  int bench_time;
106
107
  /**
108
   * size of buffer we use for benchmarking
109
   */
110
  int bench_size;
111
};
112
113
#if DEBUG_LEVEL >= 1
114
/**
115
 * Get the name of a test vector, if available
116
 */
117
static const char* get_name(void *sym)
118
{
119
#ifdef HAVE_DLADDR
120
  Dl_info dli;
121
122
  if (dladdr(sym, &dli))
123
  {
124
    return dli.dli_sname;
125
  }
126
#endif
127
  return "unknown";
128
}
129
#endif
130
131
#if defined(CLOCK_THREAD_CPUTIME_ID) && defined(HAVE_CLOCK_GETTIME)
132
133
/**
134
 * Start a benchmark timer
135
 */
136
static void start_timing(struct timespec *start)
137
0
{
138
0
  clock_gettime(CLOCK_THREAD_CPUTIME_ID, start);
139
0
}
140
141
/**
142
 * End a benchmark timer, return ms
143
 */
144
static u_int end_timing(struct timespec *start)
145
0
{
146
0
  struct timespec end;
147
148
0
  clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
149
0
  return (end.tv_nsec - start->tv_nsec) / 1000000 +
150
0
      (end.tv_sec - start->tv_sec) * 1000;
151
0
}
152
153
#else /* CLOCK_THREAD_CPUTIME_ID */
154
155
/* Make benchmarking a no-op if CLOCK_THREAD_CPUTIME_ID is not available */
156
#define start_timing(start) ((start)->tv_sec = 0, (start)->tv_nsec = 0)
157
#define end_timing(...) (this->bench_time)
158
159
#endif /* CLOCK_THREAD_CPUTIME_ID */
160
161
/**
162
 * Benchmark a crypter
163
 */
164
static u_int bench_crypter(private_crypto_tester_t *this,
165
  encryption_algorithm_t alg, crypter_constructor_t create, size_t key_size)
166
0
{
167
0
  crypter_t *crypter;
168
169
0
  crypter = create(alg, key_size);
170
0
  if (crypter)
171
0
  {
172
0
    char iv[crypter->get_iv_size(crypter)];
173
0
    char key[crypter->get_key_size(crypter)];
174
0
    chunk_t buf;
175
0
    struct timespec start;
176
0
    u_int runs;
177
178
0
    memset(iv, 0x56, sizeof(iv));
179
0
    memset(key, 0x12, sizeof(key));
180
0
    if (!crypter->set_key(crypter, chunk_from_thing(key)))
181
0
    {
182
0
      return 0;
183
0
    }
184
185
0
    buf = chunk_alloc(this->bench_size);
186
0
    memset(buf.ptr, 0x34, buf.len);
187
188
0
    runs = 0;
189
0
    start_timing(&start);
190
0
    while (end_timing(&start) < this->bench_time)
191
0
    {
192
0
      if (crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL))
193
0
      {
194
0
        runs++;
195
0
      }
196
0
      if (crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL))
197
0
      {
198
0
        runs++;
199
0
      }
200
0
    }
201
0
    free(buf.ptr);
202
0
    crypter->destroy(crypter);
203
204
0
    return runs;
205
0
  }
206
0
  return 0;
207
0
}
208
209
METHOD(crypto_tester_t, test_crypter, bool,
210
  private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
211
  crypter_constructor_t create, u_int *speed, const char *plugin_name)
212
0
{
213
0
  enumerator_t *enumerator;
214
0
  crypter_test_vector_t *vector;
215
0
  bool failed = FALSE;
216
0
  u_int tested = 0;
217
218
0
  enumerator = this->crypter->create_enumerator(this->crypter);
219
0
  while (enumerator->enumerate(enumerator, &vector))
220
0
  {
221
0
    crypter_t *crypter;
222
0
    chunk_t key, iv, plain = chunk_empty, cipher = chunk_empty;
223
224
0
    if (vector->alg != alg)
225
0
    {
226
0
      continue;
227
0
    }
228
0
    if (key_size && key_size != vector->key_size)
229
0
    { /* test only vectors with a specific key size, if key size given */
230
0
      continue;
231
0
    }
232
233
0
    crypter = create(alg, vector->key_size);
234
0
    if (!crypter)
235
0
    { /* key size not supported */
236
0
      continue;
237
0
    }
238
0
    tested++;
239
0
    failed = TRUE;
240
241
0
    key = chunk_create(vector->key, crypter->get_key_size(crypter));
242
0
    if (!crypter->set_key(crypter, key))
243
0
    {
244
0
      goto failure;
245
0
    }
246
0
    iv = chunk_create(vector->iv, crypter->get_iv_size(crypter));
247
248
    /* allocated encryption */
249
0
    plain = chunk_create(vector->plain, vector->len);
250
0
    if (!crypter->encrypt(crypter, plain, iv, &cipher))
251
0
    {
252
0
      goto failure;
253
0
    }
254
0
    if (!memeq(vector->cipher, cipher.ptr, cipher.len))
255
0
    {
256
0
      goto failure;
257
0
    }
258
    /* inline decryption */
259
0
    if (!crypter->decrypt(crypter, cipher, iv, NULL))
260
0
    {
261
0
      goto failure;
262
0
    }
263
0
    if (!memeq(vector->plain, cipher.ptr, cipher.len))
264
0
    {
265
0
      goto failure;
266
0
    }
267
    /* allocated decryption */
268
0
    if (!crypter->decrypt(crypter,
269
0
            chunk_create(vector->cipher, vector->len), iv, &plain))
270
0
    {
271
0
      goto failure;
272
0
    }
273
0
    if (!memeq(vector->plain, plain.ptr, plain.len))
274
0
    {
275
0
      goto failure;
276
0
    }
277
    /* inline encryption */
278
0
    if (!crypter->encrypt(crypter, plain, iv, NULL))
279
0
    {
280
0
      goto failure;
281
0
    }
282
0
    if (!memeq(vector->cipher, plain.ptr, plain.len))
283
0
    {
284
0
      goto failure;
285
0
    }
286
287
0
    failed = FALSE;
288
0
failure:
289
0
    crypter->destroy(crypter);
290
0
    chunk_free(&cipher);
291
0
    if (plain.ptr != vector->plain)
292
0
    {
293
0
      chunk_free(&plain);
294
0
    }
295
0
    if (failed)
296
0
    {
297
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
298
0
         encryption_algorithm_names, alg, plugin_name, get_name(vector));
299
0
      break;
300
0
    }
301
0
  }
302
0
  enumerator->destroy(enumerator);
303
0
  if (!tested)
304
0
  {
305
0
    if (failed)
306
0
    {
307
0
      DBG1(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
308
0
         encryption_algorithm_names, alg, plugin_name, key_size);
309
0
      return FALSE;
310
0
    }
311
0
    else
312
0
    {
313
0
      DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
314
0
         this->required ? "disabled" : "enabled ",
315
0
         encryption_algorithm_names, alg, plugin_name);
316
0
      return !this->required;
317
0
    }
318
0
  }
319
0
  if (!failed)
320
0
  {
321
0
    if (speed)
322
0
    {
323
0
      *speed = bench_crypter(this, alg, create, key_size);
324
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points "
325
0
         "(%zd bit key)", encryption_algorithm_names, alg,
326
0
         plugin_name, tested, *speed, key_size * 8);
327
0
    }
328
0
    else
329
0
    {
330
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
331
0
         encryption_algorithm_names, alg, plugin_name, tested);
332
0
    }
333
0
  }
334
0
  return !failed;
335
0
}
336
337
/**
338
 * Benchmark an aead transform
339
 */
340
static u_int bench_aead(private_crypto_tester_t *this,
341
  encryption_algorithm_t alg, aead_constructor_t create, size_t key_size)
342
0
{
343
0
  aead_t *aead;
344
345
0
  aead = create(alg, key_size, 0);
346
0
  if (aead)
347
0
  {
348
0
    char iv[aead->get_iv_size(aead)];
349
0
    char key[aead->get_key_size(aead)];
350
0
    char assoc[4];
351
0
    chunk_t buf;
352
0
    struct timespec start;
353
0
    u_int runs;
354
0
    size_t icv;
355
356
0
    memset(iv, 0x56, sizeof(iv));
357
0
    memset(key, 0x12, sizeof(key));
358
0
    memset(assoc, 0x78, sizeof(assoc));
359
0
    if (!aead->set_key(aead, chunk_from_thing(key)))
360
0
    {
361
0
      return 0;
362
0
    }
363
0
    icv = aead->get_icv_size(aead);
364
365
0
    buf = chunk_alloc(this->bench_size + icv);
366
0
    memset(buf.ptr, 0x34, buf.len);
367
0
    buf.len -= icv;
368
369
0
    runs = 0;
370
0
    start_timing(&start);
371
0
    while (end_timing(&start) < this->bench_time)
372
0
    {
373
0
      if (aead->encrypt(aead, buf, chunk_from_thing(assoc),
374
0
            chunk_from_thing(iv), NULL))
375
0
      {
376
0
        runs += 2;
377
0
      }
378
0
      if (aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv),
379
0
            chunk_from_thing(assoc), chunk_from_thing(iv), NULL))
380
0
      {
381
0
        runs += 2;
382
0
      }
383
0
    }
384
0
    free(buf.ptr);
385
0
    aead->destroy(aead);
386
387
0
    return runs;
388
0
  }
389
0
  return 0;
390
0
}
391
392
METHOD(crypto_tester_t, test_aead, bool,
393
  private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
394
  size_t salt_size, aead_constructor_t create,
395
  u_int *speed, const char *plugin_name)
396
0
{
397
0
  enumerator_t *enumerator;
398
0
  aead_test_vector_t *vector;
399
0
  bool failed = FALSE;
400
0
  u_int tested = 0;
401
402
0
  enumerator = this->aead->create_enumerator(this->aead);
403
0
  while (enumerator->enumerate(enumerator, &vector))
404
0
  {
405
0
    aead_t *aead;
406
0
    chunk_t key, iv, assoc, plain = chunk_empty, cipher = chunk_empty;
407
0
    size_t icv;
408
409
0
    if (vector->alg != alg)
410
0
    {
411
0
      continue;
412
0
    }
413
0
    if (key_size && key_size != vector->key_size)
414
0
    { /* test only vectors with a specific key size, if key size given */
415
0
      continue;
416
0
    }
417
0
    if (salt_size && salt_size != vector->salt_size)
418
0
    {
419
0
      continue;
420
0
    }
421
422
0
    tested++;
423
0
    failed = TRUE;
424
0
    aead = create(alg, vector->key_size, vector->salt_size);
425
0
    if (!aead)
426
0
    {
427
0
      DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
428
0
         encryption_algorithm_names, alg, plugin_name,
429
0
         BITS_PER_BYTE * vector->key_size);
430
0
      continue;
431
0
    }
432
433
0
    key = chunk_create(vector->key, aead->get_key_size(aead));
434
0
    if (!aead->set_key(aead, key))
435
0
    {
436
0
      goto failure;
437
0
    }
438
0
    iv = chunk_create(vector->iv, aead->get_iv_size(aead));
439
0
    assoc = chunk_create(vector->adata, vector->alen);
440
0
    icv = aead->get_icv_size(aead);
441
442
    /* allocated encryption */
443
0
    plain = chunk_create(vector->plain, vector->len);
444
0
    if (!aead->encrypt(aead, plain, assoc, iv, &cipher))
445
0
    {
446
0
      goto failure;
447
0
    }
448
0
    if (!memeq(vector->cipher, cipher.ptr, cipher.len))
449
0
    {
450
0
      goto failure;
451
0
    }
452
    /* inline decryption */
453
0
    if (!aead->decrypt(aead, cipher, assoc, iv, NULL))
454
0
    {
455
0
      goto failure;
456
0
    }
457
0
    if (!memeq(vector->plain, cipher.ptr, cipher.len - icv))
458
0
    {
459
0
      goto failure;
460
0
    }
461
    /* allocated decryption */
462
0
    if (!aead->decrypt(aead, chunk_create(vector->cipher, vector->len + icv),
463
0
               assoc, iv, &plain))
464
0
    {
465
0
      goto failure;
466
0
    }
467
0
    if (!memeq(vector->plain, plain.ptr, plain.len))
468
0
    {
469
0
      goto failure;
470
0
    }
471
0
    plain.ptr = realloc(plain.ptr, plain.len + icv);
472
    /* inline encryption */
473
0
    if (!aead->encrypt(aead, plain, assoc, iv, NULL))
474
0
    {
475
0
      goto failure;
476
0
    }
477
0
    if (!memeq(vector->cipher, plain.ptr, plain.len + icv))
478
0
    {
479
0
      goto failure;
480
0
    }
481
482
0
    failed = FALSE;
483
0
failure:
484
0
    aead->destroy(aead);
485
0
    chunk_free(&cipher);
486
0
    if (plain.ptr != vector->plain)
487
0
    {
488
0
      chunk_free(&plain);
489
0
    }
490
0
    if (failed)
491
0
    {
492
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
493
0
         encryption_algorithm_names, alg, plugin_name, get_name(vector));
494
0
      break;
495
0
    }
496
0
  }
497
0
  enumerator->destroy(enumerator);
498
0
  if (!tested)
499
0
  {
500
0
    if (failed)
501
0
    {
502
0
      DBG1(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
503
0
         encryption_algorithm_names, alg, plugin_name, key_size);
504
0
      return FALSE;
505
0
    }
506
0
    else
507
0
    {
508
0
      DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
509
0
         this->required ? "disabled" : "enabled ",
510
0
         encryption_algorithm_names, alg, plugin_name);
511
0
      return !this->required;
512
0
    }
513
0
  }
514
0
  if (!failed)
515
0
  {
516
0
    if (speed)
517
0
    {
518
0
      *speed = bench_aead(this, alg, create, key_size);
519
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points "
520
0
         "(%zd bit key)", encryption_algorithm_names, alg,
521
0
         plugin_name, tested, *speed, key_size * 8);
522
0
    }
523
0
    else
524
0
    {
525
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
526
0
         encryption_algorithm_names, alg, plugin_name, tested);
527
0
    }
528
0
  }
529
0
  return !failed;
530
0
}
531
532
/**
533
 * Benchmark a signer
534
 */
535
static u_int bench_signer(private_crypto_tester_t *this,
536
  integrity_algorithm_t alg, signer_constructor_t create)
537
0
{
538
0
  signer_t *signer;
539
540
0
  signer = create(alg);
541
0
  if (signer)
542
0
  {
543
0
    char key[signer->get_key_size(signer)];
544
0
    char mac[signer->get_block_size(signer)];
545
0
    chunk_t buf;
546
0
    struct timespec start;
547
0
    u_int runs;
548
549
0
    memset(key, 0x12, sizeof(key));
550
0
    if (!signer->set_key(signer, chunk_from_thing(key)))
551
0
    {
552
0
      return 0;
553
0
    }
554
555
0
    buf = chunk_alloc(this->bench_size);
556
0
    memset(buf.ptr, 0x34, buf.len);
557
558
0
    runs = 0;
559
0
    start_timing(&start);
560
0
    while (end_timing(&start) < this->bench_time)
561
0
    {
562
0
      if (signer->get_signature(signer, buf, mac))
563
0
      {
564
0
        runs++;
565
0
      }
566
0
      if (signer->verify_signature(signer, buf, chunk_from_thing(mac)))
567
0
      {
568
0
        runs++;
569
0
      }
570
0
    }
571
0
    free(buf.ptr);
572
0
    signer->destroy(signer);
573
574
0
    return runs;
575
0
  }
576
0
  return 0;
577
0
}
578
579
METHOD(crypto_tester_t, test_signer, bool,
580
  private_crypto_tester_t *this, integrity_algorithm_t alg,
581
  signer_constructor_t create, u_int *speed, const char *plugin_name)
582
0
{
583
0
  enumerator_t *enumerator;
584
0
  signer_test_vector_t *vector;
585
0
  bool failed = FALSE;
586
0
  u_int tested = 0;
587
588
0
  enumerator = this->signer->create_enumerator(this->signer);
589
0
  while (enumerator->enumerate(enumerator, &vector))
590
0
  {
591
0
    signer_t *signer;
592
0
    chunk_t key, data, mac = chunk_empty;
593
594
0
    if (vector->alg != alg)
595
0
    {
596
0
      continue;
597
0
    }
598
599
0
    tested++;
600
0
    failed = TRUE;
601
0
    signer = create(alg);
602
0
    if (!signer)
603
0
    {
604
0
      DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
605
0
         integrity_algorithm_names, alg, plugin_name);
606
0
      break;
607
0
    }
608
609
0
    data = chunk_create(vector->data, vector->len);
610
0
    key = chunk_create(vector->key, signer->get_key_size(signer));
611
0
    if (!signer->set_key(signer, key))
612
0
    {
613
0
      goto failure;
614
0
    }
615
    /* do partial append mode and check if key gets set correctly */
616
0
    if (!signer->get_signature(signer, data, NULL))
617
0
    {
618
0
      goto failure;
619
0
    }
620
0
    if (!signer->set_key(signer, key))
621
0
    {
622
0
      goto failure;
623
0
    }
624
    /* allocated signature */
625
0
    if (!signer->allocate_signature(signer, data, &mac))
626
0
    {
627
0
      goto failure;
628
0
    }
629
0
    if (mac.len != signer->get_block_size(signer))
630
0
    {
631
0
      goto failure;
632
0
    }
633
0
    if (!memeq(vector->mac, mac.ptr, mac.len))
634
0
    {
635
0
      goto failure;
636
0
    }
637
    /* signature to existing buffer */
638
0
    memset(mac.ptr, 0, mac.len);
639
0
    if (!signer->get_signature(signer, data, mac.ptr))
640
0
    {
641
0
      goto failure;
642
0
    }
643
0
    if (!memeq(vector->mac, mac.ptr, mac.len))
644
0
    {
645
0
      goto failure;
646
0
    }
647
    /* signature verification, good case */
648
0
    if (!signer->verify_signature(signer, data, mac))
649
0
    {
650
0
      goto failure;
651
0
    }
652
    /* signature verification, bad case */
653
0
    *(mac.ptr + mac.len - 1) += 1;
654
0
    if (signer->verify_signature(signer, data, mac))
655
0
    {
656
0
      goto failure;
657
0
    }
658
    /* signature to existing buffer, using append mode */
659
0
    if (data.len > 2)
660
0
    {
661
0
      if (!signer->allocate_signature(signer,
662
0
                      chunk_create(data.ptr, 1), NULL))
663
0
      {
664
0
        goto failure;
665
0
      }
666
0
      if (!signer->get_signature(signer,
667
0
                     chunk_create(data.ptr + 1, 1), NULL))
668
0
      {
669
0
        goto failure;
670
0
      }
671
0
      if (!signer->verify_signature(signer, chunk_skip(data, 2),
672
0
                      chunk_create(vector->mac, mac.len)))
673
0
      {
674
0
        goto failure;
675
0
      }
676
0
    }
677
678
0
    failed = FALSE;
679
0
failure:
680
0
    signer->destroy(signer);
681
0
    chunk_free(&mac);
682
0
    if (failed)
683
0
    {
684
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
685
0
         integrity_algorithm_names, alg, plugin_name, get_name(vector));
686
0
      break;
687
0
    }
688
0
  }
689
0
  enumerator->destroy(enumerator);
690
0
  if (!tested)
691
0
  {
692
0
    DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
693
0
       this->required ? "disabled" : "enabled ",
694
0
       integrity_algorithm_names, alg, plugin_name);
695
0
    return !this->required;
696
0
  }
697
0
  if (!failed)
698
0
  {
699
0
    if (speed)
700
0
    {
701
0
      *speed = bench_signer(this, alg, create);
702
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
703
0
         integrity_algorithm_names, alg, plugin_name, tested, *speed);
704
0
    }
705
0
    else
706
0
    {
707
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
708
0
         integrity_algorithm_names, alg, plugin_name, tested);
709
0
    }
710
0
  }
711
0
  return !failed;
712
0
}
713
714
/**
715
 * Benchmark a hasher
716
 */
717
static u_int bench_hasher(private_crypto_tester_t *this,
718
  hash_algorithm_t alg, hasher_constructor_t create)
719
0
{
720
0
  hasher_t *hasher;
721
722
0
  hasher = create(alg);
723
0
  if (hasher)
724
0
  {
725
0
    char hash[hasher->get_hash_size(hasher)];
726
0
    chunk_t buf;
727
0
    struct timespec start;
728
0
    u_int runs;
729
730
0
    buf = chunk_alloc(this->bench_size);
731
0
    memset(buf.ptr, 0x34, buf.len);
732
733
0
    runs = 0;
734
0
    start_timing(&start);
735
0
    while (end_timing(&start) < this->bench_time)
736
0
    {
737
0
      if (hasher->get_hash(hasher, buf, hash))
738
0
      {
739
0
        runs++;
740
0
      }
741
0
    }
742
0
    free(buf.ptr);
743
0
    hasher->destroy(hasher);
744
745
0
    return runs;
746
0
  }
747
0
  return 0;
748
0
}
749
750
METHOD(crypto_tester_t, test_hasher, bool,
751
  private_crypto_tester_t *this, hash_algorithm_t alg,
752
  hasher_constructor_t create, u_int *speed, const char *plugin_name)
753
0
{
754
0
  enumerator_t *enumerator;
755
0
  hasher_test_vector_t *vector;
756
0
  bool failed = FALSE;
757
0
  u_int tested = 0;
758
759
0
  enumerator = this->hasher->create_enumerator(this->hasher);
760
0
  while (enumerator->enumerate(enumerator, &vector))
761
0
  {
762
0
    hasher_t *hasher;
763
0
    chunk_t data, hash;
764
765
0
    if (vector->alg != alg)
766
0
    {
767
0
      continue;
768
0
    }
769
770
0
    tested++;
771
0
    failed = TRUE;
772
0
    hasher = create(alg);
773
0
    if (!hasher)
774
0
    {
775
0
      DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
776
0
         hash_algorithm_names, alg, plugin_name);
777
0
      break;
778
0
    }
779
780
    /* allocated hash */
781
0
    data = chunk_create(vector->data, vector->len);
782
0
    if (!hasher->allocate_hash(hasher, data, &hash))
783
0
    {
784
0
      goto failure;
785
0
    }
786
0
    if (hash.len != hasher->get_hash_size(hasher))
787
0
    {
788
0
      goto failure;
789
0
    }
790
0
    if (!memeq(vector->hash, hash.ptr, hash.len))
791
0
    {
792
0
      goto failure;
793
0
    }
794
    /* hash to existing buffer, with a reset */
795
0
    memset(hash.ptr, 0, hash.len);
796
0
    if (!hasher->get_hash(hasher, data, NULL))
797
0
    {
798
0
      goto failure;
799
0
    }
800
0
    if (!hasher->reset(hasher))
801
0
    {
802
0
      goto failure;
803
0
    }
804
0
    if (!hasher->get_hash(hasher, data, hash.ptr))
805
0
    {
806
0
      goto failure;
807
0
    }
808
0
    if (!memeq(vector->hash, hash.ptr, hash.len))
809
0
    {
810
0
      goto failure;
811
0
    }
812
    /* hasher to existing buffer, using append mode */
813
0
    if (data.len > 2)
814
0
    {
815
0
      memset(hash.ptr, 0, hash.len);
816
0
      if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL))
817
0
      {
818
0
        goto failure;
819
0
      }
820
0
      if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL))
821
0
      {
822
0
        goto failure;
823
0
      }
824
0
      if (!hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr))
825
0
      {
826
0
        goto failure;
827
0
      }
828
0
      if (!memeq(vector->hash, hash.ptr, hash.len))
829
0
      {
830
0
        goto failure;
831
0
      }
832
0
    }
833
834
0
    failed = FALSE;
835
0
failure:
836
0
    hasher->destroy(hasher);
837
0
    chunk_free(&hash);
838
0
    if (failed)
839
0
    {
840
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
841
0
         hash_algorithm_names, alg, plugin_name, get_name(vector));
842
0
      break;
843
0
    }
844
0
  }
845
0
  enumerator->destroy(enumerator);
846
0
  if (!tested)
847
0
  {
848
0
    DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
849
0
       this->required ? "disabled" : "enabled ",
850
0
       hash_algorithm_names, alg, plugin_name);
851
0
    return !this->required;
852
0
  }
853
0
  if (!failed)
854
0
  {
855
0
    if (speed)
856
0
    {
857
0
      *speed = bench_hasher(this, alg, create);
858
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
859
0
         hash_algorithm_names, alg, plugin_name, tested, *speed);
860
0
    }
861
0
    else
862
0
    {
863
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
864
0
         hash_algorithm_names, alg, plugin_name, tested);
865
0
    }
866
0
  }
867
0
  return !failed;
868
0
}
869
870
/**
871
 * Benchmark a PRF
872
 */
873
static u_int bench_prf(private_crypto_tester_t *this,
874
             pseudo_random_function_t alg, prf_constructor_t create)
875
0
{
876
0
  prf_t *prf;
877
878
0
  prf = create(alg);
879
0
  if (prf)
880
0
  {
881
0
    char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)];
882
0
    chunk_t buf;
883
0
    struct timespec start;
884
0
    u_int runs;
885
886
0
    memset(key, 0x56, prf->get_block_size(prf));
887
0
    if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf))))
888
0
    {
889
0
      prf->destroy(prf);
890
0
      return 0;
891
0
    }
892
893
0
    buf = chunk_alloc(this->bench_size);
894
0
    memset(buf.ptr, 0x34, buf.len);
895
896
0
    runs = 0;
897
0
    start_timing(&start);
898
0
    while (end_timing(&start) < this->bench_time)
899
0
    {
900
0
      if (prf->get_bytes(prf, buf, bytes))
901
0
      {
902
0
        runs++;
903
0
      }
904
0
    }
905
0
    free(buf.ptr);
906
0
    prf->destroy(prf);
907
908
0
    return runs;
909
0
  }
910
0
  return 0;
911
0
}
912
913
METHOD(crypto_tester_t, test_prf, bool,
914
  private_crypto_tester_t *this, pseudo_random_function_t alg,
915
  prf_constructor_t create, u_int *speed, const char *plugin_name)
916
0
{
917
0
  enumerator_t *enumerator;
918
0
  prf_test_vector_t *vector;
919
0
  bool failed = FALSE;
920
0
  u_int tested = 0;
921
922
0
  enumerator = this->prf->create_enumerator(this->prf);
923
0
  while (enumerator->enumerate(enumerator, &vector))
924
0
  {
925
0
    prf_t *prf;
926
0
    chunk_t key, seed, out = chunk_empty;
927
928
0
    if (vector->alg != alg)
929
0
    {
930
0
      continue;
931
0
    }
932
933
0
    tested++;
934
0
    failed = TRUE;
935
0
    prf = create(alg);
936
0
    if (!prf)
937
0
    {
938
0
      DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
939
0
         pseudo_random_function_names, alg, plugin_name);
940
0
      break;
941
0
    }
942
943
0
    seed = chunk_create(vector->seed, vector->len);
944
0
    key = chunk_create(vector->key, vector->key_size);
945
0
    if (!prf->set_key(prf, key))
946
0
    {
947
0
      goto failure;
948
0
    }
949
0
    if (alg != PRF_FIPS_SHA1_160)
950
0
    {
951
      /* do partial append mode and check if key gets set correctly */
952
0
      if (!prf->get_bytes(prf, seed, NULL))
953
0
      {
954
0
        goto failure;
955
0
      }
956
0
      if (!prf->set_key(prf, key))
957
0
      {
958
0
        goto failure;
959
0
      }
960
0
    }
961
    /* allocated bytes */
962
0
    if (!prf->allocate_bytes(prf, seed, &out))
963
0
    {
964
0
      goto failure;
965
0
    }
966
0
    if (out.len != prf->get_block_size(prf))
967
0
    {
968
0
      goto failure;
969
0
    }
970
0
    if (!memeq(vector->out, out.ptr, out.len))
971
0
    {
972
0
      goto failure;
973
0
    }
974
    /* bytes to existing buffer */
975
0
    memset(out.ptr, 0, out.len);
976
0
    if (vector->stateful)
977
0
    {
978
0
      if (!prf->set_key(prf, key))
979
0
      {
980
0
        goto failure;
981
0
      }
982
0
    }
983
0
    if (!prf->get_bytes(prf, seed, out.ptr))
984
0
    {
985
0
      goto failure;
986
0
    }
987
0
    if (!memeq(vector->out, out.ptr, out.len))
988
0
    {
989
0
      goto failure;
990
0
    }
991
    /* bytes to existing buffer, using append mode */
992
0
    if (alg != PRF_FIPS_SHA1_160 && seed.len > 2)
993
0
    {
994
0
      memset(out.ptr, 0, out.len);
995
0
      if (vector->stateful)
996
0
      {
997
0
        if (!prf->set_key(prf, key))
998
0
        {
999
0
          goto failure;
1000
0
        }
1001
0
      }
1002
0
      if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL))
1003
0
      {
1004
0
        goto failure;
1005
0
      }
1006
0
      if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL))
1007
0
      {
1008
0
        goto failure;
1009
0
      }
1010
0
      if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
1011
0
      {
1012
0
        goto failure;
1013
0
      }
1014
0
      if (!memeq(vector->out, out.ptr, out.len))
1015
0
      {
1016
0
        goto failure;
1017
0
      }
1018
0
    }
1019
1020
0
    failed = FALSE;
1021
0
failure:
1022
0
    prf->destroy(prf);
1023
0
    chunk_free(&out);
1024
0
    if (failed)
1025
0
    {
1026
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1027
0
         pseudo_random_function_names, alg, plugin_name, get_name(vector));
1028
0
      break;
1029
0
    }
1030
0
  }
1031
0
  enumerator->destroy(enumerator);
1032
0
  if (!tested)
1033
0
  {
1034
0
    DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1035
0
       this->required ? "disabled" : "enabled ",
1036
0
       pseudo_random_function_names, alg, plugin_name);
1037
0
    return !this->required;
1038
0
  }
1039
0
  if (!failed)
1040
0
  {
1041
0
    if (speed)
1042
0
    {
1043
0
      *speed = bench_prf(this, alg, create);
1044
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
1045
0
         pseudo_random_function_names, alg, plugin_name, tested, *speed);
1046
0
    }
1047
0
    else
1048
0
    {
1049
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
1050
0
         pseudo_random_function_names, alg, plugin_name, tested);
1051
0
    }
1052
0
  }
1053
0
  return !failed;
1054
0
}
1055
1056
/**
1057
 * Benchmark an XOF
1058
 */
1059
static u_int bench_xof(private_crypto_tester_t *this,
1060
             ext_out_function_t alg, xof_constructor_t create)
1061
0
{
1062
0
  xof_t *xof;
1063
1064
0
  xof = create(alg);
1065
0
  if (xof)
1066
0
  {
1067
0
    char seed[xof->get_seed_size(xof)];
1068
0
    char bytes[xof->get_block_size(xof)];
1069
0
    struct timespec start;
1070
0
    u_int runs;
1071
1072
0
    memset(seed, 0x56, xof->get_seed_size(xof));
1073
0
    if (!xof->set_seed(xof, chunk_create(seed, xof->get_seed_size(xof))))
1074
0
    {
1075
0
      xof->destroy(xof);
1076
0
      return 0;
1077
0
    }
1078
1079
0
    runs = 0;
1080
0
    start_timing(&start);
1081
0
    while (end_timing(&start) < this->bench_time)
1082
0
    {
1083
0
      if (xof->get_bytes(xof, xof->get_block_size(xof), bytes))
1084
0
      {
1085
0
        runs++;
1086
0
      }
1087
0
    }
1088
0
    xof->destroy(xof);
1089
1090
0
    return runs;
1091
0
  }
1092
0
  return 0;
1093
0
}
1094
1095
METHOD(crypto_tester_t, test_xof, bool,
1096
  private_crypto_tester_t *this, ext_out_function_t alg,
1097
  xof_constructor_t create, u_int *speed, const char *plugin_name)
1098
0
{
1099
0
  enumerator_t *enumerator;
1100
0
  xof_test_vector_t *vector;
1101
0
  bool failed = FALSE;
1102
0
  u_int tested = 0;
1103
1104
0
  enumerator = this->xof->create_enumerator(this->xof);
1105
0
  while (enumerator->enumerate(enumerator, &vector))
1106
0
  {
1107
0
    xof_t *xof;
1108
0
    chunk_t seed, out = chunk_empty;
1109
1110
0
    if (vector->alg != alg)
1111
0
    {
1112
0
      continue;
1113
0
    }
1114
1115
0
    tested++;
1116
0
    failed = TRUE;
1117
0
    xof = create(alg);
1118
0
    if (!xof)
1119
0
    {
1120
0
      DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1121
0
         ext_out_function_names, alg, plugin_name);
1122
0
      break;
1123
0
    }
1124
1125
0
    seed = chunk_create(vector->seed, vector->len);
1126
0
    if (!xof->set_seed(xof, seed))
1127
0
    {
1128
0
      goto failure;
1129
0
    }
1130
    /* allocated bytes */
1131
0
    if (!xof->allocate_bytes(xof, vector->out_len, &out))
1132
0
    {
1133
0
      goto failure;
1134
0
    }
1135
0
    if (out.len != vector->out_len)
1136
0
    {
1137
0
      goto failure;
1138
0
    }
1139
0
    if (!memeq(vector->out, out.ptr, out.len))
1140
0
    {
1141
0
      goto failure;
1142
0
    }
1143
    /* bytes to existing buffer */
1144
0
    memset(out.ptr, 0, out.len);
1145
0
    if (!xof->set_seed(xof, seed))
1146
0
    {
1147
0
      goto failure;
1148
0
    }
1149
0
    if (!xof->get_bytes(xof, vector->out_len, out.ptr))
1150
0
    {
1151
0
      goto failure;
1152
0
    }
1153
0
    if (!memeq(vector->out, out.ptr, vector->out_len))
1154
0
    {
1155
0
      goto failure;
1156
0
    }
1157
    /* bytes to existing buffer, using append mode */
1158
    /* TODO */
1159
1160
0
    failed = FALSE;
1161
0
failure:
1162
0
    xof->destroy(xof);
1163
0
    chunk_free(&out);
1164
0
    if (failed)
1165
0
    {
1166
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1167
0
         ext_out_function_names, alg, plugin_name, get_name(vector));
1168
0
      break;
1169
0
    }
1170
0
  }
1171
0
  enumerator->destroy(enumerator);
1172
0
  if (!tested)
1173
0
  {
1174
0
    DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1175
0
       this->required ? "disabled" : "enabled ",
1176
0
       ext_out_function_names, alg, plugin_name);
1177
0
    return !this->required;
1178
0
  }
1179
0
  if (!failed)
1180
0
  {
1181
0
    if (speed)
1182
0
    {
1183
0
      *speed = bench_xof(this, alg, create);
1184
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
1185
0
         ext_out_function_names, alg, plugin_name, tested, *speed);
1186
0
    }
1187
0
    else
1188
0
    {
1189
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
1190
0
         ext_out_function_names, alg, plugin_name, tested);
1191
0
    }
1192
0
  }
1193
0
  return !failed;
1194
0
}
1195
1196
1197
1198
/**
1199
 * Create a KDF using the given arguments
1200
 */
1201
static kdf_t *create_kdf_args(kdf_constructor_t create,
1202
                key_derivation_function_t alg, ...)
1203
0
{
1204
0
  va_list args;
1205
0
  kdf_t *kdf;
1206
1207
0
  va_start(args, alg);
1208
0
  kdf = create(alg, args);
1209
0
  va_end(args);
1210
0
  return kdf;
1211
0
}
1212
1213
/**
1214
 * Create a KDF using arguments from the given test vector
1215
 */
1216
static kdf_t *create_kdf_vector(kdf_constructor_t create,
1217
                key_derivation_function_t alg,
1218
                kdf_test_vector_t *vector)
1219
0
{
1220
0
  switch (alg)
1221
0
  {
1222
0
    case KDF_PRF:
1223
0
    case KDF_PRF_PLUS:
1224
0
      return create_kdf_args(create, alg, vector->arg.prf);
1225
0
    case KDF_UNDEFINED:
1226
0
      break;
1227
0
  }
1228
0
  return NULL;
1229
0
}
1230
1231
/**
1232
 * Check if the given test vector applies to the passed arguments
1233
 */
1234
static bool kdf_vector_applies(key_derivation_function_t alg,
1235
                 kdf_test_args_t *args, kdf_test_vector_t *vector)
1236
0
{
1237
0
  bool applies = FALSE;
1238
1239
0
  switch (alg)
1240
0
  {
1241
0
    case KDF_PRF:
1242
0
    case KDF_PRF_PLUS:
1243
0
    {
1244
0
      pseudo_random_function_t prf;
1245
0
      VA_ARGS_VGET(args->args, prf);
1246
0
      applies = (prf == vector->arg.prf);
1247
0
      break;
1248
0
    }
1249
0
    case KDF_UNDEFINED:
1250
0
      break;
1251
0
  }
1252
0
  return applies;
1253
0
}
1254
1255
METHOD(crypto_tester_t, test_kdf, bool,
1256
  private_crypto_tester_t *this, key_derivation_function_t alg,
1257
  kdf_constructor_t create, kdf_test_args_t *args, u_int *speed,
1258
  const char *plugin_name)
1259
0
{
1260
0
  enumerator_t *enumerator;
1261
0
  kdf_test_vector_t *vector;
1262
0
  va_list copy;
1263
0
  bool failed = FALSE;
1264
0
  u_int tested = 0, construction_failed = 0;
1265
1266
0
  enumerator = this->kdf->create_enumerator(this->kdf);
1267
0
  while (enumerator->enumerate(enumerator, &vector))
1268
0
  {
1269
0
    kdf_t *kdf;
1270
0
    chunk_t out = chunk_empty;
1271
1272
0
    if (vector->alg != alg ||
1273
0
      (args && !kdf_vector_applies(alg, args, vector)))
1274
0
    {
1275
0
      continue;
1276
0
    }
1277
1278
0
    tested++;
1279
0
    failed = TRUE;
1280
0
    if (args)
1281
0
    {
1282
0
      va_copy(copy, args->args);
1283
0
      kdf = create(alg, copy);
1284
0
      va_end(copy);
1285
0
    }
1286
0
    else
1287
0
    {
1288
0
      kdf = create_kdf_vector(create, alg, vector);
1289
0
    }
1290
0
    if (!kdf)
1291
0
    {
1292
0
      if (args)
1293
0
      {
1294
0
        DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1295
0
           key_derivation_function_names, alg, plugin_name);
1296
0
        break;
1297
0
      }
1298
      /* while there could be a problem, the constructor might just not
1299
       * be able to create an instance for this test vector, we check
1300
       * for that at the end */
1301
0
      construction_failed++;
1302
0
      failed = FALSE;
1303
0
      continue;
1304
0
    }
1305
1306
0
    if (vector->key.len &&
1307
0
      !kdf->set_param(kdf, KDF_PARAM_KEY, vector->key))
1308
0
    {
1309
0
      goto failure;
1310
0
    }
1311
0
    if (vector->salt.len &&
1312
0
      !kdf->set_param(kdf, KDF_PARAM_SALT, vector->salt))
1313
0
    {
1314
0
      goto failure;
1315
0
    }
1316
0
    if (kdf_has_fixed_output_length(alg))
1317
0
    {
1318
0
      if (kdf->get_length(kdf) != vector->out.len)
1319
0
      {
1320
0
        goto failure;
1321
0
      }
1322
0
    }
1323
0
    else if (kdf->get_length(kdf) != SIZE_MAX)
1324
0
    {
1325
0
      goto failure;
1326
0
    }
1327
    /* allocated bytes */
1328
0
    if (!kdf->allocate_bytes(kdf, vector->out.len, &out))
1329
0
    {
1330
0
      goto failure;
1331
0
    }
1332
0
    if (!chunk_equals(out, vector->out))
1333
0
    {
1334
0
      goto failure;
1335
0
    }
1336
    /* allocate without knowing the length */
1337
0
    if (kdf_has_fixed_output_length(alg))
1338
0
    {
1339
0
      chunk_free(&out);
1340
0
      if (!kdf->allocate_bytes(kdf, 0, &out))
1341
0
      {
1342
0
        goto failure;
1343
0
      }
1344
0
      if (!chunk_equals(out, vector->out))
1345
0
      {
1346
0
        goto failure;
1347
0
      }
1348
0
    }
1349
    /* bytes to existing buffer */
1350
0
    memset(out.ptr, 0, out.len);
1351
0
    if (!kdf->get_bytes(kdf, out.len, out.ptr))
1352
0
    {
1353
0
      goto failure;
1354
0
    }
1355
0
    if (!chunk_equals(out, vector->out))
1356
0
    {
1357
0
      goto failure;
1358
0
    }
1359
1360
0
    failed = FALSE;
1361
0
failure:
1362
0
    kdf->destroy(kdf);
1363
0
    chunk_free(&out);
1364
0
    if (failed)
1365
0
    {
1366
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1367
0
         key_derivation_function_names, alg, plugin_name,
1368
0
         get_name(vector));
1369
0
      break;
1370
0
    }
1371
0
  }
1372
0
  enumerator->destroy(enumerator);
1373
0
  if (!tested)
1374
0
  {
1375
0
    DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1376
0
       this->required ? "disabled" : "enabled ",
1377
0
       key_derivation_function_names, alg, plugin_name);
1378
0
    return !this->required;
1379
0
  }
1380
0
  tested -= construction_failed;
1381
0
  if (!tested)
1382
0
  {
1383
0
    DBG1(DBG_LIB, "%s %N[%s]: unable to apply any available test vectors",
1384
0
       this->required ? "disabled" : "enabled ",
1385
0
       key_derivation_function_names, alg, plugin_name);
1386
0
    return !this->required;
1387
0
  }
1388
0
  if (!failed)
1389
0
  {
1390
0
    if (speed)
1391
0
    {
1392
0
      DBG2(DBG_LIB, "benchmarking for %N is currently not supported",
1393
0
         key_derivation_function_names, alg);
1394
0
    }
1395
0
    DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
1396
0
       key_derivation_function_names, alg, plugin_name, tested);
1397
0
  }
1398
0
  return !failed;
1399
0
}
1400
1401
/**
1402
 * Benchmark a DRBG
1403
 */
1404
static u_int bench_drbg(private_crypto_tester_t *this,
1405
            drbg_type_t type, drbg_constructor_t create)
1406
0
{
1407
0
  drbg_t *drbg;
1408
0
  rng_t *entropy;
1409
0
  uint32_t strength = 128;
1410
0
  chunk_t seed = chunk_alloca(48);
1411
1412
0
  memset(seed.ptr, 0x81, seed.len);
1413
0
  entropy = rng_tester_create(seed);
1414
1415
0
  drbg = create(type, strength, entropy, chunk_empty);
1416
0
  if (drbg)
1417
0
  {
1418
0
    struct timespec start;
1419
0
    u_int runs = 0;
1420
0
    size_t out_len = 128;
1421
0
    char out_buf[out_len];
1422
1423
0
    start_timing(&start);
1424
0
    while (end_timing(&start) < this->bench_time)
1425
0
    {
1426
0
      if (drbg->generate(drbg, out_len, out_buf))
1427
0
      {
1428
0
        runs++;
1429
0
      }
1430
0
    }
1431
0
    drbg->destroy(drbg);
1432
1433
0
    return runs;
1434
0
  }
1435
0
  return 0;
1436
0
}
1437
1438
METHOD(crypto_tester_t, test_drbg, bool,
1439
  private_crypto_tester_t *this, drbg_type_t type,
1440
  drbg_constructor_t create, u_int *speed, const char *plugin_name)
1441
0
{
1442
0
  enumerator_t *enumerator;
1443
0
  drbg_test_vector_t *vector;
1444
0
  bool failed = FALSE;
1445
0
  u_int tested = 0;
1446
1447
0
  enumerator = this->drbg->create_enumerator(this->drbg);
1448
0
  while (enumerator->enumerate(enumerator, &vector))
1449
0
  {
1450
0
    drbg_t *drbg;
1451
0
    rng_t *entropy;
1452
0
    chunk_t out = chunk_empty;
1453
1454
0
    if (vector->type != type)
1455
0
    {
1456
0
      continue;
1457
0
    }
1458
0
    tested++;
1459
0
    failed = TRUE;
1460
1461
0
    entropy = rng_tester_create(vector->entropy);
1462
0
    out = chunk_alloc(vector->out.len);
1463
1464
0
    drbg = create(type, vector->strength, entropy,
1465
0
            vector->personalization_str);
1466
0
    if (!drbg)
1467
0
    {
1468
0
      DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1469
0
         drbg_type_names, type, plugin_name);
1470
0
      entropy->destroy(entropy);
1471
0
      chunk_free(&out);
1472
0
      break;
1473
0
    }
1474
0
    if (!drbg->reseed(drbg))
1475
0
    {
1476
0
      goto failure;
1477
0
    }
1478
0
    if (!drbg->generate(drbg, out.len, out.ptr))
1479
0
    {
1480
0
      goto failure;
1481
0
    }
1482
0
    if (!drbg->generate(drbg, out.len, out.ptr))
1483
0
    {
1484
0
      goto failure;
1485
0
    }
1486
0
    if (!chunk_equals(out, vector->out))
1487
0
    {
1488
0
      goto failure;
1489
0
    }
1490
0
    failed = FALSE;
1491
1492
0
failure:
1493
0
    drbg->destroy(drbg);
1494
0
    chunk_free(&out);
1495
0
    if (failed)
1496
0
    {
1497
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1498
0
         drbg_type_names, type, plugin_name, get_name(vector));
1499
0
      break;
1500
0
    }
1501
0
  }
1502
0
  enumerator->destroy(enumerator);
1503
0
  if (!tested)
1504
0
  {
1505
0
    DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1506
0
       this->required ? "disabled" : "enabled ",
1507
0
       drbg_type_names, type, plugin_name);
1508
0
    return !this->required;
1509
0
  }
1510
0
  if (!failed)
1511
0
  {
1512
0
    if (speed)
1513
0
    {
1514
0
      *speed = bench_drbg(this, type, create);
1515
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
1516
0
         drbg_type_names, type, plugin_name, tested, *speed);
1517
0
    }
1518
0
    else
1519
0
    {
1520
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
1521
0
         drbg_type_names, type, plugin_name, tested);
1522
0
    }
1523
0
  }
1524
0
  return !failed;
1525
0
}
1526
1527
/**
1528
 * Benchmark a RNG
1529
 */
1530
static u_int bench_rng(private_crypto_tester_t *this,
1531
             rng_quality_t quality, rng_constructor_t create)
1532
0
{
1533
0
  rng_t *rng;
1534
1535
0
  rng = create(quality);
1536
0
  if (rng)
1537
0
  {
1538
0
    struct timespec start;
1539
0
    chunk_t buf;
1540
0
    u_int runs;
1541
1542
0
    runs = 0;
1543
0
    buf = chunk_alloc(this->bench_size);
1544
0
    start_timing(&start);
1545
0
    while (end_timing(&start) < this->bench_time)
1546
0
    {
1547
0
      if (!rng->get_bytes(rng, buf.len, buf.ptr))
1548
0
      {
1549
0
        runs = 0;
1550
0
        break;
1551
0
      }
1552
0
      runs++;
1553
0
    }
1554
0
    free(buf.ptr);
1555
0
    rng->destroy(rng);
1556
1557
0
    return runs;
1558
0
  }
1559
0
  return 0;
1560
0
}
1561
1562
METHOD(crypto_tester_t, test_rng, bool,
1563
  private_crypto_tester_t *this, rng_quality_t quality,
1564
  rng_constructor_t create, u_int *speed, const char *plugin_name)
1565
0
{
1566
0
  enumerator_t *enumerator;
1567
0
  rng_test_vector_t *vector;
1568
0
  bool failed = FALSE;
1569
0
  u_int tested = 0;
1570
1571
0
  if (!this->rng_true && quality == RNG_TRUE)
1572
0
  {
1573
0
    DBG1(DBG_LIB, "enabled  %N[%s]: skipping test (disabled by config)",
1574
0
       rng_quality_names, quality, plugin_name);
1575
0
    return TRUE;
1576
0
  }
1577
1578
0
  enumerator = this->rng->create_enumerator(this->rng);
1579
0
  while (enumerator->enumerate(enumerator, &vector))
1580
0
  {
1581
0
    chunk_t data = chunk_empty;
1582
0
    rng_t *rng;
1583
1584
0
    if (vector->quality != quality)
1585
0
    {
1586
0
      continue;
1587
0
    }
1588
1589
0
    tested++;
1590
0
    failed = TRUE;
1591
0
    rng = create(quality);
1592
0
    if (!rng)
1593
0
    {
1594
0
      DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
1595
0
         rng_quality_names, quality, plugin_name);
1596
0
      break;
1597
0
    }
1598
1599
    /* allocated bytes */
1600
0
    if (!rng->allocate_bytes(rng, vector->len, &data) ||
1601
0
      data.len != vector->len ||
1602
0
      !vector->test(vector->user, data))
1603
0
    {
1604
0
      goto failure;
1605
0
    }
1606
    /* write bytes into existing buffer */
1607
0
    memset(data.ptr, 0, data.len);
1608
0
    if (!rng->get_bytes(rng, vector->len, data.ptr))
1609
0
    {
1610
0
      goto failure;
1611
0
    }
1612
0
    if (!vector->test(vector->user, data))
1613
0
    {
1614
0
      goto failure;
1615
0
    }
1616
1617
0
    failed = FALSE;
1618
0
failure:
1619
0
    rng->destroy(rng);
1620
0
    chunk_free(&data);
1621
0
    if (failed)
1622
0
    {
1623
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1624
0
         rng_quality_names, quality, plugin_name, get_name(vector));
1625
0
      break;
1626
0
    }
1627
0
  }
1628
0
  enumerator->destroy(enumerator);
1629
0
  if (!tested)
1630
0
  {
1631
0
    DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
1632
0
       this->required ? ", disabled" : "enabled ",
1633
0
       rng_quality_names, quality, plugin_name);
1634
0
    return !this->required;
1635
0
  }
1636
0
  if (!failed)
1637
0
  {
1638
0
    if (speed)
1639
0
    {
1640
0
      *speed = bench_rng(this, quality, create);
1641
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
1642
0
         rng_quality_names, quality, plugin_name, tested, *speed);
1643
0
    }
1644
0
    else
1645
0
    {
1646
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
1647
0
         rng_quality_names, quality, plugin_name, tested);
1648
0
    }
1649
0
  }
1650
0
  return !failed;
1651
0
}
1652
1653
/**
1654
 * Benchmark a key exchange backend
1655
 */
1656
static u_int bench_ke(private_crypto_tester_t *this,
1657
            key_exchange_method_t method, ke_constructor_t create)
1658
0
{
1659
0
  chunk_t a_pub = chunk_empty, b_pub = chunk_empty, shared = chunk_empty;
1660
0
  key_exchange_t *a, *b;
1661
0
  struct timespec start;
1662
0
  u_int runs;
1663
1664
0
  runs = 0;
1665
0
  start_timing(&start);
1666
0
  while (end_timing(&start) < this->bench_time)
1667
0
  {
1668
0
    a = create(method);
1669
0
    b = create(method);
1670
0
    if (!a || !b)
1671
0
    {
1672
0
      DESTROY_IF(a);
1673
0
      DESTROY_IF(b);
1674
0
      return 0;
1675
0
    }
1676
0
    if (a->get_public_key(a, &a_pub) &&
1677
0
      b->set_public_key(b,  a_pub) &&
1678
0
      b->get_public_key(b, &b_pub) &&
1679
0
      a->set_public_key(a,  b_pub) &&
1680
0
      a->get_shared_secret(a, &shared))
1681
0
    {
1682
0
      runs++;
1683
0
    }
1684
0
    chunk_free(&a_pub);
1685
0
    chunk_free(&b_pub);
1686
0
    chunk_free(&shared);
1687
0
    a->destroy(a);
1688
0
    b->destroy(b);
1689
0
  }
1690
0
  return runs;
1691
0
}
1692
1693
#ifdef TESTABLE_KE
1694
1695
static bool test_single_ke(key_exchange_method_t method, ke_test_vector_t *v,
1696
               ke_constructor_t create)
1697
0
{
1698
0
  rng_t *entropy = NULL;
1699
0
  drbg_t *drbg = NULL;
1700
0
  key_exchange_t *a = NULL, *b = NULL;
1701
0
  chunk_t a_priv, b_priv, a_pub, b_pub, a_sec, b_sec;
1702
0
  bool success = FALSE;
1703
1704
0
  a_pub = b_pub = a_sec = b_sec = chunk_empty;
1705
0
  a = create(method);
1706
0
  b = create(method);
1707
0
  if (!a || !b)
1708
0
  {
1709
0
    goto failure;
1710
0
  }
1711
1712
0
  if (key_exchange_is_kem(method))
1713
0
  {
1714
    /* entropy instance will be owned by drbg */
1715
0
    entropy = rng_tester_create(v->seed);
1716
0
    drbg = lib->crypto->create_drbg(lib->crypto, DRBG_CTR_AES256, 256,
1717
0
                    entropy, chunk_empty);
1718
0
    if (!drbg)
1719
0
    {
1720
0
      entropy->destroy(entropy);
1721
0
      goto failure;
1722
0
    }
1723
0
    if (!a->set_seed(a, chunk_empty, drbg) ||
1724
0
      !b->set_seed(b, chunk_empty, drbg))
1725
0
    {
1726
0
      goto failure;
1727
0
    }
1728
0
  }
1729
0
  else
1730
0
  {
1731
    /* the seed is the concatenation of both DH private keys */
1732
0
    a_priv = chunk_create(v->seed.ptr, v->seed.len/2);
1733
0
    b_priv = chunk_create(v->seed.ptr + v->seed.len/2, v->seed.len/2);
1734
1735
0
    if (!a->set_seed(a, a_priv, NULL) || !b->set_seed(b, b_priv, NULL))
1736
0
    {
1737
0
      goto failure;
1738
0
    }
1739
0
  }
1740
0
  if (!a->get_public_key(a, &a_pub) || !chunk_equals(a_pub, v->pub_i))
1741
0
  {
1742
0
    goto failure;
1743
0
  }
1744
0
  if (!b->set_public_key(b, a_pub))
1745
0
  {
1746
0
    goto failure;
1747
0
  }
1748
0
  if (!b->get_shared_secret(b, &b_sec) || !chunk_equals(b_sec, v->shared))
1749
0
  {
1750
0
    goto failure;
1751
0
  }
1752
0
  if (!b->get_public_key(b, &b_pub) || !chunk_equals(b_pub, v->pub_r))
1753
0
  {
1754
0
    goto failure;
1755
0
  }
1756
0
  if (!a->set_public_key(a, b_pub))
1757
0
  {
1758
0
    goto failure;
1759
0
  }
1760
0
  if (!a->get_shared_secret(a, &a_sec) || !chunk_equals(a_sec, v->shared))
1761
0
  {
1762
0
    goto failure;
1763
0
  }
1764
0
  success = TRUE;
1765
1766
0
failure:
1767
0
  DESTROY_IF(a);
1768
0
  DESTROY_IF(b);
1769
0
  chunk_free(&a_pub);
1770
0
  chunk_free(&b_pub);
1771
0
  chunk_free(&a_sec);
1772
0
  chunk_free(&b_sec);
1773
0
  DESTROY_IF(drbg);
1774
0
  return success;
1775
0
}
1776
1777
#else /* TESTABLE_KE */
1778
1779
static bool test_single_ke(key_exchange_method_t method, ke_constructor_t create)
1780
{
1781
  key_exchange_t *a = NULL, *b = NULL;
1782
  chunk_t a_pub, b_pub, a_sec, b_sec;
1783
  bool success = FALSE;
1784
1785
  a_pub = b_pub = a_sec = b_sec = chunk_empty;
1786
  a = create(method);
1787
  b = create(method);
1788
  if (!a || !b)
1789
  {
1790
    goto failure;
1791
  }
1792
  if (!a->get_public_key(a, &a_pub) ||
1793
    !b->set_public_key(b, a_pub) ||
1794
    !b->get_shared_secret(b, &b_sec) ||
1795
    !b->get_public_key(b, &b_pub) ||
1796
     chunk_equals(a_pub, b_pub) ||
1797
    !a->set_public_key(a, b_pub) ||
1798
    !a->get_shared_secret(a, &a_sec) ||
1799
    !chunk_equals(a_sec, b_sec))
1800
  {
1801
    goto failure;
1802
  }
1803
  success = TRUE;
1804
1805
failure:
1806
  DESTROY_IF(a);
1807
  DESTROY_IF(b);
1808
  chunk_free(&a_pub);
1809
  chunk_free(&b_pub);
1810
  chunk_free(&a_sec);
1811
  chunk_free(&b_sec);
1812
  return success;
1813
}
1814
1815
#endif /* TESTABLE_KE */
1816
1817
METHOD(crypto_tester_t, test_ke, bool,
1818
  private_crypto_tester_t *this, key_exchange_method_t method,
1819
  ke_constructor_t create, u_int *speed, const char *plugin_name)
1820
0
{
1821
0
#ifdef TESTABLE_KE
1822
0
  enumerator_t *enumerator;
1823
0
  ke_test_vector_t *v;
1824
0
  bool success = TRUE;
1825
0
  u_int tested = 0;
1826
1827
0
  enumerator = this->ke->create_enumerator(this->ke);
1828
0
  while (enumerator->enumerate(enumerator, &v))
1829
0
  {
1830
0
    if (v->method != method)
1831
0
    {
1832
0
      continue;
1833
0
    }
1834
0
    success = test_single_ke(method, v, create);
1835
0
    tested++;
1836
1837
0
    if (!success)
1838
0
    {
1839
0
      DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
1840
0
         key_exchange_method_names, method, plugin_name, get_name(v));
1841
0
      break;
1842
0
    }
1843
0
  }
1844
0
  enumerator->destroy(enumerator);
1845
1846
0
  if (!tested)
1847
0
  {
1848
0
    DBG1(DBG_LIB, "%s %N[%s]: no test vectors found / untestable",
1849
0
       this->required ? "disabled" : "enabled ",
1850
0
       key_exchange_method_names, method, plugin_name);
1851
0
    return !this->required;
1852
0
  }
1853
1854
0
  if (success)
1855
0
  {
1856
0
    if (speed)
1857
0
    {
1858
0
      *speed = bench_ke(this, method, create);
1859
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors, %d points",
1860
0
         key_exchange_method_names, method, plugin_name, tested, *speed);
1861
0
    }
1862
0
    else
1863
0
    {
1864
0
      DBG1(DBG_LIB, "enabled  %N[%s]: passed %u test vectors",
1865
0
         key_exchange_method_names, method, plugin_name, tested);
1866
0
    }
1867
0
  }
1868
0
  return success;
1869
1870
#else /* TESTABLE_KE */
1871
1872
  if (method == MODP_CUSTOM)
1873
  {
1874
    DBG1(DBG_LIB, "enabled  %N[%s]: untestable",
1875
       key_exchange_method_names, method, plugin_name);
1876
    return TRUE;
1877
  }
1878
1879
  if (!test_single_ke(method, create))
1880
  {
1881
    DBG1(DBG_LIB, "disabled %N[%s]: failed basic test",
1882
       key_exchange_method_names, method, plugin_name);
1883
    return FALSE;
1884
  }
1885
1886
  if (speed)
1887
  {
1888
    *speed = bench_ke(this, method, create);
1889
    DBG1(DBG_LIB, "enabled  %N[%s]: passed basic test (vector tests "
1890
       "disabled), %d points", key_exchange_method_names, method,
1891
       plugin_name, *speed);
1892
  }
1893
  else
1894
  {
1895
    DBG1(DBG_LIB, "enabled  %N[%s]: passed basic test (vector tests "
1896
       "disabled)", key_exchange_method_names, method, plugin_name);
1897
  }
1898
  return TRUE;
1899
1900
#endif /* TESTABLE_KE */
1901
0
}
1902
1903
METHOD(crypto_tester_t, add_crypter_vector, void,
1904
  private_crypto_tester_t *this, crypter_test_vector_t *vector)
1905
0
{
1906
0
  this->crypter->insert_last(this->crypter, vector);
1907
0
}
1908
1909
METHOD(crypto_tester_t, add_aead_vector, void,
1910
  private_crypto_tester_t *this, aead_test_vector_t *vector)
1911
0
{
1912
0
  this->aead->insert_last(this->aead, vector);
1913
0
}
1914
1915
METHOD(crypto_tester_t, add_signer_vector, void,
1916
  private_crypto_tester_t *this, signer_test_vector_t *vector)
1917
0
{
1918
0
  this->signer->insert_last(this->signer, vector);
1919
0
}
1920
1921
METHOD(crypto_tester_t, add_hasher_vector, void,
1922
  private_crypto_tester_t *this, hasher_test_vector_t *vector)
1923
0
{
1924
0
  this->hasher->insert_last(this->hasher, vector);
1925
0
}
1926
1927
METHOD(crypto_tester_t, add_prf_vector, void,
1928
  private_crypto_tester_t *this, prf_test_vector_t *vector)
1929
0
{
1930
0
  this->prf->insert_last(this->prf, vector);
1931
0
}
1932
1933
METHOD(crypto_tester_t, add_xof_vector, void,
1934
  private_crypto_tester_t *this, xof_test_vector_t *vector)
1935
0
{
1936
0
  this->xof->insert_last(this->xof, vector);
1937
0
}
1938
1939
METHOD(crypto_tester_t, add_kdf_vector, void,
1940
  private_crypto_tester_t *this, kdf_test_vector_t *vector)
1941
0
{
1942
0
  this->kdf->insert_last(this->kdf, vector);
1943
0
}
1944
1945
METHOD(crypto_tester_t, add_drbg_vector, void,
1946
  private_crypto_tester_t *this, drbg_test_vector_t *vector)
1947
0
{
1948
0
  this->drbg->insert_last(this->drbg, vector);
1949
0
}
1950
1951
METHOD(crypto_tester_t, add_rng_vector, void,
1952
  private_crypto_tester_t *this, rng_test_vector_t *vector)
1953
0
{
1954
0
  this->rng->insert_last(this->rng, vector);
1955
0
}
1956
1957
METHOD(crypto_tester_t, add_ke_vector, void,
1958
  private_crypto_tester_t *this, ke_test_vector_t *vector)
1959
0
{
1960
0
  this->ke->insert_last(this->ke, vector);
1961
0
}
1962
1963
METHOD(crypto_tester_t, destroy, void,
1964
  private_crypto_tester_t *this)
1965
16.5k
{
1966
16.5k
  this->crypter->destroy(this->crypter);
1967
16.5k
  this->aead->destroy(this->aead);
1968
16.5k
  this->signer->destroy(this->signer);
1969
16.5k
  this->hasher->destroy(this->hasher);
1970
16.5k
  this->prf->destroy(this->prf);
1971
16.5k
  this->xof->destroy(this->xof);
1972
16.5k
  this->kdf->destroy(this->kdf);
1973
16.5k
  this->drbg->destroy(this->drbg);
1974
16.5k
  this->rng->destroy(this->rng);
1975
16.5k
  this->ke->destroy(this->ke);
1976
16.5k
  free(this);
1977
16.5k
}
1978
1979
/**
1980
 * See header
1981
 */
1982
crypto_tester_t *crypto_tester_create()
1983
16.5k
{
1984
16.5k
  private_crypto_tester_t *this;
1985
1986
16.5k
  INIT(this,
1987
16.5k
    .public = {
1988
16.5k
      .test_crypter = _test_crypter,
1989
16.5k
      .test_aead = _test_aead,
1990
16.5k
      .test_signer = _test_signer,
1991
16.5k
      .test_hasher = _test_hasher,
1992
16.5k
      .test_prf = _test_prf,
1993
16.5k
      .test_xof = _test_xof,
1994
16.5k
      .test_kdf = _test_kdf,
1995
16.5k
      .test_drbg = _test_drbg,
1996
16.5k
      .test_rng = _test_rng,
1997
16.5k
      .test_ke = _test_ke,
1998
16.5k
      .add_crypter_vector = _add_crypter_vector,
1999
16.5k
      .add_aead_vector = _add_aead_vector,
2000
16.5k
      .add_signer_vector = _add_signer_vector,
2001
16.5k
      .add_hasher_vector = _add_hasher_vector,
2002
16.5k
      .add_prf_vector = _add_prf_vector,
2003
16.5k
      .add_xof_vector = _add_xof_vector,
2004
16.5k
      .add_kdf_vector = _add_kdf_vector,
2005
16.5k
      .add_drbg_vector = _add_drbg_vector,
2006
16.5k
      .add_rng_vector = _add_rng_vector,
2007
16.5k
      .add_ke_vector = _add_ke_vector,
2008
16.5k
      .destroy = _destroy,
2009
16.5k
    },
2010
16.5k
    .crypter = linked_list_create(),
2011
16.5k
    .aead = linked_list_create(),
2012
16.5k
    .signer = linked_list_create(),
2013
16.5k
    .hasher = linked_list_create(),
2014
16.5k
    .prf = linked_list_create(),
2015
16.5k
    .xof = linked_list_create(),
2016
16.5k
    .kdf = linked_list_create(),
2017
16.5k
    .drbg = linked_list_create(),
2018
16.5k
    .rng = linked_list_create(),
2019
16.5k
    .ke = linked_list_create(),
2020
2021
16.5k
    .required = lib->settings->get_bool(lib->settings,
2022
16.5k
                "%s.crypto_test.required", FALSE, lib->ns),
2023
16.5k
    .rng_true = lib->settings->get_bool(lib->settings,
2024
16.5k
                "%s.crypto_test.rng_true", FALSE, lib->ns),
2025
16.5k
    .bench_time = lib->settings->get_int(lib->settings,
2026
16.5k
                "%s.crypto_test.bench_time", 50, lib->ns),
2027
16.5k
    .bench_size = lib->settings->get_int(lib->settings,
2028
16.5k
                "%s.crypto_test.bench_size", 1024, lib->ns),
2029
16.5k
  );
2030
2031
  /* enforce a block size of 16, should be fine for all algorithms */
2032
16.5k
  this->bench_size = this->bench_size / 16 * 16;
2033
2034
16.5k
  return &this->public;
2035
16.5k
}