blowfish_test.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : test blowfish encryption                                          *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *  Purpose:                                                                   *
00007 *                                                                             *
00008 *    Exercises the BlowFish encryption functions from the OpenSSL package.    *
00009 *                                                                             *
00010 *******************************************************************************
00011 * Copyright (c) 2005-$now By Author.  This program is free software; you can  *
00012 * redistribute it and/or modify it under the terms of the GNU General Public  *
00013 * License as published by the Free Software Foundation; either version 2 of   *
00014 * the License or (at your option) any later version.  This is online at:      *
00015 *     http://www.fsf.org/copyleft/gpl.html                                    *
00016 * Please send any updates to: fred@gruntose.com                               *
00017 \*****************************************************************************/
00018 
00019 #include <basis/byte_array.h>
00020 #include <basis/chaos.h>
00021 #include <basis/function.h>
00022 #include <basis/istring.h>
00023 #include <mechanisms/time_stamp.h>
00024 #include <data_struct/static_memory_gremlin.h>
00025 #include <textual/string_manipulation.h>
00026 
00027 #include <openssl/blowfish.h>
00028 #include <openssl/crypto.h>
00029 #include <openssl/err.h>
00030 #include <openssl/evp.h>
00031 #include <openssl/rand.h>
00032 
00033 #include <stdio.h>
00034 #include <string.h>
00035 
00036 HOOPLE_STARTUP_CODE;
00037 
00038 const int KEY_SIZE = 402;
00039   // the size of the BF key that we'll create.
00040 
00041 const int TEST_RUNS = 100;
00042   // the number of cycles of testing.
00043 
00044 const int SEED_SIZE = 100;
00045   // the size of the random seed that we'll use.
00046 
00047 const int MAX_STRING = 1000000;
00048   // the largest chunk that we'll try to encrypt.
00049 
00050 const int MAX_CHUNK = 1024;
00051   // the largest chunk of data that we encrypt at a time.
00052 
00053 chaos rando;
00054 
00055 #define static_class_name() "blowfish_test"
00056 
00057 void provide_init_vect(byte_array &new_iv)
00058 {
00059   new_iv.reset(EVP_MAX_IV_LENGTH);
00060   for (int i = 0; i < EVP_MAX_IV_LENGTH; i++) new_iv[i] = 214 - i;
00061 }
00062 
00063 void generate_key(int size, byte_array &new_key)
00064 {
00065   new_key.reset(size);
00066   for (int i = 0; i < size; i++) new_key[i] = rando.inclusive(0, 255);
00067 }
00068 
00069 const byte_array &random_seed()
00070 {
00071   static byte_array seed;
00072   static bool initted = false;
00073   if (!initted) {
00074     for (int i = 0; i < SEED_SIZE; i++) {
00075       seed += byte(rando.inclusive(0, 255));
00076     }
00077     initted = true;
00078   }
00079   return seed;
00080 }
00081 
00083 
00084 bool blowfish_encryption(const byte_array &key, const byte_array &init_vect,
00085     const byte_array &source, byte_array &target)
00086 {
00087   FUNCDEF("blowfish_encryption");
00088   target.reset();
00089   bool to_return = true;
00090 
00091   // initialize an encoding session.
00092   EVP_CIPHER_CTX session;
00093   EVP_CIPHER_CTX_init(&session);
00094   EVP_EncryptInit(&session, EVP_bf_cbc(), key.observe(), init_vect.observe());
00095   EVP_CIPHER_CTX_set_key_length(&session, key.length());
00096 
00097   byte_array cipher(MAX_CHUNK + 100);  // temporary space for encrypted data.
00098   for (int i = 0; i < source.length(); i += MAX_CHUNK) {
00099     // calculate the extent of what's included.
00100     int edge = i + MAX_CHUNK - 1;
00101     if (edge > source.last())
00102       edge = source.last();
00103     int next_chunk = edge - i + 1;
00104     int cipher_len = 0;
00105     // encrypt the current range.
00106     int enc_ret = EVP_EncryptUpdate(&session, cipher.access(), &cipher_len,
00107         &source[i], next_chunk);
00108     if (enc_ret != 1) {
00109       continuable_error(static_class_name(), func, "encryption failed.");
00110       to_return = false;
00111       break;
00112     }
00113     // chop any extra space off.
00114 //    printf("encrypting bytes %d to %d.\n", i, edge);
00115     cipher.zap(cipher_len, cipher.last());
00116     target += cipher;
00117     cipher.reset(MAX_CHUNK + 100);  // reinflate for next cycle.
00118   }
00119 
00120   // finalize the encryption.
00121   int pad_len = 0;
00122   int enc_ret = EVP_EncryptFinal(&session, cipher.access(), &pad_len);
00123   if (enc_ret != 1) {
00124     continuable_error(static_class_name(), func, "finalizing encryption failed.");
00125     to_return = false;
00126   } else {
00127 //    printf("padding added %d bytes.\n", pad_len);
00128     cipher.zap(pad_len, cipher.last());
00129     target += cipher;
00130   }
00131 
00132   EVP_CIPHER_CTX_cleanup(&session);
00133   return to_return;
00134 }
00135 
00136 bool blowfish_decryption(const byte_array &key, const byte_array &init_vect,
00137     const byte_array &source, byte_array &target)
00138 {
00139   FUNCDEF("blowfish_decryption");
00140   target.reset();
00141   bool to_return = true;
00142   EVP_CIPHER_CTX session;
00143   EVP_CIPHER_CTX_init(&session);
00144   EVP_DecryptInit(&session, EVP_bf_cbc(), key.observe(), init_vect.observe());
00145   EVP_CIPHER_CTX_set_key_length(&session, key.length());
00146 
00147   byte_array uncipher(MAX_CHUNK + 100);
00148   for (int i = 0; i < source.length(); i += MAX_CHUNK) {
00149     int edge = i + MAX_CHUNK - 1;
00150     if (edge > source.last())
00151       edge = source.last();
00152     int next_chunk = edge - i + 1;
00153 //    printf("decrypting bytes %d to %d.\n", i, edge);
00154     int uncipher_len = 0;
00155     int dec_ret = EVP_DecryptUpdate(&session, uncipher.access(), &uncipher_len,
00156         &source[i], next_chunk);
00157     if (dec_ret != 1) {
00158       continuable_error(static_class_name(), func, "decryption failed.");
00159       to_return = false;
00160       break;
00161     }
00162 //    printf("  decrypted size in bytes is %d.\n", uncipher_len);
00163     uncipher.zap(uncipher_len, uncipher.last());
00164     target += uncipher;
00165     uncipher.reset(MAX_CHUNK + 100);
00166   }
00167 
00168   int pad_len = 0;
00169   int dec_ret = EVP_DecryptFinal(&session, uncipher.access(), &pad_len);
00170 //  printf("padding added %d bytes.\n", pad_len);
00171   if (dec_ret != 1) {
00172     continuable_error(static_class_name(), func, "finalizing decryption failed.");
00173     to_return = false;
00174   } else {
00175     int dec_size = pad_len;
00176     uncipher.zap(dec_size, uncipher.last());
00177     target += uncipher;
00178   }
00179 
00180   EVP_CIPHER_CTX_cleanup(&session);
00181   return to_return;
00182 }
00183 
00185 
00186 int main(int formal(argc), char *formal(argv)[])
00187 {
00188   FUNCDEF("main");
00189   CRYPTO_malloc_debug_init();
00190 
00191   CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL);
00192 
00193   CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
00194 
00195   RAND_seed(random_seed().observe(), SEED_SIZE);
00196 
00197   istring fodder = string_manipulation::make_random_name(MAX_STRING + 1,
00198       MAX_STRING + 1);
00199 
00200   time_stamp start;
00201 
00202   for (int i = 0; i < TEST_RUNS; i++) {
00203     time_stamp start;
00204     byte_array key;
00205     byte_array iv;
00206     provide_init_vect(iv);
00207     generate_key(KEY_SIZE, key);
00208     int key_durat = int(time_stamp().value() - start.value());
00209 
00210     int string_start = rando.inclusive(0, MAX_STRING);
00211     int string_end = rando.inclusive(0, MAX_STRING);
00212     flip_increasing(string_start, string_end);
00213     istring ranstring = fodder.substring(string_start, string_end);
00214 //printf("encoding %s\n", ranstring.s());
00215 
00216     byte_array target;
00217 
00218     start.reset();
00219     bool worked = blowfish_encryption(key, iv,
00220         byte_array(ranstring.length() + 1, (byte*)ranstring.s()), target);
00221     int enc_durat = int(time_stamp().value() - start.value());
00222     if (!worked)
00223       deadly_error("blowfish_test", "phase 1", "failed to encrypt the string!");
00224 
00225     byte_array recovered;
00226     start.reset();
00227     worked = blowfish_decryption(key, iv, target, recovered);
00228     int dec_durat = int(time_stamp().value() - start.value());
00229     if (!worked)
00230       deadly_error("blowfish_test", "phase 1", "failed to decrypt the string!");
00231 //    printf("original has %d chars, recovered has %d chars\n",
00232 //        ranstring.length(), recovered.length() - 1);
00233 
00234     istring teddro = (char *)recovered.observe();
00235 //printf("decoded %s\n", teddro.s());
00236 
00237     if (teddro != ranstring)
00238       deadly_error(static_class_name(), func, "failed to regenerate the original string!");
00239 
00240     printf("key generation: %d ms, encrypt: %d ms, decrypt: %d ms\n",
00241          key_durat, enc_durat, dec_durat);
00242     printf("data size: %d bytes\n", string_end - string_start + 1);
00243     printf("\n");
00244   }
00245 
00246   int duration = int(time_stamp().value() - start.value());
00247   printf("duration for %d keys and encrypt/decrypt=%d ms,\n",
00248       TEST_RUNS, duration);
00249   printf("that comes to %d ms per cycle.\n", duration / TEST_RUNS);
00250 
00251   CRYPTO_cleanup_all_ex_data();
00252   ERR_remove_state(0);
00253 
00254   CRYPTO_mem_leaks_fp(stderr);
00255 
00256   return 0;
00257 }
00258 
00259 #undef static_class_name
00260 

Generated on Fri Sep 5 04:29:08 2008 for HOOPLE Libraries by  doxygen 1.5.1