Files
strongswan-ext/src/libstrongswan/crypto/crypto_tester.c
T
Tobias Brunner 6cbd93838b Add configure option to disable testing key exchange methods
If this is used, the functionality to set a private key/value/seed for
key exchange methods is removed (including from the interface to avoid
accidentally forgetting to wrap implementations and uses of set_seed()).

The set_seed() method is assigned outside the INIT() macro to avoid
potentially undefined behavior (preprocessing directives in macro
arguments).

The test done by the crypto tester is a simple functionality test.
2025-04-10 08:31:09 +02:00

2036 lines
43 KiB
C

/*
* Copyright (C) 2009-2010 Martin Willi
* Copyright (C) 2016-2019 Andreas Steffen
*
* Copyright (C) secunet Security Networks AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifdef HAVE_DLADDR
# define _GNU_SOURCE
# include <dlfcn.h>
#endif
#include <time.h>
#include "crypto_tester.h"
#include <utils/debug.h>
#include <collections/linked_list.h>
#include <crypto/rngs/rng_tester.h>
typedef struct private_crypto_tester_t private_crypto_tester_t;
/**
* Private data of an crypto_tester_t object.
*/
struct private_crypto_tester_t {
/**
* Public crypto_tester_t interface.
*/
crypto_tester_t public;
/**
* List of crypter test vectors
*/
linked_list_t *crypter;
/**
* List of aead test vectors
*/
linked_list_t *aead;
/**
* List of signer test vectors
*/
linked_list_t *signer;
/**
* List of hasher test vectors
*/
linked_list_t *hasher;
/**
* List of PRF test vectors
*/
linked_list_t *prf;
/**
* List of XOF test vectors
*/
linked_list_t *xof;
/**
* List of KDF test vectors
*/
linked_list_t *kdf;
/**
* List of DRBG test vectors
*/
linked_list_t *drbg;
/**
* List of RNG test vectors
*/
linked_list_t *rng;
/**
* List of key exchange method test vectors
*/
linked_list_t *ke;
/**
* Is a test vector required to pass a test?
*/
bool required;
/**
* should we run RNG_TRUE tests? Enough entropy?
*/
bool rng_true;
/**
* time we test each algorithm
*/
int bench_time;
/**
* size of buffer we use for benchmarking
*/
int bench_size;
};
#if DEBUG_LEVEL >= 1
/**
* Get the name of a test vector, if available
*/
static const char* get_name(void *sym)
{
#ifdef HAVE_DLADDR
Dl_info dli;
if (dladdr(sym, &dli))
{
return dli.dli_sname;
}
#endif
return "unknown";
}
#endif
#if defined(CLOCK_THREAD_CPUTIME_ID) && defined(HAVE_CLOCK_GETTIME)
/**
* Start a benchmark timer
*/
static void start_timing(struct timespec *start)
{
clock_gettime(CLOCK_THREAD_CPUTIME_ID, start);
}
/**
* End a benchmark timer, return ms
*/
static u_int end_timing(struct timespec *start)
{
struct timespec end;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
return (end.tv_nsec - start->tv_nsec) / 1000000 +
(end.tv_sec - start->tv_sec) * 1000;
}
#else /* CLOCK_THREAD_CPUTIME_ID */
/* Make benchmarking a no-op if CLOCK_THREAD_CPUTIME_ID is not available */
#define start_timing(start) ((start)->tv_sec = 0, (start)->tv_nsec = 0)
#define end_timing(...) (this->bench_time)
#endif /* CLOCK_THREAD_CPUTIME_ID */
/**
* Benchmark a crypter
*/
static u_int bench_crypter(private_crypto_tester_t *this,
encryption_algorithm_t alg, crypter_constructor_t create, size_t key_size)
{
crypter_t *crypter;
crypter = create(alg, key_size);
if (crypter)
{
char iv[crypter->get_iv_size(crypter)];
char key[crypter->get_key_size(crypter)];
chunk_t buf;
struct timespec start;
u_int runs;
memset(iv, 0x56, sizeof(iv));
memset(key, 0x12, sizeof(key));
if (!crypter->set_key(crypter, chunk_from_thing(key)))
{
return 0;
}
buf = chunk_alloc(this->bench_size);
memset(buf.ptr, 0x34, buf.len);
runs = 0;
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
if (crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL))
{
runs++;
}
if (crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL))
{
runs++;
}
}
free(buf.ptr);
crypter->destroy(crypter);
return runs;
}
return 0;
}
METHOD(crypto_tester_t, test_crypter, bool,
private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
crypter_constructor_t create, u_int *speed, const char *plugin_name)
{
enumerator_t *enumerator;
crypter_test_vector_t *vector;
bool failed = FALSE;
u_int tested = 0;
enumerator = this->crypter->create_enumerator(this->crypter);
while (enumerator->enumerate(enumerator, &vector))
{
crypter_t *crypter;
chunk_t key, iv, plain = chunk_empty, cipher = chunk_empty;
if (vector->alg != alg)
{
continue;
}
if (key_size && key_size != vector->key_size)
{ /* test only vectors with a specific key size, if key size given */
continue;
}
crypter = create(alg, vector->key_size);
if (!crypter)
{ /* key size not supported */
continue;
}
tested++;
failed = TRUE;
key = chunk_create(vector->key, crypter->get_key_size(crypter));
if (!crypter->set_key(crypter, key))
{
goto failure;
}
iv = chunk_create(vector->iv, crypter->get_iv_size(crypter));
/* allocated encryption */
plain = chunk_create(vector->plain, vector->len);
if (!crypter->encrypt(crypter, plain, iv, &cipher))
{
goto failure;
}
if (!memeq(vector->cipher, cipher.ptr, cipher.len))
{
goto failure;
}
/* inline decryption */
if (!crypter->decrypt(crypter, cipher, iv, NULL))
{
goto failure;
}
if (!memeq(vector->plain, cipher.ptr, cipher.len))
{
goto failure;
}
/* allocated decryption */
if (!crypter->decrypt(crypter,
chunk_create(vector->cipher, vector->len), iv, &plain))
{
goto failure;
}
if (!memeq(vector->plain, plain.ptr, plain.len))
{
goto failure;
}
/* inline encryption */
if (!crypter->encrypt(crypter, plain, iv, NULL))
{
goto failure;
}
if (!memeq(vector->cipher, plain.ptr, plain.len))
{
goto failure;
}
failed = FALSE;
failure:
crypter->destroy(crypter);
chunk_free(&cipher);
if (plain.ptr != vector->plain)
{
chunk_free(&plain);
}
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
encryption_algorithm_names, alg, plugin_name, get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
if (failed)
{
DBG1(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
encryption_algorithm_names, alg, plugin_name, key_size);
return FALSE;
}
else
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? "disabled" : "enabled ",
encryption_algorithm_names, alg, plugin_name);
return !this->required;
}
}
if (!failed)
{
if (speed)
{
*speed = bench_crypter(this, alg, create, key_size);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points "
"(%zd bit key)", encryption_algorithm_names, alg,
plugin_name, tested, *speed, key_size * 8);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
encryption_algorithm_names, alg, plugin_name, tested);
}
}
return !failed;
}
/**
* Benchmark an aead transform
*/
static u_int bench_aead(private_crypto_tester_t *this,
encryption_algorithm_t alg, aead_constructor_t create, size_t key_size)
{
aead_t *aead;
aead = create(alg, key_size, 0);
if (aead)
{
char iv[aead->get_iv_size(aead)];
char key[aead->get_key_size(aead)];
char assoc[4];
chunk_t buf;
struct timespec start;
u_int runs;
size_t icv;
memset(iv, 0x56, sizeof(iv));
memset(key, 0x12, sizeof(key));
memset(assoc, 0x78, sizeof(assoc));
if (!aead->set_key(aead, chunk_from_thing(key)))
{
return 0;
}
icv = aead->get_icv_size(aead);
buf = chunk_alloc(this->bench_size + icv);
memset(buf.ptr, 0x34, buf.len);
buf.len -= icv;
runs = 0;
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
if (aead->encrypt(aead, buf, chunk_from_thing(assoc),
chunk_from_thing(iv), NULL))
{
runs += 2;
}
if (aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv),
chunk_from_thing(assoc), chunk_from_thing(iv), NULL))
{
runs += 2;
}
}
free(buf.ptr);
aead->destroy(aead);
return runs;
}
return 0;
}
METHOD(crypto_tester_t, test_aead, bool,
private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
size_t salt_size, aead_constructor_t create,
u_int *speed, const char *plugin_name)
{
enumerator_t *enumerator;
aead_test_vector_t *vector;
bool failed = FALSE;
u_int tested = 0;
enumerator = this->aead->create_enumerator(this->aead);
while (enumerator->enumerate(enumerator, &vector))
{
aead_t *aead;
chunk_t key, iv, assoc, plain = chunk_empty, cipher = chunk_empty;
size_t icv;
if (vector->alg != alg)
{
continue;
}
if (key_size && key_size != vector->key_size)
{ /* test only vectors with a specific key size, if key size given */
continue;
}
if (salt_size && salt_size != vector->salt_size)
{
continue;
}
tested++;
failed = TRUE;
aead = create(alg, vector->key_size, vector->salt_size);
if (!aead)
{
DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
encryption_algorithm_names, alg, plugin_name,
BITS_PER_BYTE * vector->key_size);
continue;
}
key = chunk_create(vector->key, aead->get_key_size(aead));
if (!aead->set_key(aead, key))
{
goto failure;
}
iv = chunk_create(vector->iv, aead->get_iv_size(aead));
assoc = chunk_create(vector->adata, vector->alen);
icv = aead->get_icv_size(aead);
/* allocated encryption */
plain = chunk_create(vector->plain, vector->len);
if (!aead->encrypt(aead, plain, assoc, iv, &cipher))
{
goto failure;
}
if (!memeq(vector->cipher, cipher.ptr, cipher.len))
{
goto failure;
}
/* inline decryption */
if (!aead->decrypt(aead, cipher, assoc, iv, NULL))
{
goto failure;
}
if (!memeq(vector->plain, cipher.ptr, cipher.len - icv))
{
goto failure;
}
/* allocated decryption */
if (!aead->decrypt(aead, chunk_create(vector->cipher, vector->len + icv),
assoc, iv, &plain))
{
goto failure;
}
if (!memeq(vector->plain, plain.ptr, plain.len))
{
goto failure;
}
plain.ptr = realloc(plain.ptr, plain.len + icv);
/* inline encryption */
if (!aead->encrypt(aead, plain, assoc, iv, NULL))
{
goto failure;
}
if (!memeq(vector->cipher, plain.ptr, plain.len + icv))
{
goto failure;
}
failed = FALSE;
failure:
aead->destroy(aead);
chunk_free(&cipher);
if (plain.ptr != vector->plain)
{
chunk_free(&plain);
}
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
encryption_algorithm_names, alg, plugin_name, get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
if (failed)
{
DBG1(DBG_LIB,"disable %N[%s]: %zd byte key size not supported",
encryption_algorithm_names, alg, plugin_name, key_size);
return FALSE;
}
else
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? "disabled" : "enabled ",
encryption_algorithm_names, alg, plugin_name);
return !this->required;
}
}
if (!failed)
{
if (speed)
{
*speed = bench_aead(this, alg, create, key_size);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points "
"(%zd bit key)", encryption_algorithm_names, alg,
plugin_name, tested, *speed, key_size * 8);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
encryption_algorithm_names, alg, plugin_name, tested);
}
}
return !failed;
}
/**
* Benchmark a signer
*/
static u_int bench_signer(private_crypto_tester_t *this,
integrity_algorithm_t alg, signer_constructor_t create)
{
signer_t *signer;
signer = create(alg);
if (signer)
{
char key[signer->get_key_size(signer)];
char mac[signer->get_block_size(signer)];
chunk_t buf;
struct timespec start;
u_int runs;
memset(key, 0x12, sizeof(key));
if (!signer->set_key(signer, chunk_from_thing(key)))
{
return 0;
}
buf = chunk_alloc(this->bench_size);
memset(buf.ptr, 0x34, buf.len);
runs = 0;
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
if (signer->get_signature(signer, buf, mac))
{
runs++;
}
if (signer->verify_signature(signer, buf, chunk_from_thing(mac)))
{
runs++;
}
}
free(buf.ptr);
signer->destroy(signer);
return runs;
}
return 0;
}
METHOD(crypto_tester_t, test_signer, bool,
private_crypto_tester_t *this, integrity_algorithm_t alg,
signer_constructor_t create, u_int *speed, const char *plugin_name)
{
enumerator_t *enumerator;
signer_test_vector_t *vector;
bool failed = FALSE;
u_int tested = 0;
enumerator = this->signer->create_enumerator(this->signer);
while (enumerator->enumerate(enumerator, &vector))
{
signer_t *signer;
chunk_t key, data, mac = chunk_empty;
if (vector->alg != alg)
{
continue;
}
tested++;
failed = TRUE;
signer = create(alg);
if (!signer)
{
DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
integrity_algorithm_names, alg, plugin_name);
break;
}
data = chunk_create(vector->data, vector->len);
key = chunk_create(vector->key, signer->get_key_size(signer));
if (!signer->set_key(signer, key))
{
goto failure;
}
/* do partial append mode and check if key gets set correctly */
if (!signer->get_signature(signer, data, NULL))
{
goto failure;
}
if (!signer->set_key(signer, key))
{
goto failure;
}
/* allocated signature */
if (!signer->allocate_signature(signer, data, &mac))
{
goto failure;
}
if (mac.len != signer->get_block_size(signer))
{
goto failure;
}
if (!memeq(vector->mac, mac.ptr, mac.len))
{
goto failure;
}
/* signature to existing buffer */
memset(mac.ptr, 0, mac.len);
if (!signer->get_signature(signer, data, mac.ptr))
{
goto failure;
}
if (!memeq(vector->mac, mac.ptr, mac.len))
{
goto failure;
}
/* signature verification, good case */
if (!signer->verify_signature(signer, data, mac))
{
goto failure;
}
/* signature verification, bad case */
*(mac.ptr + mac.len - 1) += 1;
if (signer->verify_signature(signer, data, mac))
{
goto failure;
}
/* signature to existing buffer, using append mode */
if (data.len > 2)
{
if (!signer->allocate_signature(signer,
chunk_create(data.ptr, 1), NULL))
{
goto failure;
}
if (!signer->get_signature(signer,
chunk_create(data.ptr + 1, 1), NULL))
{
goto failure;
}
if (!signer->verify_signature(signer, chunk_skip(data, 2),
chunk_create(vector->mac, mac.len)))
{
goto failure;
}
}
failed = FALSE;
failure:
signer->destroy(signer);
chunk_free(&mac);
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
integrity_algorithm_names, alg, plugin_name, get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? "disabled" : "enabled ",
integrity_algorithm_names, alg, plugin_name);
return !this->required;
}
if (!failed)
{
if (speed)
{
*speed = bench_signer(this, alg, create);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
integrity_algorithm_names, alg, plugin_name, tested, *speed);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
integrity_algorithm_names, alg, plugin_name, tested);
}
}
return !failed;
}
/**
* Benchmark a hasher
*/
static u_int bench_hasher(private_crypto_tester_t *this,
hash_algorithm_t alg, hasher_constructor_t create)
{
hasher_t *hasher;
hasher = create(alg);
if (hasher)
{
char hash[hasher->get_hash_size(hasher)];
chunk_t buf;
struct timespec start;
u_int runs;
buf = chunk_alloc(this->bench_size);
memset(buf.ptr, 0x34, buf.len);
runs = 0;
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
if (hasher->get_hash(hasher, buf, hash))
{
runs++;
}
}
free(buf.ptr);
hasher->destroy(hasher);
return runs;
}
return 0;
}
METHOD(crypto_tester_t, test_hasher, bool,
private_crypto_tester_t *this, hash_algorithm_t alg,
hasher_constructor_t create, u_int *speed, const char *plugin_name)
{
enumerator_t *enumerator;
hasher_test_vector_t *vector;
bool failed = FALSE;
u_int tested = 0;
enumerator = this->hasher->create_enumerator(this->hasher);
while (enumerator->enumerate(enumerator, &vector))
{
hasher_t *hasher;
chunk_t data, hash;
if (vector->alg != alg)
{
continue;
}
tested++;
failed = TRUE;
hasher = create(alg);
if (!hasher)
{
DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
hash_algorithm_names, alg, plugin_name);
break;
}
/* allocated hash */
data = chunk_create(vector->data, vector->len);
if (!hasher->allocate_hash(hasher, data, &hash))
{
goto failure;
}
if (hash.len != hasher->get_hash_size(hasher))
{
goto failure;
}
if (!memeq(vector->hash, hash.ptr, hash.len))
{
goto failure;
}
/* hash to existing buffer, with a reset */
memset(hash.ptr, 0, hash.len);
if (!hasher->get_hash(hasher, data, NULL))
{
goto failure;
}
if (!hasher->reset(hasher))
{
goto failure;
}
if (!hasher->get_hash(hasher, data, hash.ptr))
{
goto failure;
}
if (!memeq(vector->hash, hash.ptr, hash.len))
{
goto failure;
}
/* hasher to existing buffer, using append mode */
if (data.len > 2)
{
memset(hash.ptr, 0, hash.len);
if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL))
{
goto failure;
}
if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL))
{
goto failure;
}
if (!hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr))
{
goto failure;
}
if (!memeq(vector->hash, hash.ptr, hash.len))
{
goto failure;
}
}
failed = FALSE;
failure:
hasher->destroy(hasher);
chunk_free(&hash);
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
hash_algorithm_names, alg, plugin_name, get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? "disabled" : "enabled ",
hash_algorithm_names, alg, plugin_name);
return !this->required;
}
if (!failed)
{
if (speed)
{
*speed = bench_hasher(this, alg, create);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
hash_algorithm_names, alg, plugin_name, tested, *speed);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
hash_algorithm_names, alg, plugin_name, tested);
}
}
return !failed;
}
/**
* Benchmark a PRF
*/
static u_int bench_prf(private_crypto_tester_t *this,
pseudo_random_function_t alg, prf_constructor_t create)
{
prf_t *prf;
prf = create(alg);
if (prf)
{
char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)];
chunk_t buf;
struct timespec start;
u_int runs;
memset(key, 0x56, prf->get_block_size(prf));
if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf))))
{
prf->destroy(prf);
return 0;
}
buf = chunk_alloc(this->bench_size);
memset(buf.ptr, 0x34, buf.len);
runs = 0;
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
if (prf->get_bytes(prf, buf, bytes))
{
runs++;
}
}
free(buf.ptr);
prf->destroy(prf);
return runs;
}
return 0;
}
METHOD(crypto_tester_t, test_prf, bool,
private_crypto_tester_t *this, pseudo_random_function_t alg,
prf_constructor_t create, u_int *speed, const char *plugin_name)
{
enumerator_t *enumerator;
prf_test_vector_t *vector;
bool failed = FALSE;
u_int tested = 0;
enumerator = this->prf->create_enumerator(this->prf);
while (enumerator->enumerate(enumerator, &vector))
{
prf_t *prf;
chunk_t key, seed, out = chunk_empty;
if (vector->alg != alg)
{
continue;
}
tested++;
failed = TRUE;
prf = create(alg);
if (!prf)
{
DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
pseudo_random_function_names, alg, plugin_name);
break;
}
seed = chunk_create(vector->seed, vector->len);
key = chunk_create(vector->key, vector->key_size);
if (!prf->set_key(prf, key))
{
goto failure;
}
if (alg != PRF_FIPS_SHA1_160)
{
/* do partial append mode and check if key gets set correctly */
if (!prf->get_bytes(prf, seed, NULL))
{
goto failure;
}
if (!prf->set_key(prf, key))
{
goto failure;
}
}
/* allocated bytes */
if (!prf->allocate_bytes(prf, seed, &out))
{
goto failure;
}
if (out.len != prf->get_block_size(prf))
{
goto failure;
}
if (!memeq(vector->out, out.ptr, out.len))
{
goto failure;
}
/* bytes to existing buffer */
memset(out.ptr, 0, out.len);
if (vector->stateful)
{
if (!prf->set_key(prf, key))
{
goto failure;
}
}
if (!prf->get_bytes(prf, seed, out.ptr))
{
goto failure;
}
if (!memeq(vector->out, out.ptr, out.len))
{
goto failure;
}
/* bytes to existing buffer, using append mode */
if (alg != PRF_FIPS_SHA1_160 && seed.len > 2)
{
memset(out.ptr, 0, out.len);
if (vector->stateful)
{
if (!prf->set_key(prf, key))
{
goto failure;
}
}
if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL))
{
goto failure;
}
if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL))
{
goto failure;
}
if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr))
{
goto failure;
}
if (!memeq(vector->out, out.ptr, out.len))
{
goto failure;
}
}
failed = FALSE;
failure:
prf->destroy(prf);
chunk_free(&out);
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
pseudo_random_function_names, alg, plugin_name, get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? "disabled" : "enabled ",
pseudo_random_function_names, alg, plugin_name);
return !this->required;
}
if (!failed)
{
if (speed)
{
*speed = bench_prf(this, alg, create);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
pseudo_random_function_names, alg, plugin_name, tested, *speed);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
pseudo_random_function_names, alg, plugin_name, tested);
}
}
return !failed;
}
/**
* Benchmark an XOF
*/
static u_int bench_xof(private_crypto_tester_t *this,
ext_out_function_t alg, xof_constructor_t create)
{
xof_t *xof;
xof = create(alg);
if (xof)
{
char seed[xof->get_seed_size(xof)];
char bytes[xof->get_block_size(xof)];
struct timespec start;
u_int runs;
memset(seed, 0x56, xof->get_seed_size(xof));
if (!xof->set_seed(xof, chunk_create(seed, xof->get_seed_size(xof))))
{
xof->destroy(xof);
return 0;
}
runs = 0;
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
if (xof->get_bytes(xof, xof->get_block_size(xof), bytes))
{
runs++;
}
}
xof->destroy(xof);
return runs;
}
return 0;
}
METHOD(crypto_tester_t, test_xof, bool,
private_crypto_tester_t *this, ext_out_function_t alg,
xof_constructor_t create, u_int *speed, const char *plugin_name)
{
enumerator_t *enumerator;
xof_test_vector_t *vector;
bool failed = FALSE;
u_int tested = 0;
enumerator = this->xof->create_enumerator(this->xof);
while (enumerator->enumerate(enumerator, &vector))
{
xof_t *xof;
chunk_t seed, out = chunk_empty;
if (vector->alg != alg)
{
continue;
}
tested++;
failed = TRUE;
xof = create(alg);
if (!xof)
{
DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
ext_out_function_names, alg, plugin_name);
break;
}
seed = chunk_create(vector->seed, vector->len);
if (!xof->set_seed(xof, seed))
{
goto failure;
}
/* allocated bytes */
if (!xof->allocate_bytes(xof, vector->out_len, &out))
{
goto failure;
}
if (out.len != vector->out_len)
{
goto failure;
}
if (!memeq(vector->out, out.ptr, out.len))
{
goto failure;
}
/* bytes to existing buffer */
memset(out.ptr, 0, out.len);
if (!xof->set_seed(xof, seed))
{
goto failure;
}
if (!xof->get_bytes(xof, vector->out_len, out.ptr))
{
goto failure;
}
if (!memeq(vector->out, out.ptr, vector->out_len))
{
goto failure;
}
/* bytes to existing buffer, using append mode */
/* TODO */
failed = FALSE;
failure:
xof->destroy(xof);
chunk_free(&out);
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
ext_out_function_names, alg, plugin_name, get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? "disabled" : "enabled ",
ext_out_function_names, alg, plugin_name);
return !this->required;
}
if (!failed)
{
if (speed)
{
*speed = bench_xof(this, alg, create);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
ext_out_function_names, alg, plugin_name, tested, *speed);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
ext_out_function_names, alg, plugin_name, tested);
}
}
return !failed;
}
/**
* Create a KDF using the given arguments
*/
static kdf_t *create_kdf_args(kdf_constructor_t create,
key_derivation_function_t alg, ...)
{
va_list args;
kdf_t *kdf;
va_start(args, alg);
kdf = create(alg, args);
va_end(args);
return kdf;
}
/**
* Create a KDF using arguments from the given test vector
*/
static kdf_t *create_kdf_vector(kdf_constructor_t create,
key_derivation_function_t alg,
kdf_test_vector_t *vector)
{
switch (alg)
{
case KDF_PRF:
case KDF_PRF_PLUS:
return create_kdf_args(create, alg, vector->arg.prf);
case KDF_UNDEFINED:
break;
}
return NULL;
}
/**
* Check if the given test vector applies to the passed arguments
*/
static bool kdf_vector_applies(key_derivation_function_t alg,
kdf_test_args_t *args, kdf_test_vector_t *vector)
{
bool applies = FALSE;
switch (alg)
{
case KDF_PRF:
case KDF_PRF_PLUS:
{
pseudo_random_function_t prf;
VA_ARGS_VGET(args->args, prf);
applies = (prf == vector->arg.prf);
break;
}
case KDF_UNDEFINED:
break;
}
return applies;
}
METHOD(crypto_tester_t, test_kdf, bool,
private_crypto_tester_t *this, key_derivation_function_t alg,
kdf_constructor_t create, kdf_test_args_t *args, u_int *speed,
const char *plugin_name)
{
enumerator_t *enumerator;
kdf_test_vector_t *vector;
va_list copy;
bool failed = FALSE;
u_int tested = 0, construction_failed = 0;
enumerator = this->kdf->create_enumerator(this->kdf);
while (enumerator->enumerate(enumerator, &vector))
{
kdf_t *kdf;
chunk_t out = chunk_empty;
if (vector->alg != alg ||
(args && !kdf_vector_applies(alg, args, vector)))
{
continue;
}
tested++;
failed = TRUE;
if (args)
{
va_copy(copy, args->args);
kdf = create(alg, copy);
va_end(copy);
}
else
{
kdf = create_kdf_vector(create, alg, vector);
}
if (!kdf)
{
if (args)
{
DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
key_derivation_function_names, alg, plugin_name);
break;
}
/* while there could be a problem, the constructor might just not
* be able to create an instance for this test vector, we check
* for that at the end */
construction_failed++;
failed = FALSE;
continue;
}
if (vector->key.len &&
!kdf->set_param(kdf, KDF_PARAM_KEY, vector->key))
{
goto failure;
}
if (vector->salt.len &&
!kdf->set_param(kdf, KDF_PARAM_SALT, vector->salt))
{
goto failure;
}
if (kdf_has_fixed_output_length(alg))
{
if (kdf->get_length(kdf) != vector->out.len)
{
goto failure;
}
}
else if (kdf->get_length(kdf) != SIZE_MAX)
{
goto failure;
}
/* allocated bytes */
if (!kdf->allocate_bytes(kdf, vector->out.len, &out))
{
goto failure;
}
if (!chunk_equals(out, vector->out))
{
goto failure;
}
/* allocate without knowing the length */
if (kdf_has_fixed_output_length(alg))
{
chunk_free(&out);
if (!kdf->allocate_bytes(kdf, 0, &out))
{
goto failure;
}
if (!chunk_equals(out, vector->out))
{
goto failure;
}
}
/* bytes to existing buffer */
memset(out.ptr, 0, out.len);
if (!kdf->get_bytes(kdf, out.len, out.ptr))
{
goto failure;
}
if (!chunk_equals(out, vector->out))
{
goto failure;
}
failed = FALSE;
failure:
kdf->destroy(kdf);
chunk_free(&out);
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
key_derivation_function_names, alg, plugin_name,
get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? "disabled" : "enabled ",
key_derivation_function_names, alg, plugin_name);
return !this->required;
}
tested -= construction_failed;
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: unable to apply any available test vectors",
this->required ? "disabled" : "enabled ",
key_derivation_function_names, alg, plugin_name);
return !this->required;
}
if (!failed)
{
if (speed)
{
DBG2(DBG_LIB, "benchmarking for %N is currently not supported",
key_derivation_function_names, alg);
}
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
key_derivation_function_names, alg, plugin_name, tested);
}
return !failed;
}
/**
* Benchmark a DRBG
*/
static u_int bench_drbg(private_crypto_tester_t *this,
drbg_type_t type, drbg_constructor_t create)
{
drbg_t *drbg;
rng_t *entropy;
uint32_t strength = 128;
chunk_t seed = chunk_alloca(48);
memset(seed.ptr, 0x81, seed.len);
entropy = rng_tester_create(seed);
drbg = create(type, strength, entropy, chunk_empty);
if (drbg)
{
struct timespec start;
u_int runs = 0;
size_t out_len = 128;
char out_buf[out_len];
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
if (drbg->generate(drbg, out_len, out_buf))
{
runs++;
}
}
drbg->destroy(drbg);
return runs;
}
return 0;
}
METHOD(crypto_tester_t, test_drbg, bool,
private_crypto_tester_t *this, drbg_type_t type,
drbg_constructor_t create, u_int *speed, const char *plugin_name)
{
enumerator_t *enumerator;
drbg_test_vector_t *vector;
bool failed = FALSE;
u_int tested = 0;
enumerator = this->drbg->create_enumerator(this->drbg);
while (enumerator->enumerate(enumerator, &vector))
{
drbg_t *drbg;
rng_t *entropy;
chunk_t out = chunk_empty;
if (vector->type != type)
{
continue;
}
tested++;
failed = TRUE;
entropy = rng_tester_create(vector->entropy);
out = chunk_alloc(vector->out.len);
drbg = create(type, vector->strength, entropy,
vector->personalization_str);
if (!drbg)
{
DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
drbg_type_names, type, plugin_name);
entropy->destroy(entropy);
chunk_free(&out);
break;
}
if (!drbg->reseed(drbg))
{
goto failure;
}
if (!drbg->generate(drbg, out.len, out.ptr))
{
goto failure;
}
if (!drbg->generate(drbg, out.len, out.ptr))
{
goto failure;
}
if (!chunk_equals(out, vector->out))
{
goto failure;
}
failed = FALSE;
failure:
drbg->destroy(drbg);
chunk_free(&out);
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
drbg_type_names, type, plugin_name, get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? "disabled" : "enabled ",
drbg_type_names, type, plugin_name);
return !this->required;
}
if (!failed)
{
if (speed)
{
*speed = bench_drbg(this, type, create);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
drbg_type_names, type, plugin_name, tested, *speed);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
drbg_type_names, type, plugin_name, tested);
}
}
return !failed;
}
/**
* Benchmark a RNG
*/
static u_int bench_rng(private_crypto_tester_t *this,
rng_quality_t quality, rng_constructor_t create)
{
rng_t *rng;
rng = create(quality);
if (rng)
{
struct timespec start;
chunk_t buf;
u_int runs;
runs = 0;
buf = chunk_alloc(this->bench_size);
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
if (!rng->get_bytes(rng, buf.len, buf.ptr))
{
runs = 0;
break;
}
runs++;
}
free(buf.ptr);
rng->destroy(rng);
return runs;
}
return 0;
}
METHOD(crypto_tester_t, test_rng, bool,
private_crypto_tester_t *this, rng_quality_t quality,
rng_constructor_t create, u_int *speed, const char *plugin_name)
{
enumerator_t *enumerator;
rng_test_vector_t *vector;
bool failed = FALSE;
u_int tested = 0;
if (!this->rng_true && quality == RNG_TRUE)
{
DBG1(DBG_LIB, "enabled %N[%s]: skipping test (disabled by config)",
rng_quality_names, quality, plugin_name);
return TRUE;
}
enumerator = this->rng->create_enumerator(this->rng);
while (enumerator->enumerate(enumerator, &vector))
{
chunk_t data = chunk_empty;
rng_t *rng;
if (vector->quality != quality)
{
continue;
}
tested++;
failed = TRUE;
rng = create(quality);
if (!rng)
{
DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed",
rng_quality_names, quality, plugin_name);
break;
}
/* allocated bytes */
if (!rng->allocate_bytes(rng, vector->len, &data) ||
data.len != vector->len ||
!vector->test(vector->user, data))
{
goto failure;
}
/* write bytes into existing buffer */
memset(data.ptr, 0, data.len);
if (!rng->get_bytes(rng, vector->len, data.ptr))
{
goto failure;
}
if (!vector->test(vector->user, data))
{
goto failure;
}
failed = FALSE;
failure:
rng->destroy(rng);
chunk_free(&data);
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
rng_quality_names, quality, plugin_name, get_name(vector));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found",
this->required ? ", disabled" : "enabled ",
rng_quality_names, quality, plugin_name);
return !this->required;
}
if (!failed)
{
if (speed)
{
*speed = bench_rng(this, quality, create);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
rng_quality_names, quality, plugin_name, tested, *speed);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
rng_quality_names, quality, plugin_name, tested);
}
}
return !failed;
}
/**
* Benchmark a key exchange backend
*/
static u_int bench_ke(private_crypto_tester_t *this,
key_exchange_method_t method, ke_constructor_t create)
{
chunk_t a_pub = chunk_empty, b_pub = chunk_empty, shared = chunk_empty;
key_exchange_t *a, *b;
struct timespec start;
u_int runs;
runs = 0;
start_timing(&start);
while (end_timing(&start) < this->bench_time)
{
a = create(method);
b = create(method);
if (!a || !b)
{
DESTROY_IF(a);
DESTROY_IF(b);
return 0;
}
if (a->get_public_key(a, &a_pub) &&
b->set_public_key(b, a_pub) &&
b->get_public_key(b, &b_pub) &&
a->set_public_key(a, b_pub) &&
a->get_shared_secret(a, &shared))
{
runs++;
}
chunk_free(&a_pub);
chunk_free(&b_pub);
chunk_free(&shared);
a->destroy(a);
b->destroy(b);
}
return runs;
}
#ifdef TESTABLE_KE
static bool test_single_ke(key_exchange_method_t method, ke_test_vector_t *v,
ke_constructor_t create)
{
rng_t *entropy = NULL;
drbg_t *drbg = NULL;
key_exchange_t *a = NULL, *b = NULL;
chunk_t a_priv, b_priv, a_pub, b_pub, a_sec, b_sec;
bool success = FALSE;
a_pub = b_pub = a_sec = b_sec = chunk_empty;
a = create(method);
b = create(method);
if (!a || !b)
{
goto failure;
}
if (key_exchange_is_kem(method))
{
/* entropy instance will be owned by drbg */
entropy = rng_tester_create(v->seed);
drbg = lib->crypto->create_drbg(lib->crypto, DRBG_CTR_AES256, 256,
entropy, chunk_empty);
if (!drbg)
{
entropy->destroy(entropy);
goto failure;
}
if (!a->set_seed(a, chunk_empty, drbg) ||
!b->set_seed(b, chunk_empty, drbg))
{
goto failure;
}
}
else
{
/* the seed is the concatenation of both DH private keys */
a_priv = chunk_create(v->seed.ptr, v->seed.len/2);
b_priv = chunk_create(v->seed.ptr + v->seed.len/2, v->seed.len/2);
if (!a->set_seed(a, a_priv, NULL) || !b->set_seed(b, b_priv, NULL))
{
goto failure;
}
}
if (!a->get_public_key(a, &a_pub) || !chunk_equals(a_pub, v->pub_i))
{
goto failure;
}
if (!b->set_public_key(b, a_pub))
{
goto failure;
}
if (!b->get_shared_secret(b, &b_sec) || !chunk_equals(b_sec, v->shared))
{
goto failure;
}
if (!b->get_public_key(b, &b_pub) || !chunk_equals(b_pub, v->pub_r))
{
goto failure;
}
if (!a->set_public_key(a, b_pub))
{
goto failure;
}
if (!a->get_shared_secret(a, &a_sec) || !chunk_equals(a_sec, v->shared))
{
goto failure;
}
success = TRUE;
failure:
DESTROY_IF(a);
DESTROY_IF(b);
chunk_free(&a_pub);
chunk_free(&b_pub);
chunk_free(&a_sec);
chunk_free(&b_sec);
DESTROY_IF(drbg);
return success;
}
#else /* TESTABLE_KE */
static bool test_single_ke(key_exchange_method_t method, ke_constructor_t create)
{
key_exchange_t *a = NULL, *b = NULL;
chunk_t a_pub, b_pub, a_sec, b_sec;
bool success = FALSE;
a_pub = b_pub = a_sec = b_sec = chunk_empty;
a = create(method);
b = create(method);
if (!a || !b)
{
goto failure;
}
if (!a->get_public_key(a, &a_pub) ||
!b->set_public_key(b, a_pub) ||
!b->get_shared_secret(b, &b_sec) ||
!b->get_public_key(b, &b_pub) ||
chunk_equals(a_pub, b_pub) ||
!a->set_public_key(a, b_pub) ||
!a->get_shared_secret(a, &a_sec) ||
!chunk_equals(a_sec, b_sec))
{
goto failure;
}
success = TRUE;
failure:
DESTROY_IF(a);
DESTROY_IF(b);
chunk_free(&a_pub);
chunk_free(&b_pub);
chunk_free(&a_sec);
chunk_free(&b_sec);
return success;
}
#endif /* TESTABLE_KE */
METHOD(crypto_tester_t, test_ke, bool,
private_crypto_tester_t *this, key_exchange_method_t method,
ke_constructor_t create, u_int *speed, const char *plugin_name)
{
#ifdef TESTABLE_KE
enumerator_t *enumerator;
ke_test_vector_t *v;
bool success = TRUE;
u_int tested = 0;
enumerator = this->ke->create_enumerator(this->ke);
while (enumerator->enumerate(enumerator, &v))
{
if (v->method != method)
{
continue;
}
success = test_single_ke(method, v, create);
tested++;
if (!success)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
key_exchange_method_names, method, plugin_name, get_name(v));
break;
}
}
enumerator->destroy(enumerator);
if (!tested)
{
DBG1(DBG_LIB, "%s %N[%s]: no test vectors found / untestable",
this->required ? "disabled" : "enabled ",
key_exchange_method_names, method, plugin_name);
return !this->required;
}
if (success)
{
if (speed)
{
*speed = bench_ke(this, method, create);
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors, %d points",
key_exchange_method_names, method, plugin_name, tested, *speed);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed %u test vectors",
key_exchange_method_names, method, plugin_name, tested);
}
}
return success;
#else /* TESTABLE_KE */
if (method == MODP_CUSTOM)
{
DBG1(DBG_LIB, "enabled %N[%s]: untestable",
key_exchange_method_names, method, plugin_name);
return TRUE;
}
if (!test_single_ke(method, create))
{
DBG1(DBG_LIB, "disabled %N[%s]: failed basic test",
key_exchange_method_names, method, plugin_name);
return FALSE;
}
if (speed)
{
*speed = bench_ke(this, method, create);
DBG1(DBG_LIB, "enabled %N[%s]: passed basic test (vector tests "
"disabled), %d points", key_exchange_method_names, method,
plugin_name, *speed);
}
else
{
DBG1(DBG_LIB, "enabled %N[%s]: passed basic test (vector tests "
"disabled)", key_exchange_method_names, method, plugin_name);
}
return TRUE;
#endif /* TESTABLE_KE */
}
METHOD(crypto_tester_t, add_crypter_vector, void,
private_crypto_tester_t *this, crypter_test_vector_t *vector)
{
this->crypter->insert_last(this->crypter, vector);
}
METHOD(crypto_tester_t, add_aead_vector, void,
private_crypto_tester_t *this, aead_test_vector_t *vector)
{
this->aead->insert_last(this->aead, vector);
}
METHOD(crypto_tester_t, add_signer_vector, void,
private_crypto_tester_t *this, signer_test_vector_t *vector)
{
this->signer->insert_last(this->signer, vector);
}
METHOD(crypto_tester_t, add_hasher_vector, void,
private_crypto_tester_t *this, hasher_test_vector_t *vector)
{
this->hasher->insert_last(this->hasher, vector);
}
METHOD(crypto_tester_t, add_prf_vector, void,
private_crypto_tester_t *this, prf_test_vector_t *vector)
{
this->prf->insert_last(this->prf, vector);
}
METHOD(crypto_tester_t, add_xof_vector, void,
private_crypto_tester_t *this, xof_test_vector_t *vector)
{
this->xof->insert_last(this->xof, vector);
}
METHOD(crypto_tester_t, add_kdf_vector, void,
private_crypto_tester_t *this, kdf_test_vector_t *vector)
{
this->kdf->insert_last(this->kdf, vector);
}
METHOD(crypto_tester_t, add_drbg_vector, void,
private_crypto_tester_t *this, drbg_test_vector_t *vector)
{
this->drbg->insert_last(this->drbg, vector);
}
METHOD(crypto_tester_t, add_rng_vector, void,
private_crypto_tester_t *this, rng_test_vector_t *vector)
{
this->rng->insert_last(this->rng, vector);
}
METHOD(crypto_tester_t, add_ke_vector, void,
private_crypto_tester_t *this, ke_test_vector_t *vector)
{
this->ke->insert_last(this->ke, vector);
}
METHOD(crypto_tester_t, destroy, void,
private_crypto_tester_t *this)
{
this->crypter->destroy(this->crypter);
this->aead->destroy(this->aead);
this->signer->destroy(this->signer);
this->hasher->destroy(this->hasher);
this->prf->destroy(this->prf);
this->xof->destroy(this->xof);
this->kdf->destroy(this->kdf);
this->drbg->destroy(this->drbg);
this->rng->destroy(this->rng);
this->ke->destroy(this->ke);
free(this);
}
/**
* See header
*/
crypto_tester_t *crypto_tester_create()
{
private_crypto_tester_t *this;
INIT(this,
.public = {
.test_crypter = _test_crypter,
.test_aead = _test_aead,
.test_signer = _test_signer,
.test_hasher = _test_hasher,
.test_prf = _test_prf,
.test_xof = _test_xof,
.test_kdf = _test_kdf,
.test_drbg = _test_drbg,
.test_rng = _test_rng,
.test_ke = _test_ke,
.add_crypter_vector = _add_crypter_vector,
.add_aead_vector = _add_aead_vector,
.add_signer_vector = _add_signer_vector,
.add_hasher_vector = _add_hasher_vector,
.add_prf_vector = _add_prf_vector,
.add_xof_vector = _add_xof_vector,
.add_kdf_vector = _add_kdf_vector,
.add_drbg_vector = _add_drbg_vector,
.add_rng_vector = _add_rng_vector,
.add_ke_vector = _add_ke_vector,
.destroy = _destroy,
},
.crypter = linked_list_create(),
.aead = linked_list_create(),
.signer = linked_list_create(),
.hasher = linked_list_create(),
.prf = linked_list_create(),
.xof = linked_list_create(),
.kdf = linked_list_create(),
.drbg = linked_list_create(),
.rng = linked_list_create(),
.ke = linked_list_create(),
.required = lib->settings->get_bool(lib->settings,
"%s.crypto_test.required", FALSE, lib->ns),
.rng_true = lib->settings->get_bool(lib->settings,
"%s.crypto_test.rng_true", FALSE, lib->ns),
.bench_time = lib->settings->get_int(lib->settings,
"%s.crypto_test.bench_time", 50, lib->ns),
.bench_size = lib->settings->get_int(lib->settings,
"%s.crypto_test.bench_size", 1024, lib->ns),
);
/* enforce a block size of 16, should be fine for all algorithms */
this->bench_size = this->bench_size / 16 * 16;
return &this->public;
}