Added AEAD support to crypto tester
authorMartin Willi <martin@revosec.ch>
Wed, 18 Aug 2010 18:15:18 +0000 (20:15 +0200)
committerMartin Willi <martin@revosec.ch>
Thu, 19 Aug 2010 17:02:33 +0000 (19:02 +0200)
src/libstrongswan/crypto/crypto_tester.c
src/libstrongswan/crypto/crypto_tester.h

index a5434cf..7970383 100644 (file)
@@ -41,6 +41,11 @@ struct private_crypto_tester_t {
        linked_list_t *crypter;
 
        /**
+        * List of aead test vectors
+        */
+       linked_list_t *aead;
+
+       /**
         * List of signer test vectors
         */
        linked_list_t *signer;
@@ -256,6 +261,162 @@ METHOD(crypto_tester_t, test_crypter, bool,
 }
 
 /**
+ * Benchmark an aead transform
+ */
+static u_int bench_aead(private_crypto_tester_t *this,
+       encryption_algorithm_t alg, aead_constructor_t create)
+{
+       aead_t *aead;
+
+       aead = create(alg, 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));
+               aead->set_key(aead, chunk_from_thing(key));
+               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)
+               {
+                       aead->encrypt(aead, buf, chunk_from_thing(assoc),
+                                                 chunk_from_thing(iv), NULL);
+                       aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv),
+                                                 chunk_from_thing(assoc), chunk_from_thing(iv), NULL);
+                       runs++;
+               }
+               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,
+       aead_constructor_t create, u_int *speed)
+{
+       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, plain, cipher, iv, assoc;
+               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;
+               }
+               aead = create(alg, vector->key_size);
+               if (!aead)
+               {       /* key size not supported... */
+                       continue;
+               }
+
+               failed = FALSE;
+               tested++;
+
+               key = chunk_create(vector->key, aead->get_key_size(aead));
+               aead->set_key(aead, key);
+               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);
+               aead->encrypt(aead, plain, assoc, iv, &cipher);
+               if (!memeq(vector->cipher, cipher.ptr, cipher.len))
+               {
+                       failed = TRUE;
+               }
+               /* inline decryption */
+               if (!aead->decrypt(aead, cipher, assoc, iv, NULL))
+               {
+                       failed = TRUE;
+               }
+               if (!memeq(vector->plain, cipher.ptr, cipher.len - icv))
+               {
+                       failed = TRUE;
+               }
+               free(cipher.ptr);
+               /* allocated decryption */
+               cipher = chunk_create(vector->cipher, vector->len + icv);
+               if (!aead->decrypt(aead, cipher, assoc, iv, &plain))
+               {
+                       plain = chunk_empty;
+                       failed = TRUE;
+               }
+               else if (!memeq(vector->plain, plain.ptr, plain.len))
+               {
+                       failed = TRUE;
+               }
+               plain.ptr = realloc(plain.ptr, plain.len + icv);
+               /* inline encryption */
+               aead->encrypt(aead, plain, assoc, iv, NULL);
+               if (!memeq(vector->cipher, plain.ptr, plain.len + icv))
+               {
+                       failed = TRUE;
+               }
+               free(plain.ptr);
+
+               aead->destroy(aead);
+               if (failed)
+               {
+                       DBG1(DBG_LIB, "disabled %N: %s test vector failed",
+                                encryption_algorithm_names, alg, get_name(vector));
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       if (!tested)
+       {
+               DBG1(DBG_LIB, "%s %N: no test vectors found",
+                        this->required ? "disabled" : "enabled ",
+                        encryption_algorithm_names, alg);
+               return !this->required;
+       }
+       if (!failed)
+       {
+               if (speed)
+               {
+                       *speed = bench_aead(this, alg, create);
+                       DBG1(DBG_LIB, "enabled  %N: passed %u test vectors, %d points",
+                                encryption_algorithm_names, alg, tested, *speed);
+               }
+               else
+               {
+                       DBG1(DBG_LIB, "enabled  %N: passed %u test vectors",
+                                encryption_algorithm_names, alg, tested);
+               }
+       }
+       return !failed;
+}
+
+/**
  * Benchmark a signer
  */
 static u_int bench_signer(private_crypto_tester_t *this,
@@ -805,6 +966,12 @@ METHOD(crypto_tester_t, add_crypter_vector, void,
        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)
 {
@@ -833,6 +1000,7 @@ 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);
@@ -850,11 +1018,13 @@ crypto_tester_t *crypto_tester_create()
        INIT(this,
                .public = {
                        .test_crypter = _test_crypter,
+                       .test_aead = _test_aead,
                        .test_signer = _test_signer,
                        .test_hasher = _test_hasher,
                        .test_prf = _test_prf,
                        .test_rng = _test_rng,
                        .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,
@@ -862,6 +1032,7 @@ crypto_tester_t *crypto_tester_create()
                        .destroy = _destroy,
                },
                .crypter = linked_list_create(),
+               .aead = linked_list_create(),
                .signer = linked_list_create(),
                .hasher = linked_list_create(),
                .prf = linked_list_create(),
index a670931..cef0b3c 100644 (file)
@@ -26,6 +26,7 @@ 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 aead_test_vector_t aead_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;
@@ -48,6 +49,27 @@ struct crypter_test_vector_t {
        u_char *cipher;
 };
 
+struct aead_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 associated data */
+       size_t alen;
+       /** associated data */
+       u_char *adata;
+       /** length of plain 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;
@@ -114,7 +136,7 @@ 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 key_size              key size to test, 0 for default
         * @param create                constructor function for the crypter
         * @param speed                 speed test result, NULL to omit
         * @return                              TRUE if test passed
@@ -122,6 +144,19 @@ struct crypto_tester_t {
        bool (*test_crypter)(crypto_tester_t *this, encryption_algorithm_t alg,
                                                 size_t key_size, crypter_constructor_t create,
                                                 u_int *speed);
+
+       /**
+        * Test an aead algorithm, optionally using a specified key size.
+        *
+        * @param alg                   algorithm to test
+        * @param key_size              key size to test, 0 for default
+        * @param create                constructor function for the aead transform
+        * @param speed                 speed test result, NULL to omit
+        * @return                              TRUE if test passed
+        */
+       bool (*test_aead)(crypto_tester_t *this, encryption_algorithm_t alg,
+                                                size_t key_size, aead_constructor_t create,
+                                                u_int *speed);
        /**
         * Test a signer algorithm.
         *
@@ -170,6 +205,13 @@ struct crypto_tester_t {
        void (*add_crypter_vector)(crypto_tester_t *this,
                                                           crypter_test_vector_t *vector);
        /**
+        * Add a test vector to test an aead transform.
+        *
+        * @param vector                pointer to test vector
+        */
+       void (*add_aead_vector)(crypto_tester_t *this,
+                                                       aead_test_vector_t *vector);
+       /**
         * Add a test vector to test a signer.
         *
         * @param vector                pointer to test vector