WvStreams
wvtripledes.cc
00001 /*
00002  * Worldvisions Tunnel Vision Software:
00003  *   Copyright (C) 1997-2003 Net Integration Technologies, Inc.
00004  * 
00005  * TripleDES cryptography abstractions.
00006  */
00007 #include "wvtripledes.h"
00008 #include <assert.h>
00009 #include <openssl/rand.h>
00010 
00011 /***** WvTripleDESEncoder ****/
00012 
00013 WvTripleDESEncoder::WvTripleDESEncoder(Mode _mode, const void *_key1, 
00014                                        const void *_key2, const void *_key3) :
00015     mode(_mode)
00016 {
00017     setkey(_key1, _key2, _key3);
00018 }
00019 
00020 
00021 // WvTripleDESEncoder::~WvTripleDESEncoder()
00022 // {
00023 //     delete[] key;
00024 //     delete deskey1;
00025 //     delete deskey2;
00026 //     delete deskey3;
00027 // }
00028 
00029 
00030 bool WvTripleDESEncoder::_reset()
00031 {
00032     memset(ivec, 0, sizeof(ivec));
00033     ivecoff = 0;
00034     return true;
00035 }
00036 
00037 
00038 void WvTripleDESEncoder::setkey(const void *_key1, const void *_key2, 
00039                                 const void *_key3)
00040 {
00041     memcpy(key, _key1, DES_KEY_SZ);
00042     DES_set_key(&key, &deskey1);
00043 
00044     memcpy(key, _key2, DES_KEY_SZ);
00045     DES_set_key(&key, &deskey2);
00046 
00047     memcpy(key, _key3, DES_KEY_SZ);
00048     DES_set_key(&key, &deskey3);
00049 
00050     memset(ivec, 0, sizeof(ivec));
00051     ivecoff = 0;
00052 }
00053 
00054 
00055 void WvTripleDESEncoder::setiv(const void *_iv)
00056 {
00057     memcpy(ivec, _iv, sizeof(ivec));
00058     ivecoff = 0;
00059 }
00060 
00061 bool WvTripleDESEncoder::_encode(WvBuf &in, WvBuf &out, bool flush)
00062 {
00063     size_t len = in.used();
00064     bool success = true;
00065     switch (mode) {
00066     case ECBEncrypt:
00067     case ECBDecrypt:
00068     case CBCEncrypt: // The caller should ensure the padding is correct or
00069     case CBCDecrypt: // we do it for them, in probably the wrong way.
00070     {
00071         size_t remainder = len & 7; // conviently this is the same as len % 8
00072         len -= remainder;
00073         if (remainder != 0 && flush)
00074         {
00075             if (mode == ECBEncrypt || mode == CBCEncrypt)
00076             {
00077                 // if flushing on encryption, add some randomized padding
00078                 size_t padlen = 8 - remainder;
00079                 unsigned char *pad = in.alloc(padlen);
00080                 RAND_pseudo_bytes(pad, padlen);
00081                 len += 8;
00082             }
00083             else // nothing we can do here, flushing does not make sense!
00084                 success = false;
00085         }
00086     }
00087 
00088     default:
00089         break;
00090     }
00091 
00092     if (len == 0) 
00093         return success;
00094     
00095     const unsigned char *data = in.get(len);
00096     unsigned char *crypt = out.alloc(len);
00097     
00098     switch (mode)
00099     {
00100     case ECBEncrypt:
00101     case ECBDecrypt:
00102         // ECB works 64bits at a time
00103         while (len >= 8)
00104         {
00105 #if OPENSSL_VERSION_NUMBER >= 0x0090705fL \
00106     && OPENSSL_VERSION_NUMBER < 0x0090800fL
00107             DES_ecb3_encrypt(data, crypt,
00108                              &deskey1, &deskey2, &deskey3,
00109                              mode == ECBEncrypt ? DES_ENCRYPT : DES_DECRYPT);
00110 #else
00111             DES_ecb3_encrypt(reinterpret_cast<const_DES_cblock*>(&data),
00112                              reinterpret_cast<DES_cblock*>(&crypt),
00113                              &deskey1, &deskey2, &deskey3,
00114                              mode == ECBEncrypt ? DES_ENCRYPT : DES_DECRYPT);
00115 #endif
00116             len -= 8;
00117             data += 8;
00118             crypt += 8;
00119         }
00120         break;
00121 
00122     case CFBEncrypt:
00123     case CFBDecrypt:
00124         // CFB simulates a stream
00125         DES_ede3_cfb64_encrypt(data, crypt, len, &deskey1, &deskey2, &deskey3,
00126                                &ivec, &ivecoff,
00127                                mode == CFBEncrypt ? DES_ENCRYPT : DES_DECRYPT);
00128         break;
00129     case CBCEncrypt:
00130         DES_ede3_cbc_encrypt(data, crypt, len, &deskey1, &deskey2, &deskey3,
00131                              &ivec, DES_ENCRYPT);
00132         break;
00133     case CBCDecrypt:
00134         DES_ede3_cbc_encrypt(data, crypt, len, &deskey1, &deskey2, &deskey3,
00135                              &ivec, DES_DECRYPT);
00136         break;
00137     }
00138     return success;
00139 }
00140 
00141 
00142 /***** WvTripleDESStream *****/
00143 
00144 WvTripleDESStream::WvTripleDESStream(WvStream *_cloned, const void *_key1,
00145                                      const void *_key2, const void *_key3, 
00146                                      WvTripleDESEncoder::Mode readmode, 
00147                                      WvTripleDESEncoder::Mode writemode) :
00148     WvEncoderStream(_cloned)
00149 {
00150     readchain.append(new WvTripleDESEncoder(readmode,
00151                                             _key1, _key2, _key3), true);
00152     writechain.append(new WvTripleDESEncoder(writemode,
00153                                              _key1, _key2, _key3), true);
00154 }