Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvrsa.cc

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

Generated on Sat Feb 21 21:05:31 2004 for WvStreams by doxygen 1.3.5