/* * Name : test twofish encryption * Author : Chris Koeritz * Purpose: Exercises the BlowFish encryption methods in the crypto library. ** * Copyright (c) 2005-$now By Author. 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. This is online at: * * http://www.fsf.org/copyleft/gpl.html * * Please send any updates to: fred@gruntose.com * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace application; using namespace basis; using namespace crypto; using namespace filesystem; using namespace loggers; using namespace mathematics; using namespace processes; using namespace structures; using namespace textual; using namespace timely; using namespace unit_test; #define LOG(to_print) EMERGENCY_LOG(program_wide_logger::get(), astring(to_print)) #define DEBUG_TWOFISH // uncomment for noisier run. const int TEST_RUNS_PER_KEY = 42; // encryption test cycles done on each key. const int THREAD_COUNT = 10; // number of threads testing twofish at once. const int ITERATIONS = 64; // number of test runs in our testing threads. const int MAX_STRING = 64 * KILOBYTE; // largest chunk that we'll try to encrypt. ////////////// class test_twofish; // forward. class twofish_thread : public ethread { public: twofish_thread(test_twofish &parent) : ethread(), _parent(parent) {} void perform_activity(void *ptr); // try out random twofish keys on randomly chosen chunks of the fodder. private: test_twofish &_parent; }; ////////////// class test_twofish : virtual public unit_base, virtual public application_shell { public: test_twofish() : _fodder(string_manipulation::make_random_name(MAX_STRING + 1, MAX_STRING + 1)) {} DEFINE_CLASS_NAME("test_twofish"); int execute(); private: astring _fodder; // chunks taken from this are encrypted and decrypted. time_stamp _program_start; // the time at which we started executing. thread_cabinet _threads; // manages our testing threads. friend class twofish_thread; // bad practice, but saves time in test app. }; int test_twofish::execute() { FUNCDEF("execute"); #ifdef DEBUG_TWOFISH LOG("starting twofish test..."); #endif int left = THREAD_COUNT; while (left--) { #ifdef DEBUG_TWOFISH LOG(a_sprintf("twofish thread %d starting...", left)); #endif _threads.add_thread(new twofish_thread(*this), true, NULL_POINTER); } #ifdef DEBUG_TWOFISH LOG("started all threads..."); #endif while (_threads.threads()) { #ifdef DEBUG_TWOFISH LOG("periodic debris cleaning."); #endif _threads.clean_debris(); time_control::sleep_ms(1000); } int duration = int(time_stamp().value() - _program_start.value()); LOG(a_sprintf("duration for %d keys and encrypt/decrypt=%d ms,", ITERATIONS * TEST_RUNS_PER_KEY * THREAD_COUNT, duration)); LOG(a_sprintf("that comes to %d ms per cycle.", int(double(duration / TEST_RUNS_PER_KEY / ITERATIONS / THREAD_COUNT)))); return final_report(); } ////////////// #undef UNIT_BASE_THIS_OBJECT #define UNIT_BASE_THIS_OBJECT (*dynamic_cast(application_shell::single_instance())) void twofish_thread::perform_activity(void *) { FUNCDEF("perform_activity"); int left = ITERATIONS; while (left--) { time_stamp key_start; twofish_crypto tc = twofish_crypto(_parent.randomizer().inclusive(tc.static_minimum_key_size_in_bits(), tc.static_maximum_key_size_in_bits())); #ifdef DEBUG_TWOFISH LOG(a_sprintf("%d bit key has:", tc.key_size())); astring dumped_key = byte_formatter::text_dump(tc.get_key()); LOG(a_sprintf("%s", dumped_key.s())); #endif int key_dur = int(time_stamp().value() - key_start.value()); #ifdef DEBUG_TWOFISH LOG(a_sprintf(" key generation took %d ms", key_dur)); #endif for (int i = 0; i < TEST_RUNS_PER_KEY; i++) { /// byte_array key; /// byte_array iv; LOG(a_sprintf("test run %d on this key.", i+1)); int string_start = _parent.randomizer().inclusive(0, MAX_STRING - 1); int string_end = _parent.randomizer().inclusive(0, MAX_STRING - 1); flip_increasing(string_start, string_end); astring ranstring = _parent._fodder.substring(string_start, string_end); #ifdef DEBUG_TWOFISH // LOG(a_sprintf("encoding %s", ranstring.s())); // LOG(a_sprintf("string length encoded: %d", ranstring.length())); #endif byte_array target; time_stamp test_start; bool worked = tc.encrypt(byte_array(ranstring.length() + 1, (abyte*)ranstring.s()), target); int enc_durat = int(time_stamp().value() - test_start.value()); ASSERT_TRUE(worked, "phase 1 should not fail to encrypt the string"); byte_array recovered; test_start.reset(); worked = tc.decrypt(target, recovered); int dec_durat = int(time_stamp().value() - test_start.value()); ASSERT_TRUE(worked, "phase 1 should not fail to decrypt the string"); #ifdef DEBUG_TWOFISH astring jammer_piece = a_sprintf("--\noriginal has %d chars, recovered has %d chars", ranstring.length(), recovered.length() - 1); #endif astring teddro = (char *)recovered.observe(); #ifdef DEBUG_TWOFISH // LOG(a_sprintf("decoded %s", teddro.s())); #endif #ifdef DEBUG_TWOFISH if (teddro != ranstring) { LOG(a_sprintf("error!\toriginal has %d chars, recovered has %d chars", ranstring.length(), recovered.length() - 1)); LOG(a_sprintf("\tencoded %s", ranstring.s())); LOG(a_sprintf("\tdecoded %s", teddro.s())); } #endif ASSERT_EQUAL(teddro, ranstring, "should not fail to regenerate the original string"); #ifdef DEBUG_TWOFISH LOG(a_sprintf("%s\nencrypt %d ms, decrypt %d ms, data %d bytes", jammer_piece.s(), enc_durat, dec_durat, string_end - string_start + 1)); #endif time_control::sleep_ms(0); // take a rest. } time_control::sleep_ms(0); // take a rest. } } HOOPLE_MAIN(test_twofish, )