rsa_crypto.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : RSA public key encryption                                         *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *  Purpose:                                                                   *
00007 *                                                                             *
00008 *    Supports public (and private) key encryption and decryption using the    *
00009 *  OpenSSL package's support for RSA encryption.                              *
00010 *                                                                             *
00011 *******************************************************************************
00012 * Copyright (c) 2005-$now By Author.  This program is free software; you can  *
00013 * redistribute it and/or modify it under the terms of the GNU General Public  *
00014 * License as published by the Free Software Foundation; either version 2 of   *
00015 * the License or (at your option) any later version.  This is online at:      *
00016 *     http://www.fsf.org/copyleft/gpl.html                                    *
00017 * Please send any updates to: fred@gruntose.com                               *
00018 \*****************************************************************************/
00019 
00020 #include "rsa_crypto.h"
00021 #include "ssl_init.h"
00022 
00023 #include <basis/functions.h>
00024 #include <loggers/critical_events.h>
00025 #include <mathematics/chaos.h>
00026 #include <structures/object_packers.h>
00027 
00028 #include <openssl/bn.h>
00029 #include <openssl/rsa.h>
00030 
00031 using namespace basis;
00032 using namespace loggers;
00033 using namespace mathematics;
00034 using namespace structures;
00035 
00036 namespace crypto {
00037 
00038 // notes from openssl docs: length to be encrypted in a chunk must be less than
00039 // RSA_size(rsa) - 11 for the PKCS #1 v1.5 based padding modes, less than
00040 // RSA_size(rsa) - 41 for RSA_PKCS1_OAEP_PADDING and exactly RSA_size(rsa)
00041 // for RSA_NO_PADDING.
00042 
00043 #undef LOG
00044 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
00045 
00046 //nice printing method...  RSA_print_fp(stdout, private_key, 0);
00047 
00048 rsa_crypto::rsa_crypto(int key_size)
00049 : _key(NIL)
00050 {
00051   _key = generate_key(key_size);  // generate_key initializes ssl for us.
00052 }
00053 
00054 rsa_crypto::rsa_crypto(const byte_array &key)
00055 : _key(NIL)
00056 {
00057   static_ssl_initializer();
00058   byte_array key_copy = key;
00059   set_key(key_copy);
00060 }
00061 
00062 rsa_crypto::rsa_crypto(rsa_st *key)
00063 : _key(NIL)
00064 {
00065   static_ssl_initializer();
00066   set_key(key);
00067 }
00068 
00069 rsa_crypto::rsa_crypto(const rsa_crypto &to_copy)
00070 : root_object(),
00071   _key(NIL)
00072 {
00073   static_ssl_initializer();
00074   set_key(to_copy._key);
00075 }
00076 
00077 rsa_crypto::~rsa_crypto()
00078 {
00079   RSA_free(_key);
00080 }
00081 
00082 const rsa_crypto &rsa_crypto::operator = (const rsa_crypto &to_copy)
00083 {
00084   if (this == &to_copy) return *this;
00085   set_key(to_copy._key);
00086   return *this;
00087 }
00088 
00089 rsa_st *rsa_crypto::generate_key(int key_size)
00090 {
00091   FUNCDEF("generate_key");
00092   if (key_size < 4) key_size = 4;  // laughable lower default.
00093   static_ssl_initializer();
00094   rsa_st *to_return = RSA_generate_key(key_size, 65537, NIL, NIL);
00095   if (!to_return) {
00096     continuable_error(static_class_name(), func,
00097         a_sprintf("failed to generate a key of %d bits.", key_size));
00098   }
00099   return to_return;
00100 }
00101 
00102 bool rsa_crypto::check_key(rsa_st *key) { return RSA_check_key(key) == 1; }
00103 
00104 bool rsa_crypto::set_key(byte_array &key)
00105 {
00106   FUNCDEF("set_key [byte_array]");
00107   if (!key.length()) return false;
00108   if (_key) RSA_free(_key);
00109   _key = RSA_new();
00110   abyte type;
00111   if (!structures::detach(key, type)) return false;
00112   if ( (type != 'r') && (type != 'u') ) return false;
00113   // get the public key bits first.
00114   byte_array n;
00115   if (!structures::detach(key, n)) return false;
00116   _key->n = BN_bin2bn(n.access(), n.length(), NIL);
00117   if (!_key->n) return false;
00118   byte_array e;
00119   if (!structures::detach(key, e)) return false;
00120   _key->e = BN_bin2bn(e.access(), e.length(), NIL);
00121   if (!_key->e) return false;
00122   if (type == 'u') return true;  // done with public key.
00123 
00124   // the rest is for a private key.
00125   byte_array d;
00126   if (!structures::detach(key, d)) return false;
00127   _key->d = BN_bin2bn(d.access(), d.length(), NIL);
00128   if (!_key->d) return false;
00129   byte_array p;
00130   if (!structures::detach(key, p)) return false;
00131   _key->p = BN_bin2bn(p.access(), p.length(), NIL);
00132   if (!_key->p) return false;
00133   byte_array q;
00134   if (!structures::detach(key, q)) return false;
00135   _key->q = BN_bin2bn(q.access(), q.length(), NIL);
00136   if (!_key->q) return false;
00137   byte_array dmp1;
00138   if (!structures::detach(key, dmp1)) return false;
00139   _key->dmp1 = BN_bin2bn(dmp1.access(), dmp1.length(), NIL);
00140   if (!_key->dmp1) return false;
00141   byte_array dmq1;
00142   if (!structures::detach(key, dmq1)) return false;
00143   _key->dmq1 = BN_bin2bn(dmq1.access(), dmq1.length(), NIL);
00144   if (!_key->dmq1) return false;
00145   byte_array iqmp;
00146   if (!structures::detach(key, iqmp)) return false;
00147   _key->iqmp = BN_bin2bn(iqmp.access(), iqmp.length(), NIL);
00148   if (!_key->iqmp) return false;
00149   int check = RSA_check_key(_key);
00150   if (check != 1) {
00151     continuable_error(static_class_name(), func, "failed to check the private "
00152         "portion of the key!");
00153     return false;
00154   }
00155 
00156   return true;
00157 }
00158 
00159 bool rsa_crypto::set_key(rsa_st *key)
00160 {
00161   FUNCDEF("set_key [rsa_st]");
00162   if (!key) return NIL;
00163   // test the incoming key.
00164   int check = RSA_check_key(key);
00165   if (check != 1) return false;
00166   // clean out the old key.
00167   if (_key) RSA_free(_key);
00168   _key = RSAPrivateKey_dup(key);
00169   if (!_key) {
00170     continuable_error(static_class_name(), func, "failed to create a "
00171         "duplicate of the key!");
00172     return false;
00173   }
00174   return true;
00175 }
00176 
00177 bool rsa_crypto::public_key(byte_array &pubkey) const
00178 {
00179 //  FUNCDEF("public_key");
00180   if (!_key) return false;
00181   structures::attach(pubkey, abyte('u'));  // signal a public key.
00182   // convert the two public portions into binary.
00183   byte_array n(BN_num_bytes(_key->n));
00184   int ret = BN_bn2bin(_key->n, n.access());
00185   byte_array e(BN_num_bytes(_key->e));
00186   ret = BN_bn2bin(_key->e, e.access());
00187   // pack those two chunks.
00188   structures::attach(pubkey, n);
00189   structures::attach(pubkey, e);
00190   return true;
00191 }
00192 
00193 bool rsa_crypto::private_key(byte_array &privkey) const
00194 {
00195 //  FUNCDEF("private_key");
00196   if (!_key) return false;
00197   int posn = privkey.length();
00198   bool worked = public_key(privkey);  // get the public pieces first.
00199   if (!worked) return false;
00200   privkey[posn] = abyte('r');  // switch public key flag to private.
00201   // convert the multiple private portions into binary.
00202   byte_array d(BN_num_bytes(_key->d));
00203   int ret = BN_bn2bin(_key->d, d.access());
00204   byte_array p(BN_num_bytes(_key->p));
00205   ret = BN_bn2bin(_key->p, p.access());
00206   byte_array q(BN_num_bytes(_key->q));
00207   ret = BN_bn2bin(_key->q, q.access());
00208   byte_array dmp1(BN_num_bytes(_key->dmp1));
00209   ret = BN_bn2bin(_key->dmp1, dmp1.access());
00210   byte_array dmq1(BN_num_bytes(_key->dmq1));
00211   ret = BN_bn2bin(_key->dmq1, dmq1.access());
00212   byte_array iqmp(BN_num_bytes(_key->iqmp));
00213   ret = BN_bn2bin(_key->iqmp, iqmp.access());
00214   // pack all those in now.
00215   structures::attach(privkey, d);
00216   structures::attach(privkey, p);
00217   structures::attach(privkey, q);
00218   structures::attach(privkey, dmp1);
00219   structures::attach(privkey, dmq1);
00220   structures::attach(privkey, iqmp);
00221   return true;
00222 }
00223 
00224 bool rsa_crypto::public_encrypt(const byte_array &source,
00225     byte_array &target) const
00226 {
00227 //  FUNCDEF("public_encrypt");
00228   target.reset();
00229   if (!source.length()) return false;
00230   const int max_chunk = RSA_size(_key) - 12;
00231 
00232   byte_array encoded(RSA_size(_key));
00233   for (int i = 0; i < source.length(); i += max_chunk) {
00234     int edge = i + max_chunk - 1;
00235     if (edge > source.last())
00236       edge = source.last();
00237     int next_chunk = edge - i + 1;
00238     RSA_public_encrypt(next_chunk, &source[i],
00239         encoded.access(), _key, RSA_PKCS1_PADDING);
00240     target += encoded;
00241   }
00242   return true;
00243 }
00244 
00245 bool rsa_crypto::private_decrypt(const byte_array &source,
00246     byte_array &target) const
00247 {
00248 //  FUNCDEF("private_decrypt");
00249   target.reset();
00250   if (!source.length()) return false;
00251   const int max_chunk = RSA_size(_key);
00252 
00253   byte_array decoded(max_chunk);
00254   for (int i = 0; i < source.length(); i += max_chunk) {
00255     int edge = i + max_chunk - 1;
00256     if (edge > source.last())
00257       edge = source.last();
00258     int next_chunk = edge - i + 1;
00259     int dec_size = RSA_private_decrypt(next_chunk, &source[i],
00260         decoded.access(), _key, RSA_PKCS1_PADDING);
00261     if (dec_size < 0) return false;  // that didn't work.
00262     decoded.zap(dec_size, decoded.last());
00263     target += decoded;
00264     decoded.reset(max_chunk);
00265   }
00266   return true;
00267 }
00268 
00269 bool rsa_crypto::private_encrypt(const byte_array &source,
00270     byte_array &target) const
00271 {
00272 //  FUNCDEF("private_encrypt");
00273   target.reset();
00274   if (!source.length()) return false;
00275   const int max_chunk = RSA_size(_key) - 12;
00276 
00277   byte_array encoded(RSA_size(_key));
00278   for (int i = 0; i < source.length(); i += max_chunk) {
00279     int edge = i + max_chunk - 1;
00280     if (edge > source.last())
00281       edge = source.last();
00282     int next_chunk = edge - i + 1;
00283     RSA_private_encrypt(next_chunk, &source[i],
00284         encoded.access(), _key, RSA_PKCS1_PADDING);
00285     target += encoded;
00286   }
00287   return true;
00288 }
00289 
00290 bool rsa_crypto::public_decrypt(const byte_array &source,
00291     byte_array &target) const
00292 {
00293 //  FUNCDEF("public_decrypt");
00294   target.reset();
00295   if (!source.length()) return false;
00296   const int max_chunk = RSA_size(_key);
00297 
00298   byte_array decoded(max_chunk);
00299   for (int i = 0; i < source.length(); i += max_chunk) {
00300     int edge = i + max_chunk - 1;
00301     if (edge > source.last())
00302       edge = source.last();
00303     int next_chunk = edge - i + 1;
00304     int dec_size = RSA_public_decrypt(next_chunk, &source[i],
00305         decoded.access(), _key, RSA_PKCS1_PADDING);
00306     if (dec_size < 0) return false;  // that didn't work.
00307     decoded.zap(dec_size, decoded.last());
00308     target += decoded;
00309     decoded.reset(max_chunk);
00310   }
00311   return true;
00312 }
00313 
00314 } //namespace.
00315 
Generated on Sat Jan 28 04:22:18 2012 for hoople2 project by  doxygen 1.6.3