implemented a crypto_tester class to test crypto algorithms
authorMartin Willi <martin@strongswan.org>
Wed, 10 Jun 2009 09:22:02 +0000 (11:22 +0200)
committerMartin Willi <martin@strongswan.org>
Thu, 11 Jun 2009 13:54:44 +0000 (15:54 +0200)
libstrongswan.crypto.test.required to require at least one test vector to use an algorithm
libstrongswan.crypto.test.rng_true to run RNG tests on RNG_TRUE quality

src/libstrongswan/Makefile.am
src/libstrongswan/crypto/crypto_tester.c [new file with mode: 0644]
src/libstrongswan/crypto/crypto_tester.h [new file with mode: 0644]

index ca5f5e5..681434e 100644 (file)
@@ -28,6 +28,7 @@ crypto/rngs/rng.c crypto/rngs/rng.h \
 crypto/prf_plus.h crypto/prf_plus.c \
 crypto/signers/signer.c crypto/signers/signer.h \
 crypto/crypto_factory.c crypto/crypto_factory.h \
+crypto/crypto_tester.c crypto/crypto_tester.h \
 crypto/diffie_hellman.c crypto/diffie_hellman.h \
 crypto/transform.c crypto/transform.h \
 credentials/credential_factory.c credentials/credential_factory.h \
diff --git a/src/libstrongswan/crypto/crypto_tester.c b/src/libstrongswan/crypto/crypto_tester.c
new file mode 100644 (file)
index 0000000..4b81734
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+#include "crypto_tester.h"
+
+#include <debug.h>
+#include <utils/linked_list.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 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 RNG test vectors
+        */
+       linked_list_t *rng;
+       
+       /**
+        * Is a test vector required to pass a test?
+        */
+       bool required;
+       
+       /**
+        * should we run RNG_TRUE tests? Enough entropy?
+        */
+       bool rng_true;
+};
+
+/**
+ * Implementation of crypto_tester_t.test_crypter
+ */
+static bool test_crypter(private_crypto_tester_t *this,
+       encryption_algorithm_t alg, size_t key_size, crypter_constructor_t create)
+{
+       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, plain, cipher, iv;
+               
+               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;
+               }
+               
+               failed = FALSE;
+               tested++;
+               
+               key = chunk_create(vector->key, crypter->get_key_size(crypter));
+               crypter->set_key(crypter, key);
+               iv = chunk_create(vector->iv, crypter->get_block_size(crypter));
+               
+               /* allocated encryption */
+               plain = chunk_create(vector->plain, vector->len);
+               crypter->encrypt(crypter, plain, iv, &cipher);
+               if (!memeq(vector->cipher, cipher.ptr, cipher.len))
+               {
+                       failed = TRUE;
+               }
+               /* inline decryption */
+               crypter->decrypt(crypter, cipher, iv, NULL);
+               if (!memeq(vector->plain, cipher.ptr, cipher.len))
+               {
+                       failed = TRUE;
+               }
+               free(cipher.ptr);
+               /* allocated decryption */
+               cipher = chunk_create(vector->cipher, vector->len);
+               crypter->decrypt(crypter, cipher, iv, &plain);
+               if (!memeq(vector->plain, plain.ptr, plain.len))
+               {
+                       failed = TRUE;
+               }
+               /* inline encryption */
+               crypter->encrypt(crypter, plain, iv, NULL);
+               if (!memeq(vector->cipher, plain.ptr, plain.len))
+               {
+                       failed = TRUE;
+               }
+               free(plain.ptr);
+               
+               crypter->destroy(crypter);
+               if (failed)
+               {
+                       DBG1("test vector %d failed, %N disabled",
+                                tested, encryption_algorithm_names, alg);
+                       break;
+               }
+               DBG2("%N test vector %d successful",
+                        encryption_algorithm_names, alg, tested);
+       }
+       enumerator->destroy(enumerator);
+       if (!tested)
+       {
+               DBG1("no test vectors found for %N%s",
+                        encryption_algorithm_names, alg, 
+                        this->required ? ", disabled" : "");
+               return !this->required;
+       }
+       if (!failed)
+       {
+               DBG2("successfully tested %d test vectors for %N",
+                        tested, encryption_algorithm_names, alg);
+       }
+       return !failed;
+}
+
+/**
+ * Implementation of crypto_tester_t.test_signer
+ */
+static bool test_signer(private_crypto_tester_t *this,
+                                               integrity_algorithm_t alg, signer_constructor_t create)
+{
+       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;
+               
+               if (vector->alg != alg)
+               {
+                       continue;
+               }
+               
+               tested++;
+               signer = create(alg);
+               if (!signer)
+               {
+                       DBG1("creating instance failed, %N disabled",
+                                integrity_algorithm_names, alg);
+                       failed = TRUE;
+                       break;
+               }
+               
+               failed = FALSE;
+               
+               key = chunk_create(vector->key, signer->get_key_size(signer));
+               signer->set_key(signer, key);
+               
+               /* allocated signature */
+               data = chunk_create(vector->data, vector->len);
+               signer->allocate_signature(signer, data, &mac);
+               if (mac.len != signer->get_block_size(signer))
+               {
+                       failed = TRUE;
+               }
+               if (!memeq(vector->mac, mac.ptr, mac.len))
+               {
+                       failed = TRUE;
+               }
+               /* signature to existing buffer */
+               memset(mac.ptr, 0, mac.len);
+               signer->get_signature(signer, data, mac.ptr);
+               if (!memeq(vector->mac, mac.ptr, mac.len))
+               {
+                       failed = TRUE;
+               }
+               /* signature verification, good case */
+               if (!signer->verify_signature(signer, data, mac))
+               {
+                       failed = TRUE;
+               }
+               /* signature verification, bad case */
+               *(mac.ptr + mac.len - 1) += 1;
+               if (signer->verify_signature(signer, data, mac))
+               {
+                       failed = TRUE;
+               }
+               /* signature to existing buffer, using append mode */
+               if (data.len > 2)
+               {
+                       memset(mac.ptr, 0, mac.len);
+                       signer->allocate_signature(signer, chunk_create(data.ptr, 1), NULL);
+                       signer->get_signature(signer, chunk_create(data.ptr + 1, 1), NULL);
+                       signer->get_signature(signer, chunk_skip(data, 2), mac.ptr);
+                       if (!memeq(vector->mac, mac.ptr, mac.len))
+                       {
+                               failed = TRUE;
+                       }
+               }
+               free(mac.ptr);
+               
+               signer->destroy(signer);
+               if (failed)
+               {
+                       DBG1("test vector %d failed, %N disabled",
+                                tested, integrity_algorithm_names, alg);
+                       break;
+               }
+               DBG2(" %N test vector %d successful",
+                        integrity_algorithm_names, alg, tested);
+       }
+       enumerator->destroy(enumerator);
+       if (!tested)
+       {
+               DBG1("no test vectors found for %N%s",
+                        integrity_algorithm_names, alg, 
+                        this->required ? ", disabled" : "");
+               return !this->required;
+       }
+       if (!failed)
+       {
+               DBG2("successfully tested %d test vectors for %N",
+                        tested, integrity_algorithm_names, alg);
+       }
+       return !failed;
+}
+
+/**
+ * Implementation of hasher_t.test_hasher
+ */
+static bool test_hasher(private_crypto_tester_t *this, hash_algorithm_t alg,
+                                               hasher_constructor_t create)
+{
+       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++;
+               hasher = create(alg);
+               if (!hasher)
+               {
+                       DBG1("creating instance failed, %N disabled",
+                                hash_algorithm_names, alg);
+                       failed = TRUE;
+                       break;
+               }
+               
+               failed = FALSE;
+               
+               /* allocated hash */
+               data = chunk_create(vector->data, vector->len);
+               hasher->allocate_hash(hasher, data, &hash);
+               if (hash.len != hasher->get_hash_size(hasher))
+               {
+                       failed = TRUE;
+               }
+               if (!memeq(vector->hash, hash.ptr, hash.len))
+               {
+                       failed = TRUE;
+               }
+               /* hash to existing buffer */
+               memset(hash.ptr, 0, hash.len);
+               hasher->get_hash(hasher, data, hash.ptr);
+               if (!memeq(vector->hash, hash.ptr, hash.len))
+               {
+                       failed = TRUE;
+               }
+               /* hasher to existing buffer, using append mode */
+               if (data.len > 2)
+               {
+                       memset(hash.ptr, 0, hash.len);
+                       hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL);
+                       hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL);
+                       hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr);
+                       if (!memeq(vector->hash, hash.ptr, hash.len))
+                       {
+                               failed = TRUE;
+                       }
+               }
+               free(hash.ptr);
+               
+               hasher->destroy(hasher);
+               if (failed)
+               {
+                       DBG1("test vector %d failed, %N disabled",
+                                tested, hash_algorithm_names, alg);
+                       break;
+               }
+               DBG2("%N test vector %d successful",
+                        hash_algorithm_names, alg, tested);
+       }
+       enumerator->destroy(enumerator);
+       if (!tested)
+       {
+               DBG1("no test vectors found for %N%s",
+                        hash_algorithm_names, alg, 
+                        this->required ? ", disabled" : "");
+               return !this->required;
+       }
+       if (!failed)
+       {
+               DBG2("successfully tested %d test vectors for %N",
+                        tested, hash_algorithm_names, alg);
+       }
+       return !failed;
+}
+
+/**
+ * Implementation of crypto_tester_t.test_prf
+ */
+static bool test_prf(private_crypto_tester_t *this,
+                                        pseudo_random_function_t alg, prf_constructor_t create)
+{
+       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;
+               
+               if (vector->alg != alg)
+               {
+                       continue;
+               }
+               
+               tested++;
+               prf = create(alg);
+               if (!prf)
+               {
+                       DBG1("creating instance failed, %N disabled",
+                                pseudo_random_function_names, alg);
+                       failed = TRUE;
+                       break;
+               }
+               
+               failed = FALSE;
+               
+               key = chunk_create(vector->key, vector->key_size);
+               prf->set_key(prf, key);
+               
+               /* allocated bytes */
+               seed = chunk_create(vector->seed, vector->len);
+               prf->allocate_bytes(prf, seed, &out);
+               if (out.len != prf->get_block_size(prf))
+               {
+                       failed = TRUE;
+               }
+               if (!memeq(vector->out, out.ptr, out.len))
+               {
+                       failed = TRUE;
+               }
+               /* bytes to existing buffer */
+               memset(out.ptr, 0, out.len);
+               prf->get_bytes(prf, seed, out.ptr);
+               if (!memeq(vector->out, out.ptr, out.len))
+               {
+                       failed = TRUE;
+               }
+               /* bytes to existing buffer, using append mode */
+               if (seed.len > 2)
+               {
+                       memset(out.ptr, 0, out.len);
+                       prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL);
+                       prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL);
+                       prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr);
+                       if (!memeq(vector->out, out.ptr, out.len))
+                       {
+                               failed = TRUE;
+                       }
+               }
+               free(out.ptr);
+               
+               prf->destroy(prf);
+               if (failed)
+               {
+                       DBG1("test vector %d failed, %N disabled",
+                                tested, pseudo_random_function_names, alg);
+                       break;
+               }
+               DBG2("%N test vector %d successful",
+                        pseudo_random_function_names, alg, tested);
+       }
+       enumerator->destroy(enumerator);
+       if (!tested)
+       {
+               DBG1("no test vectors found for %N%s",
+                        pseudo_random_function_names, alg, 
+                        this->required ? ", disabled" : "");
+               return !this->required;
+       }
+       if (!failed)
+       {
+               DBG2("successfully tested %d testvectors for %N",
+                        tested, pseudo_random_function_names, alg);
+       }
+       return !failed;
+}
+
+/**
+ * Implementation of crypto_tester_t.test_rng
+ */
+static bool test_rng(private_crypto_tester_t *this, rng_quality_t quality,
+                                        rng_constructor_t create)
+{
+       enumerator_t *enumerator;
+       rng_test_vector_t *vector;
+       bool failed = FALSE;
+       u_int tested = 0;
+       
+       if (!this->rng_true && quality == RNG_TRUE)
+       {
+               DBG1("skipping %N test, disabled by config", rng_quality_names, quality);
+               return TRUE;
+       }
+       
+       enumerator = this->rng->create_enumerator(this->rng);
+       while (enumerator->enumerate(enumerator, &vector))
+       {
+               rng_t *rng;
+               chunk_t data;
+               
+               if (vector->quality != quality)
+               {
+                       continue;
+               }
+               
+               tested++;
+               rng = create(quality);
+               if (!rng)
+               {
+                       DBG1("creating instance failed, %N disabled",
+                                rng_quality_names, quality);
+                       failed = TRUE;
+                       break;
+               }
+               
+               failed = FALSE;
+               
+               /* allocated bytes */
+               rng->allocate_bytes(rng, vector->len, &data);
+               if (data.len != vector->len)
+               {
+                       failed = TRUE;
+               }
+               if (!vector->test(vector->user, data))
+               {
+                       failed = TRUE;
+               }
+               /* bytes to existing buffer */
+               memset(data.ptr, 0, data.len);
+               rng->get_bytes(rng, vector->len, data.ptr);
+               if (!vector->test(vector->user, data))
+               {
+                       failed = TRUE;
+               }
+               free(data.ptr);
+               
+               rng->destroy(rng);
+               if (failed)
+               {
+                       DBG1("test vector %d failed, %N disabled",
+                                tested, rng_quality_names, quality);
+                       break;
+               }
+               DBG2("%N test vector %d successful", rng_quality_names, quality, tested);
+       }
+       enumerator->destroy(enumerator);
+       if (!tested)
+       {
+               DBG1("no test vectors found for %N%s",
+                        rng_quality_names, quality, this->required ? ", disabled" : "");
+               return !this->required;
+       }
+       if (!failed)
+       {
+               DBG2("successfully tested %d testvectors for %N",
+                        tested, rng_quality_names, quality);
+       }
+       return !failed;
+}
+
+/**
+ * Implementation of crypter_tester_t.add_crypter_vector
+ */
+static void add_crypter_vector(private_crypto_tester_t *this,
+                                                          crypter_test_vector_t *vector)
+{
+       this->crypter->insert_last(this->crypter, vector);
+}
+
+/**
+ * Implementation of crypter_tester_t.add_signer_vector
+ */
+static void add_signer_vector(private_crypto_tester_t *this,
+                                                         signer_test_vector_t *vector)
+{
+       this->signer->insert_last(this->signer, vector);
+}
+
+/**
+ * Implementation of crypter_tester_t.add_hasher_vector
+ */
+static void add_hasher_vector(private_crypto_tester_t *this,
+                                                         hasher_test_vector_t *vector)
+{
+       this->hasher->insert_last(this->hasher, vector);
+}
+
+/**
+ * Implementation of crypter_tester_t.add_prf_vector
+ */
+static void add_prf_vector(private_crypto_tester_t *this,
+                                                  prf_test_vector_t *vector)
+{
+       this->prf->insert_last(this->prf, vector);
+}
+
+/**
+ * Implementation of crypter_tester_t.add_rng_vector
+ */
+static void add_rng_vector(private_crypto_tester_t *this,
+                                                  rng_test_vector_t *vector)
+{
+       this->rng->insert_last(this->rng, vector);
+}
+
+/**
+ * Implementation of crypto_tester_t.destroy.
+ */
+static void destroy(private_crypto_tester_t *this)
+{
+       this->crypter->destroy(this->crypter);
+       this->signer->destroy(this->signer);
+       this->hasher->destroy(this->hasher);
+       this->prf->destroy(this->prf);
+       this->rng->destroy(this->rng);
+       free(this);
+}
+
+/**
+ * See header
+ */
+crypto_tester_t *crypto_tester_create()
+{
+       private_crypto_tester_t *this = malloc_thing(private_crypto_tester_t);
+       
+       this->public.test_crypter = (bool(*)(crypto_tester_t*, encryption_algorithm_t alg,size_t key_size, crypter_constructor_t create))test_crypter;
+       this->public.test_signer = (bool(*)(crypto_tester_t*, integrity_algorithm_t alg, signer_constructor_t create))test_signer;
+       this->public.test_hasher = (bool(*)(crypto_tester_t*, hash_algorithm_t alg, hasher_constructor_t create))test_hasher;
+       this->public.test_prf = (bool(*)(crypto_tester_t*, pseudo_random_function_t alg, prf_constructor_t create))test_prf;
+       this->public.test_rng = (bool(*)(crypto_tester_t*, rng_quality_t quality, rng_constructor_t create))test_rng;
+       this->public.add_crypter_vector = (void(*)(crypto_tester_t*, crypter_test_vector_t *vector))add_crypter_vector;
+       this->public.add_signer_vector = (void(*)(crypto_tester_t*, signer_test_vector_t *vector))add_signer_vector;
+       this->public.add_hasher_vector = (void(*)(crypto_tester_t*, hasher_test_vector_t *vector))add_hasher_vector;
+       this->public.add_prf_vector = (void(*)(crypto_tester_t*, prf_test_vector_t *vector))add_prf_vector;
+       this->public.add_rng_vector = (void(*)(crypto_tester_t*, rng_test_vector_t *vector))add_rng_vector;
+       this->public.destroy = (void(*)(crypto_tester_t*))destroy;
+       
+       this->crypter = linked_list_create();
+       this->signer = linked_list_create();
+       this->hasher = linked_list_create();
+       this->prf = linked_list_create();
+       this->rng = linked_list_create();
+       
+       this->required = lib->settings->get_bool(lib->settings,
+                                                               "libstrongswan.crypto.test.required", FALSE);
+       this->rng_true = lib->settings->get_bool(lib->settings,
+                                                               "libstrongswan.crypto.test.rng_true", FALSE);
+       
+       return &this->public;
+}
+
diff --git a/src/libstrongswan/crypto/crypto_tester.h b/src/libstrongswan/crypto/crypto_tester.h
new file mode 100644 (file)
index 0000000..5a97261
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup crypto_tester crypto_tester
+ * @{ @ingroup crypto
+ */
+
+#ifndef CRYPTO_TESTER_H_
+#define CRYPTO_TESTER_H_
+
+typedef struct crypto_tester_t crypto_tester_t;
+
+#include <crypto/crypto_factory.h>
+
+typedef struct crypter_test_vector_t crypter_test_vector_t;
+typedef struct signer_test_vector_t signer_test_vector_t;
+typedef struct hasher_test_vector_t hasher_test_vector_t;
+typedef struct prf_test_vector_t prf_test_vector_t;
+typedef struct rng_test_vector_t rng_test_vector_t;
+
+struct crypter_test_vector_t {
+       /** encryption algorithm this vector tests */
+       encryption_algorithm_t alg;
+       /** key length to use, in bytes */
+       size_t key_size;
+       /** encryption key of test vector */
+       u_char *key;
+       /** initialization vector, using crypters blocksize bytes */
+       u_char *iv;
+       /** length of plain and cipher text */
+       size_t len;
+       /** plain text */
+       u_char *plain;
+       /** cipher text */
+       u_char *cipher;
+};
+
+struct signer_test_vector_t {
+       /** signer algorithm this test vector tests */
+       pseudo_random_function_t alg;
+       /** key to use, with a length the algorithm expects */
+       u_char *key;
+       /** size of the input data */
+       size_t len;
+       /** input data */
+       u_char *data;
+       /** expected output, with ouput size of the tested algorithm */
+       u_char *mac;
+};
+
+struct hasher_test_vector_t {
+       /** hash algorithm this test vector tests */
+       hash_algorithm_t alg;
+       /** length of the input data */
+       size_t len;
+       /** input data */
+       u_char *data;
+       /** expected hash, with hash size of the tested algorithm */
+       u_char *hash;
+};
+
+struct prf_test_vector_t {
+       /** prf algorithm this test vector tests */
+       pseudo_random_function_t alg;
+       /** key length to use, in bytes */
+       size_t key_size;
+       /** key to use */
+       u_char *key;
+       /** size of the seed data */
+       size_t len;
+       /** seed data */
+       u_char *seed;
+       /** expected output, with block size of the tested algorithm */
+       u_char *out;
+};
+
+/**
+ * Test vector for a RNG.
+ *
+ * Contains a callback function to analyze the output of a RNG,
+ */
+struct rng_test_vector_t {
+       /** quality of random data this test vector tests */
+       rng_quality_t quality;
+       /** callback function to test RNG output, returns TRUE if data ok */
+       bool (*test)(void *user, chunk_t data);
+       /** number of bytes the function requests */
+       size_t len;
+       /** user data passed back to the test() function on invocation */
+       void *user;
+};
+
+/**
+ * Cryptographic primitive testing framework.
+ */
+struct crypto_tester_t {
+       
+       /**
+        * Test a crypter algorithm, optionally using a specified key size.
+        *
+        * @param alg                   algorithm to test
+        * @param key_size              key size to test, 0 for all 
+        * @param create                constructor function for the crypter
+        * @return                              TRUE if test passed
+        */
+       bool (*test_crypter)(crypto_tester_t *this, encryption_algorithm_t alg,
+                                                size_t key_size, crypter_constructor_t create);
+       /**
+        * Test a signer algorithm.
+        *
+        * @param alg                   algorithm to test
+        * @param create                constructor function for the signer
+        * @return                              TRUE if test passed
+        */
+       bool (*test_signer)(crypto_tester_t *this, integrity_algorithm_t alg,
+                                               signer_constructor_t create);
+       /**
+        * Test a hasher algorithm.
+        *
+        * @param alg                   algorithm to test
+        * @param create                constructor function for the hasher
+        * @return                              TRUE if test passed
+        */
+       bool (*test_hasher)(crypto_tester_t *this, hash_algorithm_t alg,
+                                               hasher_constructor_t create);
+       /**
+        * Test a PRF algorithm.
+        *
+        * @param alg                   algorithm to test
+        * @param create                constructor function for the PRF
+        * @return                              TRUE if test passed
+        */
+       bool (*test_prf)(crypto_tester_t *this, pseudo_random_function_t alg,
+                                        prf_constructor_t create);
+       /**
+        * Test a RNG implementation.
+        *
+        * @param alg                   algorithm to test
+        * @param create                constructor function for the RNG
+        * @return                              TRUE if test passed
+        */
+       bool (*test_rng)(crypto_tester_t *this, rng_quality_t quality,
+                                        rng_constructor_t create);
+       /**
+        * Add a test vector to test a crypter.
+        *
+        * @param vector                pointer to test vector
+        */
+       void (*add_crypter_vector)(crypto_tester_t *this,
+                                                          crypter_test_vector_t *vector);
+       /**
+        * Add a test vector to test a signer.
+        *
+        * @param vector                pointer to test vector
+        */
+       void (*add_signer_vector)(crypto_tester_t *this,
+                                                         signer_test_vector_t *vector);
+       /**
+        * Add a test vector to test a hasher.
+        *
+        * @param vector                pointer to test vector
+        */
+       void (*add_hasher_vector)(crypto_tester_t *this,
+                                                         hasher_test_vector_t *vector);
+       /**
+        * Add a test vector to test a PRF.
+        *
+        * @param vector                pointer to test vector
+        */
+       void (*add_prf_vector)(crypto_tester_t *this, prf_test_vector_t *vector);
+       
+       /**
+        * Add a test vector to test a RNG.
+        *
+        * @param vector                pointer to test vector
+        */
+       void (*add_rng_vector)(crypto_tester_t *this, rng_test_vector_t *vector);
+       
+       /**
+        * Destroy a crypto_tester_t.
+        */
+       void (*destroy)(crypto_tester_t *this);
+};
+
+/**
+ * Create a crypto_tester instance.
+ */
+crypto_tester_t *crypto_tester_create();
+
+#endif /* CRYPTO_TESTER_ @}*/