rsa_crypto.cpp

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

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