rsa_test.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : test RSA public key encryption                                    *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *  Purpose:                                                                   *
00007 *                                                                             *
00008 *    Exercises the RSA 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/crypto.h>
00028 #include <openssl/err.h>
00029 #include <openssl/rand.h>
00030 
00031 #include <openssl/rsa.h>
00032 
00033 #include <stdio.h>
00034 #include <string.h>
00035 
00036 HOOPLE_STARTUP_CODE;
00037 
00038 const int KEY_SIZE = 1024;
00039   // the size of the RSA 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 = 100000;
00048   // the largest chunk that we'll try to encrypt.
00049 
00050 chaos rando;
00051 
00052 RSA *generate_key()
00053 {
00054   RSA *to_return = RSA_generate_key(512, 65537, NIL, NIL);
00055   if (!to_return) {
00056 printf("failed to generate a key\n");
00057     return NIL;
00058   }
00059 
00060   int check = RSA_check_key(to_return);
00061   if (check != 1) {
00062 printf("failed to check the key\n");
00063     return NIL;
00064   }
00065   return to_return;
00066 }
00067 
00068 const byte_array &random_seed()
00069 {
00070   static byte_array seed;
00071   static bool initted = false;
00072   if (!initted) {
00073     for (int i = 0; i < SEED_SIZE; i++) {
00074       seed += byte(rando.inclusive(0, 255));
00075     }
00076     initted = true;
00077   }
00078   return seed;
00079 }
00080 
00081 // flen must be less than RSA_size(rsa) - 11 for the PKCS #1 v1.5 based padding modes, less than
00082 // RSA_size(rsa) - 41 for RSA_PKCS1_OAEP_PADDING and exactly RSA_size(rsa) for RSA_NO_PADDING.
00083 
00085 
00086 // rsa_public_encryption and rsa_private_decryption are a pair.
00087 // an untrusted user can encrypt with the public key and only the possessor of
00088 // the private key should be able to decrypt it.
00089 
00090 bool rsa_public_encryption(RSA *key, const byte_array &source,
00091     byte_array &target)
00092 {
00093   target.reset();
00094   const int max_chunk = RSA_size(key) - 12;
00095 //printf("max chunk for encryption is %d\n", max_chunk);
00096 
00097   byte_array cipher(RSA_size(key));
00098   for (int i = 0; i < source.length(); i += max_chunk) {
00099     int edge = i + max_chunk - 1;
00100     if (edge > source.last())
00101       edge = source.last();
00102 //printf("range now %d to %d\n", i, edge);
00103     int next_chunk = edge - i + 1;
00104     RSA_public_encrypt(next_chunk, &source[i],
00105         cipher.access(), key, RSA_PKCS1_PADDING);
00106     target += cipher;
00107   }
00108   return true;
00109 }
00110 
00111 bool rsa_private_decryption(RSA *key, const byte_array &source,
00112     byte_array &target)
00113 {
00114   target.reset();
00115   const int max_chunk = RSA_size(key);
00116 //printf("max chunk for decryption is %d\n", max_chunk);
00117 
00118   byte_array uncipher(max_chunk);
00119   for (int i = 0; i < source.length(); i += max_chunk) {
00120     int edge = i + max_chunk - 1;
00121     if (edge > source.last())
00122       edge = source.last();
00123     int next_chunk = edge - i + 1;
00124 //printf("range now %d to %d\n", i, edge);
00125     int dec_size = RSA_private_decrypt(next_chunk, &source[i],
00126         uncipher.access(), key, RSA_PKCS1_PADDING);
00127 //printf("got decryp size %d\n", dec_size);
00128     if (dec_size < 0) return false;  // that didn't work.
00129     uncipher.zap(dec_size, uncipher.last());
00130     target += uncipher;
00131     uncipher.reset(max_chunk);
00132   }
00133   return true;
00134 }
00135 
00137 
00138 // rsa_private_encryption and rsa_public_decryption are a pair.
00139 // the trusted user with the private key can create encrypted chunks that
00140 // anyone with the public key can decrypt.
00141 
00142 bool rsa_private_encryption(RSA *key, const byte_array &source,
00143     byte_array &target)
00144 {
00145   target.reset();
00146   const int max_chunk = RSA_size(key) - 12;
00147 //printf("max chunk for encryption is %d\n", max_chunk);
00148 
00149   byte_array cipher(RSA_size(key));
00150   for (int i = 0; i < source.length(); i += max_chunk) {
00151     int edge = i + max_chunk - 1;
00152     if (edge > source.last())
00153       edge = source.last();
00154 //printf("range now %d to %d\n", i, edge);
00155     int next_chunk = edge - i + 1;
00156     RSA_private_encrypt(next_chunk, &source[i],
00157         cipher.access(), key, RSA_PKCS1_PADDING);
00158     target += cipher;
00159   }
00160   return true;
00161 }
00162 
00163 bool rsa_public_decryption(RSA *key, const byte_array &source,
00164     byte_array &target)
00165 {
00166   target.reset();
00167   const int max_chunk = RSA_size(key);
00168 //printf("max chunk for decryption is %d\n", max_chunk);
00169 
00170   byte_array uncipher(max_chunk);
00171   for (int i = 0; i < source.length(); i += max_chunk) {
00172     int edge = i + max_chunk - 1;
00173     if (edge > source.last())
00174       edge = source.last();
00175     int next_chunk = edge - i + 1;
00176 //printf("range now %d to %d\n", i, edge);
00177     int dec_size = RSA_public_decrypt(next_chunk, &source[i],
00178         uncipher.access(), key, RSA_PKCS1_PADDING);
00179 //printf("got decryp size %d\n", dec_size);
00180     if (dec_size < 0) return false;  // that didn't work.
00181     uncipher.zap(dec_size, uncipher.last());
00182     target += uncipher;
00183     uncipher.reset(max_chunk);
00184   }
00185   return true;
00186 }
00187 
00189 
00190 int main(int formal(argc), char *formal(argv)[])
00191 {
00192   CRYPTO_malloc_debug_init();
00193 
00194   CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL);
00195 
00196   CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
00197 
00198   RAND_seed(random_seed().observe(), SEED_SIZE);
00199 
00200   time_stamp start;
00201 
00202   istring fodder = string_manipulation::make_random_name(MAX_STRING + 1,
00203       MAX_STRING + 1);
00204 
00205   for (int i = 0; i < TEST_RUNS; i++) {
00206     time_stamp start;
00207     RSA *private_key = generate_key();
00208     int key_durat = int(time_stamp().value() - start.value());
00209 
00210     RSA *public_key = RSAPublicKey_dup(private_key);
00211       // make our public portion.
00212 
00213 //RSA_print_fp(stdout, private_key, 0);
00214 //RSA_print_fp(stdout, public_key, 0);
00215 
00216     int string_start = rando.inclusive(0, MAX_STRING);
00217     int string_end = rando.inclusive(0, MAX_STRING);
00218     flip_increasing(string_start, string_end);
00219     istring ranstring = fodder.substring(string_start, string_end);
00220     byte_array target;
00221 
00222     // the first phase tests the outsiders sending back data that only we,
00223     // with our private key, can decrypt.
00224 
00225     start.reset();
00226     bool worked = rsa_public_encryption(public_key,
00227         byte_array(ranstring.length() + 1, (byte*)ranstring.s()), target);
00228     int pub_enc_durat = int(time_stamp().value() - start.value());
00229     if (!worked)
00230       deadly_error("rsa_test", "phase 1", "failed to encrypt the string!\n");
00231 
00232     byte_array recovered;
00233     start.reset();
00234     worked = rsa_private_decryption(private_key, target, recovered);
00235     int priv_dec_durat = int(time_stamp().value() - start.value());
00236     if (!worked)
00237       deadly_error("rsa_test", "phase 1", "failed to decrypt the string!\n");
00238 
00239     istring teddro = (char *)recovered.observe();
00240 
00241     if (teddro != ranstring)
00242       printf("failed to get back the data!\n");
00243 
00244     // the second phase tests us using our private key to encrypt data which
00245     // anyone with the public key can decode.
00246 
00247     start.reset();
00248     worked = rsa_private_encryption(private_key,
00249         byte_array(ranstring.length() + 1, (byte*)ranstring.s()), target);
00250     int priv_enc_durat = int(time_stamp().value() - start.value());
00251     if (!worked)
00252       deadly_error("rsa_test", "phase 2", "failed to encrypt the string!\n");
00253 
00254     start.reset();
00255     worked = rsa_public_decryption(public_key, target, recovered);
00256     int pub_dec_durat = int(time_stamp().value() - start.value());
00257     if (!worked)
00258       deadly_error("rsa_test", "phase 2", "failed to decrypt the string!\n");
00259 
00260     teddro = (char *)recovered.observe();
00261 
00262     if (teddro != ranstring)
00263       printf("failed to get back the data!\n");
00264 
00265     printf("key generation: %d ms, public encrypt: %d ms, private "
00266         "decrypt: %d ms\n", key_durat, pub_enc_durat, priv_dec_durat);
00267     printf("data size: %d bytes, private encrypt: %d ms, public "
00268         "decrypt: %d ms\n",
00269         string_end - string_start + 1, priv_enc_durat, pub_dec_durat);
00270     printf("\n");
00271 
00272     RSA_free(public_key);
00273     RSA_free(private_key);
00274   }
00275 
00276   int duration = int(time_stamp().value() - start.value());
00277   printf("duration for %d keys and encrypt/decrypt=%d ms,\n",
00278       TEST_RUNS, duration);
00279   printf("that comes to %d ms per cycle.\n", duration / TEST_RUNS);
00280 
00281   CRYPTO_cleanup_all_ex_data();
00282   ERR_remove_state(0);
00283 
00284   CRYPTO_mem_leaks_fp(stderr);
00285 
00286   return 0;
00287 }
00288 

Generated on Fri Nov 28 04:29:40 2008 for HOOPLE Libraries by  doxygen 1.5.1