diff options
-rw-r--r-- | src/libstrongswan/crypto/crypto_factory.c | 141 | ||||
-rw-r--r-- | src/libstrongswan/crypto/crypto_tester.c | 294 | ||||
-rw-r--r-- | src/libstrongswan/crypto/crypto_tester.h | 16 |
3 files changed, 377 insertions, 74 deletions
diff --git a/src/libstrongswan/crypto/crypto_factory.c b/src/libstrongswan/crypto/crypto_factory.c index 200fbbfbd..8089a1e7a 100644 --- a/src/libstrongswan/crypto/crypto_factory.c +++ b/src/libstrongswan/crypto/crypto_factory.c @@ -22,8 +22,10 @@ typedef struct entry_t entry_t; struct entry_t { - /** algorithm */ + /* algorithm */ u_int algo; + /* benchmarked speed */ + u_int speed; /* constructor */ union { crypter_constructor_t create_crypter; @@ -32,6 +34,7 @@ struct entry_t { prf_constructor_t create_prf; rng_constructor_t create_rng; dh_constructor_t create_dh; + void *create; }; }; @@ -93,6 +96,11 @@ struct private_crypto_factory_t { bool test_on_create; /** + * run algorithm benchmark during registration + */ + bool bench; + + /** * rwlock to lock access to modules */ rwlock_t *lock; @@ -114,7 +122,7 @@ METHOD(crypto_factory_t, create_crypter, crypter_t*, { if (this->test_on_create && !this->tester->test_crypter(this->tester, algo, key_size, - entry->create_crypter)) + entry->create_crypter, NULL)) { continue; } @@ -145,7 +153,7 @@ METHOD(crypto_factory_t, create_signer, signer_t*, { if (this->test_on_create && !this->tester->test_signer(this->tester, algo, - entry->create_signer)) + entry->create_signer, NULL)) { continue; } @@ -177,7 +185,7 @@ METHOD(crypto_factory_t, create_hasher, hasher_t*, { if (this->test_on_create && algo != HASH_PREFERRED && !this->tester->test_hasher(this->tester, algo, - entry->create_hasher)) + entry->create_hasher, NULL)) { continue; } @@ -207,7 +215,8 @@ METHOD(crypto_factory_t, create_prf, prf_t*, if (entry->algo == algo) { if (this->test_on_create && - !this->tester->test_prf(this->tester, algo, entry->create_prf)) + !this->tester->test_prf(this->tester, algo, + entry->create_prf, NULL)) { continue; } @@ -238,7 +247,8 @@ METHOD(crypto_factory_t, create_rng, rng_t*, if (entry->algo >= quality && diff > entry->algo - quality) { if (this->test_on_create && - !this->tester->test_rng(this->tester, quality, entry->create_rng)) + !this->tester->test_rng(this->tester, quality, + entry->create_rng, NULL)) { continue; } @@ -284,20 +294,61 @@ METHOD(crypto_factory_t, create_dh, diffie_hellman_t*, return diffie_hellman; } +/** + * Insert an algorithm entry to a list + */ +static void add_entry(private_crypto_factory_t *this, linked_list_t *list, + int algo, u_int speed, void *create) +{ + entry_t *entry, *current; + linked_list_t *tmp; + bool inserted = FALSE; + + INIT(entry, + .algo = algo, + .speed = speed, + ); + entry->create = create; + + this->lock->write_lock(this->lock); + if (speed) + { /* insert sorted by speed using a temporary list */ + tmp = linked_list_create(); + while (list->remove_first(list, (void**)¤t) == SUCCESS) + { + tmp->insert_last(tmp, current); + } + while (tmp->remove_first(tmp, (void**)¤t) == SUCCESS) + { + if (!inserted && + current->algo == algo && + current->speed < speed) + { + list->insert_last(list, entry); + inserted = TRUE; + } + list->insert_last(list, current); + } + tmp->destroy(tmp); + } + if (!inserted) + { + list->insert_last(list, entry); + } + this->lock->unlock(this->lock); +} + METHOD(crypto_factory_t, add_crypter, void, private_crypto_factory_t *this, encryption_algorithm_t algo, crypter_constructor_t create) { + u_int speed = 0; + if (!this->test_on_add || - this->tester->test_crypter(this->tester, algo, 0, create)) + this->tester->test_crypter(this->tester, algo, 0, create, + this->bench ? &speed : NULL)) { - entry_t *entry = malloc_thing(entry_t); - - entry->algo = algo; - entry->create_crypter = create; - this->lock->write_lock(this->lock); - this->crypters->insert_last(this->crypters, entry); - this->lock->unlock(this->lock); + add_entry(this, this->crypters, algo, speed, create); } } @@ -325,16 +376,13 @@ METHOD(crypto_factory_t, add_signer, void, private_crypto_factory_t *this, integrity_algorithm_t algo, signer_constructor_t create) { + u_int speed = 0; + if (!this->test_on_add || - this->tester->test_signer(this->tester, algo, create)) + this->tester->test_signer(this->tester, algo, create, + this->bench ? &speed : NULL)) { - entry_t *entry = malloc_thing(entry_t); - - entry->algo = algo; - entry->create_signer = create; - this->lock->write_lock(this->lock); - this->signers->insert_last(this->signers, entry); - this->lock->unlock(this->lock); + add_entry(this, this->signers, algo, speed, create); } } @@ -362,16 +410,13 @@ METHOD(crypto_factory_t, add_hasher, void, private_crypto_factory_t *this, hash_algorithm_t algo, hasher_constructor_t create) { + u_int speed = 0; + if (!this->test_on_add || - this->tester->test_hasher(this->tester, algo, create)) + this->tester->test_hasher(this->tester, algo, create, + this->bench ? &speed : NULL)) { - entry_t *entry = malloc_thing(entry_t); - - entry->algo = algo; - entry->create_hasher = create; - this->lock->write_lock(this->lock); - this->hashers->insert_last(this->hashers, entry); - this->lock->unlock(this->lock); + add_entry(this, this->hashers, algo, speed, create); } } @@ -399,16 +444,13 @@ METHOD(crypto_factory_t, add_prf, void, private_crypto_factory_t *this, pseudo_random_function_t algo, prf_constructor_t create) { + u_int speed = 0; + if (!this->test_on_add || - this->tester->test_prf(this->tester, algo, create)) + this->tester->test_prf(this->tester, algo, create, + this->bench ? &speed : NULL)) { - entry_t *entry = malloc_thing(entry_t); - - entry->algo = algo; - entry->create_prf = create; - this->lock->write_lock(this->lock); - this->prfs->insert_last(this->prfs, entry); - this->lock->unlock(this->lock); + add_entry(this, this->prfs, algo, speed, create); } } @@ -436,16 +478,13 @@ METHOD(crypto_factory_t, add_rng, void, private_crypto_factory_t *this, rng_quality_t quality, rng_constructor_t create) { + u_int speed = 0; + if (!this->test_on_add || - this->tester->test_rng(this->tester, quality, create)) + this->tester->test_rng(this->tester, quality, create, + this->bench ? &speed : NULL)) { - entry_t *entry = malloc_thing(entry_t); - - entry->algo = quality; - entry->create_rng = create; - this->lock->write_lock(this->lock); - this->rngs->insert_last(this->rngs, entry); - this->lock->unlock(this->lock); + add_entry(this, this->rngs, quality, speed, create); } } @@ -473,13 +512,7 @@ METHOD(crypto_factory_t, add_dh, void, private_crypto_factory_t *this, diffie_hellman_group_t group, dh_constructor_t create) { - entry_t *entry = malloc_thing(entry_t); - - entry->algo = group; - entry->create_dh = create; - this->lock->write_lock(this->lock); - this->dhs->insert_last(this->dhs, entry); - this->lock->unlock(this->lock); + add_entry(this, this->dhs, group, 0, create); } METHOD(crypto_factory_t, remove_dh, void, @@ -695,6 +728,8 @@ crypto_factory_t *crypto_factory_create() "libstrongswan.crypto_test.on_add", FALSE), .test_on_create = lib->settings->get_bool(lib->settings, "libstrongswan.crypto_test.on_create", FALSE), + .bench = lib->settings->get_bool(lib->settings, + "libstrongswan.crypto_test.bench", FALSE), ); return &this->public; diff --git a/src/libstrongswan/crypto/crypto_tester.c b/src/libstrongswan/crypto/crypto_tester.c index 2a6b904af..13e186a5a 100644 --- a/src/libstrongswan/crypto/crypto_tester.c +++ b/src/libstrongswan/crypto/crypto_tester.c @@ -1,6 +1,7 @@ /* - * Copyright (C) 2009 Martin Willi + * Copyright (C) 2009-2010 Martin Willi * Hochschule fuer Technik Rapperswil + * Copyright (C) 2010 revosec 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 @@ -15,6 +16,7 @@ #define _GNU_SOURCE #include <dlfcn.h> +#include <time.h> #include "crypto_tester.h" @@ -67,6 +69,16 @@ struct private_crypto_tester_t { * 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; }; /** @@ -85,9 +97,69 @@ static const char* get_name(void *sym) return "unknown"; } +/** + * 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; +} + +/** + * Benchmark a crypter + */ +static u_int bench_crypter(private_crypto_tester_t *this, + encryption_algorithm_t alg, crypter_constructor_t create) +{ + crypter_t *crypter; + + crypter = create(alg, 0); + 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)); + crypter->set_key(crypter, chunk_from_thing(key)); + + buf = chunk_alloc(this->bench_size); + memset(buf.ptr, 0x34, buf.len); + + runs = 0; + start_timing(&start); + while (end_timing(&start) < this->bench_time) + { + crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL); + 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) + crypter_constructor_t create, u_int *speed) { enumerator_t *enumerator; crypter_test_vector_t *vector; @@ -168,15 +240,63 @@ METHOD(crypto_tester_t, test_crypter, bool, } if (!failed) { - DBG1(DBG_LIB, "enabled %N: passed %u test vectors", - encryption_algorithm_names, alg, tested); + if (speed) + { + *speed = bench_crypter(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, + encryption_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)); + signer->set_key(signer, chunk_from_thing(key)); + + buf = chunk_alloc(this->bench_size); + memset(buf.ptr, 0x34, buf.len); + + runs = 0; + start_timing(&start); + while (end_timing(&start) < this->bench_time) + { + signer->get_signature(signer, buf, mac); + 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) + signer_constructor_t create, u_int *speed) { enumerator_t *enumerator; signer_test_vector_t *vector; @@ -270,15 +390,58 @@ METHOD(crypto_tester_t, test_signer, bool, } if (!failed) { - DBG1(DBG_LIB, "enabled %N: passed %u test vectors", - integrity_algorithm_names, alg, tested); + if (speed) + { + *speed = bench_signer(this, alg, create); + DBG1(DBG_LIB, "enabled %N: passed %u test vectors, %d points", + integrity_algorithm_names, alg, tested, *speed); + } + else + { + DBG1(DBG_LIB, "enabled %N: passed %u test vectors", + integrity_algorithm_names, alg, 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) + { + 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) + hasher_constructor_t create, u_int *speed) { enumerator_t *enumerator; hasher_test_vector_t *vector; @@ -358,15 +521,58 @@ METHOD(crypto_tester_t, test_hasher, bool, } if (!failed) { - DBG1(DBG_LIB, "enabled %N: passed %u test vectors", - hash_algorithm_names, alg, tested); + if (speed) + { + *speed = bench_hasher(this, alg, create); + DBG1(DBG_LIB, "enabled %N: passed %u test vectors, %d points", + hash_algorithm_names, alg, tested, *speed); + } + else + { + DBG1(DBG_LIB, "enabled %N: passed %u test vectors", + hash_algorithm_names, alg, 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)]; + 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) + { + 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) + prf_constructor_t create, u_int *speed) { enumerator_t *enumerator; prf_test_vector_t *vector; @@ -457,15 +663,55 @@ METHOD(crypto_tester_t, test_prf, bool, } if (!failed) { - DBG1(DBG_LIB, "enabled %N: passed %u test vectors", - pseudo_random_function_names, alg, tested); + if (speed) + { + *speed = bench_prf(this, alg, create); + DBG1(DBG_LIB, "enabled %N: passed %u test vectors, %d points", + pseudo_random_function_names, alg, tested, *speed); + } + else + { + DBG1(DBG_LIB, "enabled %N: passed %u test vectors", + pseudo_random_function_names, alg, 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) + { + rng->get_bytes(rng, buf.len, buf.ptr); + 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) + rng_constructor_t create, u_int *speed) { enumerator_t *enumerator; rng_test_vector_t *vector; @@ -539,8 +785,17 @@ METHOD(crypto_tester_t, test_rng, bool, } if (!failed) { - DBG1(DBG_LIB, "enabled %N: passed %u test vectors", - rng_quality_names, quality, tested); + if (speed) + { + *speed = bench_rng(this, quality, create); + DBG1(DBG_LIB, "enabled %N: passed %u test vectors, %d points", + rng_quality_names, quality, tested, *speed); + } + else + { + DBG1(DBG_LIB, "enabled %N: passed %u test vectors", + rng_quality_names, quality, tested); + } } return !failed; } @@ -617,8 +872,15 @@ crypto_tester_t *crypto_tester_create() "libstrongswan.crypto_test.required", FALSE), .rng_true = lib->settings->get_bool(lib->settings, "libstrongswan.crypto_test.rng_true", FALSE), + .bench_time = lib->settings->get_int(lib->settings, + "libstrongswan.crypto_test.bench_time", 50), + .bench_size = lib->settings->get_int(lib->settings, + "libstrongswan.crypto_test.bench_size", 1024), ); + /* enforce a block size of 16, should be fine for all algorithms */ + this->bench_size = this->bench_size / 16 * 16; + return &this->public; } diff --git a/src/libstrongswan/crypto/crypto_tester.h b/src/libstrongswan/crypto/crypto_tester.h index ddcc2da51..a670931a4 100644 --- a/src/libstrongswan/crypto/crypto_tester.h +++ b/src/libstrongswan/crypto/crypto_tester.h @@ -116,46 +116,52 @@ struct crypto_tester_t { * @param alg algorithm to test * @param key_size key size to test, 0 for all * @param create constructor function for the crypter + * @param speed speed test result, NULL to omit * @return TRUE if test passed */ bool (*test_crypter)(crypto_tester_t *this, encryption_algorithm_t alg, - size_t key_size, crypter_constructor_t create); + size_t key_size, crypter_constructor_t create, + u_int *speed); /** * Test a signer algorithm. * * @param alg algorithm to test * @param create constructor function for the signer + * @param speed speed test result, NULL to omit * @return TRUE if test passed */ bool (*test_signer)(crypto_tester_t *this, integrity_algorithm_t alg, - signer_constructor_t create); + signer_constructor_t create, u_int *speed); /** * Test a hasher algorithm. * * @param alg algorithm to test * @param create constructor function for the hasher + * @param speed speed test result, NULL to omit * @return TRUE if test passed */ bool (*test_hasher)(crypto_tester_t *this, hash_algorithm_t alg, - hasher_constructor_t create); + hasher_constructor_t create, u_int *speed); /** * Test a PRF algorithm. * * @param alg algorithm to test * @param create constructor function for the PRF + * @param speed speed test result, NULL to omit * @return TRUE if test passed */ bool (*test_prf)(crypto_tester_t *this, pseudo_random_function_t alg, - prf_constructor_t create); + prf_constructor_t create, u_int *speed); /** * Test a RNG implementation. * * @param alg algorithm to test * @param create constructor function for the RNG + * @param speed speed test result, NULL to omit * @return TRUE if test passed */ bool (*test_rng)(crypto_tester_t *this, rng_quality_t quality, - rng_constructor_t create); + rng_constructor_t create, u_int *speed); /** * Add a test vector to test a crypter. * |