wvrsa.cc

00001 /*
00002  * Worldvisions Tunnel Vision Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * RSA cryptography abstractions.
00006  */
00007 #include <assert.h>
00008 #include <openssl/rsa.h>
00009 #include <openssl/pem.h>
00010 #include "wvsslhacks.h"
00011 #include "wvrsa.h"
00012 #include "wvhex.h"
00013 #include "wvfileutils.h"
00014 
00015 /***** WvRSAKey *****/
00016 
00017 WvRSAKey::WvRSAKey(const WvRSAKey &k)
00018 {
00019     if (k.prv)
00020         init(k.private_str(), true);
00021     else
00022         init(k.public_str(), false);
00023 }
00024 
00025 
00026 WvRSAKey::WvRSAKey(struct rsa_st *_rsa, bool priv)
00027 {
00028     if (_rsa == NULL)
00029     {
00030         // assert(_rsa);
00031         pub = WvString::null;
00032         prv = WvString::null;
00033         rsa = NULL;
00034         seterr("Initializing with a NULL key.. are you insane?");
00035         return;
00036     }
00037 
00038     rsa = _rsa;
00039     pub = hexifypub(rsa);
00040     if (priv)
00041         prv = hexifyprv(rsa);
00042 }
00043 
00044 
00045 WvRSAKey::WvRSAKey(WvStringParm keystr, bool priv)
00046 {
00047     init(keystr, priv);
00048 }
00049 
00050 
00051 WvRSAKey::WvRSAKey(int bits)
00052 {
00053     rsa = RSA_generate_key(bits, 0x10001, NULL, NULL);
00054     pub = hexifypub(rsa);
00055     prv = hexifyprv(rsa);
00056 }
00057 
00058 
00059 WvRSAKey::~WvRSAKey()
00060 {
00061     if (rsa)
00062         RSA_free(rsa);
00063 }
00064 
00065 
00066 bool WvRSAKey::isok() const
00067 {
00068    return rsa && !errstring && (!prv || RSA_check_key(rsa) == 1);
00069 }
00070 
00071 
00072 void WvRSAKey::init(WvStringParm keystr, bool priv)
00073 {
00074     // Start out with everything nulled out...
00075     rsa = NULL;
00076     pub = WvString::null;
00077     prv = WvString::null;
00078     
00079     // unhexify the supplied key
00080     WvDynBuf keybuf;
00081     if (!WvHexDecoder().flushstrbuf(keystr,  keybuf, true) ||
00082         keybuf.used() == 0)
00083     {
00084         seterr("RSA key is not a valid hex string");
00085         return;
00086     }
00087     
00088     size_t keylen = keybuf.used();
00089     const unsigned char *key = keybuf.get(keylen);
00090     
00091     // create the RSA struct
00092     if (priv)
00093     {
00094         rsa = wv_d2i_RSAPrivateKey(NULL, &key, keylen);
00095         if (rsa != NULL)
00096         {
00097             prv = keystr;
00098             pub = hexifypub(rsa);
00099         }
00100     }
00101     else
00102     {
00103         rsa = wv_d2i_RSAPublicKey(NULL, &key, keylen);
00104         if (rsa != NULL)
00105         {
00106             prv = WvString::null;
00107             pub = keystr;
00108         }
00109     }
00110     if (rsa == NULL)
00111         seterr("RSA key is invalid");
00112 }
00113 
00114 
00115 
00116 WvString WvRSAKey::getpem(bool privkey)
00117 {
00118     FILE *fp = wvtmpfile();
00119     const EVP_CIPHER *enc;
00120     
00121     if (!fp)
00122     {
00123         seterr("Unable to open temporary file!");
00124         return WvString::null;
00125     }
00126 
00127     if (privkey)
00128     {
00129         enc = EVP_get_cipherbyname("rsa");
00130         PEM_write_RSAPrivateKey(fp, rsa, enc,
00131                                NULL, 0, NULL, NULL);
00132     }
00133     else
00134     {
00135         enc = EVP_get_cipherbyname("rsa");
00136         PEM_write_RSAPublicKey(fp, rsa);
00137     }
00138     
00139     WvDynBuf b;
00140     size_t len;
00141     
00142     rewind(fp);
00143     while ((len = fread(b.alloc(1024), 1, 1024, fp)) > 0)
00144         b.unalloc(1024 - len);
00145     b.unalloc(1024 - len);
00146     fclose(fp);
00147 
00148     return b.getstr();
00149 }
00150 
00151 
00152 
00153 WvString WvRSAKey::hexifypub(struct rsa_st *rsa)
00154 {
00155     WvDynBuf keybuf;
00156 
00157     assert(rsa);
00158 
00159     size_t size = i2d_RSAPublicKey(rsa, NULL);
00160     unsigned char *key = keybuf.alloc(size);
00161     size_t newsize = i2d_RSAPublicKey(rsa, & key);
00162     assert(size == newsize);
00163     assert(keybuf.used() == size);
00164 
00165     return WvString(WvHexEncoder().strflushbuf(keybuf, true));
00166 }
00167 
00168 
00169 WvString WvRSAKey::hexifyprv(struct rsa_st *rsa)
00170 {
00171     WvDynBuf keybuf;
00172 
00173     assert(rsa);
00174 
00175     size_t size = i2d_RSAPrivateKey(rsa, NULL);
00176     unsigned char *key = keybuf.alloc(size);
00177     size_t newsize = i2d_RSAPrivateKey(rsa, & key);
00178     assert(size == newsize);
00179 
00180     return WvString(WvHexEncoder().strflushbuf(keybuf, true));
00181 }
00182 
00183 
00184 /***** WvRSAEncoder *****/
00185 
00186 WvRSAEncoder::WvRSAEncoder(Mode _mode, const WvRSAKey & _key) :
00187     mode(_mode), key(_key)
00188 {
00189     if (key.isok() && key.rsa != NULL)
00190         rsasize = RSA_size(key.rsa);
00191     else
00192         rsasize = 0; // BAD KEY! (should assert but would break compatibility)
00193 }
00194 
00195 
00196 WvRSAEncoder::~WvRSAEncoder()
00197 {
00198 }
00199 
00200 
00201 bool WvRSAEncoder::_reset()
00202 {
00203     return true;
00204 }
00205 
00206 
00207 bool WvRSAEncoder::_encode(WvBuf &in, WvBuf &out, bool flush)
00208 {
00209     if (rsasize == 0)
00210     {
00211         // IGNORE BAD KEY!
00212         in.zap();
00213         return false;
00214     }
00215         
00216     bool success = true;
00217     switch (mode)
00218     {
00219         case Encrypt:
00220         case SignEncrypt:
00221         {
00222             // reserve space for PKCS1_PADDING
00223             const size_t maxchunklen = rsasize - 12;
00224             size_t chunklen;
00225             while ((chunklen = in.used()) != 0)
00226             {
00227                 if (chunklen >= maxchunklen)
00228                     chunklen = maxchunklen;
00229                 else if (! flush)
00230                     break;
00231 
00232                 // encrypt a chunk
00233                 const unsigned char *data = in.get(chunklen);
00234                 unsigned char *crypt = out.alloc(rsasize);
00235                 size_t cryptlen = (mode == Encrypt) ?
00236                     RSA_public_encrypt(chunklen,
00237                     const_cast<unsigned char*>(data), crypt,
00238                     key.rsa, RSA_PKCS1_PADDING) :
00239                     RSA_private_encrypt(chunklen,
00240                     const_cast<unsigned char*>(data), crypt,
00241                     key.rsa, RSA_PKCS1_PADDING);
00242                 if (cryptlen != rsasize)
00243                 {
00244                     out.unalloc(rsasize);
00245                     success = false;
00246                 }
00247             }
00248             break;
00249         }
00250         case Decrypt:
00251         case SignDecrypt:
00252         {
00253             const size_t chunklen = rsasize;
00254             while (in.used() >= chunklen)
00255             {
00256                 // decrypt a chunk
00257                 const unsigned char *crypt = in.get(chunklen);
00258                 unsigned char *data = out.alloc(rsasize);
00259                 int cryptlen = (mode == Decrypt) ?
00260                     RSA_private_decrypt(chunklen,
00261                     const_cast<unsigned char*>(crypt), data,
00262                     key.rsa, RSA_PKCS1_PADDING) :
00263                     RSA_public_decrypt(chunklen,
00264                     const_cast<unsigned char*>(crypt), data,
00265                     key.rsa, RSA_PKCS1_PADDING);
00266                 if (cryptlen == -1)
00267                 {
00268                     out.unalloc(rsasize);
00269                     success = false;
00270                 }
00271                 else
00272                     out.unalloc(rsasize - cryptlen);
00273             }
00274             // flush does not make sense for us here
00275             if (flush && in.used() != 0)
00276                 success = false;
00277             break;
00278         }
00279     }
00280     return success;
00281 }
00282 
00283 
00284 /***** WvRSAStream *****/
00285 
00286 WvRSAStream::WvRSAStream(WvStream *_cloned,
00287     const WvRSAKey &_my_key, const WvRSAKey &_their_key,
00288     WvRSAEncoder::Mode readmode, WvRSAEncoder::Mode writemode) :
00289     WvEncoderStream(_cloned)
00290 {
00291     readchain.append(new WvRSAEncoder(readmode, _my_key), true);
00292     writechain.append(new WvRSAEncoder(writemode, _their_key), true);
00293     if (_my_key.isok() && _my_key.rsa)
00294         min_readsize = RSA_size(_my_key.rsa);
00295 }

Generated on Fri Oct 5 18:20:28 2007 for WvStreams by  doxygen 1.5.3