Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

wvcrypto.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  * Streams with built-in cryptography on read/write.  See wvcrypto.h.
00006  */
00007 #include "wvcrypto.h"
00008 #include "strutils.h"
00009 #include <assert.h>
00010 #include <blowfish.h>
00011 #include <rsa.h>
00012 #include <md5.h>
00013 
00014 
00016 
00017 
00018 
00019 WvCryptoStream::WvCryptoStream(WvStream *_slave) : WvStreamClone(&slave)
00020 {
00021     slave = _slave;
00022     my_cryptbuf = NULL;
00023     cryptbuf_size = 0;
00024 }
00025 
00026 
00027 WvCryptoStream::~WvCryptoStream()
00028 {
00029     // nothing special
00030 }
00031 
00032 
00033 unsigned char *WvCryptoStream::cryptbuf(size_t size)
00034 {
00035     if (size > cryptbuf_size)
00036     {
00037         if (my_cryptbuf)
00038             delete[] my_cryptbuf;
00039         cryptbuf_size = size;
00040         my_cryptbuf = new unsigned char[size];
00041     }
00042     
00043     return my_cryptbuf;
00044 }
00045 
00046 
00048 
00049 
00050 
00051 WvXORStream::WvXORStream(WvStream *_slave, unsigned char _xorvalue)
00052                 : WvCryptoStream(_slave)
00053 {
00054     xorvalue = _xorvalue;
00055 }
00056 
00057 
00058 size_t WvXORStream::uwrite(const void *buf, size_t size)
00059 {
00060     unsigned char *out = cryptbuf(size);
00061     const unsigned char *i = (const unsigned char *)buf;
00062     unsigned char *o = out;
00063     size_t count;
00064     
00065     for (count = 0; count < size; count++)
00066         *o++ = (*i++) ^ xorvalue;
00067     
00068     return WvCryptoStream::uwrite(out, size);
00069 }
00070 
00071 
00072 size_t WvXORStream::uread(void *buf, size_t size)
00073 {
00074     unsigned char *in = cryptbuf(size);
00075     const unsigned char *i = (const unsigned char *)in;
00076     unsigned char *o = (unsigned char *)buf;
00077     size_t count;
00078     
00079     size = WvCryptoStream::uread(in, size);
00080     
00081     for (count = 0; count < size; count++)
00082         *o++ = (*i++) ^ xorvalue;
00083     return size;
00084 }
00085 
00086 
00087 
00089 
00090 
00091 
00092 WvBlowfishStream::WvBlowfishStream(WvStream *_slave, const void *_key,
00093                                    size_t keysize)
00094                 : WvCryptoStream(_slave)
00095 {
00096     key = new BF_KEY;
00097     BF_set_key(key, keysize, (unsigned char *)_key);
00098     ennum = denum = 0;
00099     memset(envec, 0, sizeof(envec));
00100     memset(devec, 0, sizeof(devec));
00101 }
00102 
00103 
00104 size_t WvBlowfishStream::uwrite(const void *buf, size_t size)
00105 {
00106     void *out = cryptbuf(size);
00107     
00108     BF_cfb64_encrypt((unsigned char *)buf,
00109                      (unsigned char *)out, size, key,
00110                      envec, &ennum, BF_ENCRYPT);
00111     
00112     return WvCryptoStream::uwrite(out, size);
00113 }
00114 
00115 
00116 size_t WvBlowfishStream::uread(void *buf, size_t size)
00117 {
00118     void *in = cryptbuf(size);
00119     size = WvCryptoStream::uread(in, size);
00120     
00121     BF_cfb64_encrypt((unsigned char *)in,
00122                      (unsigned char *)buf, size, key,
00123                      devec, &denum, BF_DECRYPT);
00124     
00125     return size;
00126 }
00127 
00128 
00129 WvBlowfishStream::~WvBlowfishStream()
00130 {
00131     delete key;
00132 }
00133 
00134 
00135 
00137 
00138 
00139 
00140 WvRSAKey::WvRSAKey(const char *_keystr, bool priv)
00141 {
00142     // the ssl library segfaults if the buffer isn't big enough and our key
00143     // is unexpectedly short... sigh.  There's probably a security hole
00144     // somewhere in the fact that an invalid key can segfault the library.
00145     int hexbytes = strlen(_keystr);
00146     int bufsize = ((hexbytes < 2048) ? 2048 : hexbytes) + 16;
00147     //int bufsize = hexbytes/2;
00148     
00149     unsigned char *keybuf = new unsigned char[bufsize], *bufp;
00150     char *keystr;
00151     RSA *rp;
00152     
00153     keystr = strdup(_keystr);
00154     
00155     memset(keybuf, 0, bufsize);
00156     unhexify(keybuf, keystr);
00157     bufp = keybuf;
00158     rp = rsa = RSA_new();
00159     
00160     if (priv)
00161     {
00162         rsa = d2i_RSAPrivateKey(&rp, &bufp, hexbytes/2);
00163         prv = keystr;
00164         
00165         size_t size;
00166         unsigned char *iend = keybuf;
00167         size = i2d_RSAPublicKey(rsa, &iend);
00168         pub = (char *)malloc(size * 2 + 1);
00169         hexify(pub, keybuf, size);
00170     }
00171     else
00172     {
00173         rsa = d2i_RSAPublicKey(&rp, &bufp, hexbytes/2);
00174         prv = NULL;
00175         pub = keystr;
00176     }
00177     
00178     delete[] keybuf;
00179 }
00180 
00181 
00182 WvRSAKey::WvRSAKey(int bits)
00183 {
00184     size_t size;
00185     unsigned char *keybuf, *iend;
00186     
00187     rsa = RSA_generate_key(bits, 3, NULL, NULL);
00188     
00189     size = i2d_RSAPrivateKey(rsa, NULL);
00190     iend = keybuf = new unsigned char[size];
00191     i2d_RSAPrivateKey(rsa, &iend);
00192     
00193     prv = (char *)malloc(size * 2 + 1);
00194     hexify(prv, keybuf, size);
00195     
00196     iend = keybuf;
00197     size = i2d_RSAPublicKey(rsa, &iend);
00198     
00199     pub = (char *)malloc(size * 2 + 1);
00200     hexify(pub, keybuf, size);
00201     
00202     delete[] keybuf;
00203 }
00204 
00205 
00206 WvRSAKey::~WvRSAKey()
00207 {
00208     if (prv)
00209         free(prv);
00210     if (pub)
00211         free(pub);
00212     if (rsa)
00213         RSA_free(rsa);
00214 }
00215 
00216 
00217 
00219 
00220 
00221 
00222 WvRSAStream::WvRSAStream(WvStream *_slave,
00223                          WvRSAKey &_my_key, WvRSAKey &_their_key)
00224                 : WvCryptoStream(_slave),
00225                   my_key(_my_key.private_str(), true),
00226                   their_key(_their_key.public_str(), false)
00227 {
00228     // we always want to read encrypted data in multiples of RSA_size.
00229     if (my_key.rsa)
00230         slave->queuemin(RSA_size(my_key.rsa));
00231 }
00232 
00233 
00234 WvRSAStream::~WvRSAStream()
00235 {
00236     // remove our strange queuing requirements
00237     slave->queuemin(0);
00238 }
00239 
00240 
00241 // this function has _way_ too many confusing temporary buffers... but RSA
00242 // can only deal with big chunks of data, and wvstreams doesn't expect that.
00243 size_t WvRSAStream::uread(void *buf, size_t size)
00244 {
00245     unsigned char *in = cryptbuf(size);
00246     
00247     if (!my_key.rsa)
00248     {
00249         // make sure we read the data, even if we'll discard it
00250         WvStreamClone::uread(buf, size);
00251         return 0;
00252     }
00253     
00254     size_t len, decode_len, rsa_size = RSA_size(my_key.rsa);
00255     
00256     if (size > rsa_size)
00257         size = rsa_size;
00258     
00259     len = WvStreamClone::uread(in, rsa_size);
00260     if (len < rsa_size)
00261     {
00262         // didn't get a full packet - should never really happen, since
00263         // we use queuemin()...
00264         return 0;
00265     }
00266     
00267     // decrypt the data
00268     unsigned char *decoded = new unsigned char[rsa_size];
00269     decode_len = RSA_private_decrypt(len, in, decoded,
00270                                      my_key.rsa, RSA_PKCS1_PADDING);
00271     
00272     if (decode_len == (size_t)-1)
00273         return 0; // error in decoding!
00274     
00275     // return up to "size" bytes in the main buffer
00276     if (decode_len < size)
00277         size = decode_len;
00278     memcpy(buf, decoded, size);
00279     
00280     // save the remainder in inbuf
00281     inbuf.put(decoded+size, decode_len - size);
00282     
00283     delete decoded;
00284     return size;
00285 }
00286 
00287 
00288 size_t WvRSAStream::uwrite(const void *buf, size_t size)
00289 {
00290     if (!their_key.rsa)
00291     {
00292         // invalid key; just pretend to write so we don't get stuff stuck
00293         // in the buffer.
00294         return size; 
00295     }
00296     
00297     size_t off, len, totalwrite = 0, rsa_size = RSA_size(my_key.rsa), outsz;
00298     unsigned char *out = cryptbuf(rsa_size);
00299     
00300     // break it into blocks of no more than rsa_size each
00301     for (off = 0; off < size; off += rsa_size/2)
00302     {
00303         if (size-off < rsa_size/2)
00304             len = size-off;
00305         else
00306             len = rsa_size/2;
00307         
00308         outsz = RSA_public_encrypt(len, (unsigned char *)buf+off, out,
00309                                    their_key.rsa, RSA_PKCS1_PADDING);
00310         assert(outsz == rsa_size);
00311         
00312         // FIXME: this isn't really correct.  If uwrite() doesn't manage to
00313         // write the _entire_ blob at once, we throw out the rest but
00314         // claim it got written...
00315         if (WvStreamClone::uwrite(out, outsz))
00316             totalwrite += len;
00317     }
00318     
00319     return totalwrite;
00320 }
00321 
00322 WvMD5::WvMD5(const WvString &string_to_hash)
00323 {
00324     MD5_CTX ctx;
00325     unsigned char temp[20];
00326 
00327     MD5_Init(&ctx);
00328     MD5_Update(&ctx,(const unsigned char *)string_to_hash.cstr(),
00329                 strlen(string_to_hash));
00330     MD5_Final(temp, &ctx);
00331     md5_hash_value = (unsigned char *)calloc(1,sizeof(temp));
00332     memcpy(md5_hash_value,temp,sizeof(temp));
00333 }
00334 
00335 WvMD5::WvMD5(FILE *file_to_hash)
00336 {
00337     unsigned char buf[1024];
00338     unsigned char temp[20];
00339     MD5_CTX ctx;
00340     int n;
00341 
00342     MD5_Init(&ctx);
00343     while ((n = fread(buf, 1, sizeof(buf), file_to_hash)) > 0)
00344             MD5_Update(&ctx, buf, n);
00345     MD5_Final(temp, &ctx);
00346     if (ferror(file_to_hash))
00347         md5_hash_value = NULL;
00348     else
00349     {
00350         md5_hash_value = (unsigned char *)calloc(1,sizeof(temp));
00351         memcpy(md5_hash_value,temp,sizeof(temp));
00352     }
00353 }
00354 
00355 WvMD5::~WvMD5()
00356 {
00357     free(md5_hash_value);
00358 }
00359 
00360 WvString WvMD5::md5_hash() const
00361 {
00362     int count;
00363     unsigned char *temp;
00364     WvString hash_value("");
00365 
00366     temp = md5_hash_value;
00367     for (count = 0; count < 16; count++)
00368     {
00369         char buf[2];
00370         snprintf(buf,2,"%02x", *temp++);
00371         hash_value.append(buf);
00372     }
00373 
00374     return hash_value;
00375 }

Generated on Fri Apr 5 15:16:51 2002 for WvStreams by doxygen1.2.15