WvStreams
wvblowfish.cc
00001 /*
00002  * Worldvisions Tunnel Vision Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * Blowfish cryptography abstractions.
00006  */
00007 #include "wvblowfish.h"
00008 #include <assert.h>
00009 #include <openssl/rand.h>
00010 #include <openssl/blowfish.h>
00011 
00012 /***** WvBlowfishEncoder ****/
00013 
00014 WvBlowfishEncoder::WvBlowfishEncoder(Mode _mode,
00015     const void *_key, size_t _keysize) :
00016     mode(_mode), key(NULL), bfkey(NULL)
00017 {
00018     setkey(_key, _keysize);
00019 }
00020 
00021 
00022 WvBlowfishEncoder::~WvBlowfishEncoder()
00023 {
00024     deletev key;
00025     delete bfkey;
00026 }
00027 
00028 
00029 bool WvBlowfishEncoder::_reset()
00030 {
00031     preparekey();
00032     return true;
00033 }
00034 
00035 
00036 void WvBlowfishEncoder::setkey(const void *_key, size_t _keysize)
00037 {
00038     deletev key;
00039     keysize = _keysize;
00040     key = new unsigned char[keysize];
00041     memcpy(key, _key, keysize);
00042     preparekey();
00043 }
00044 
00045 
00046 void WvBlowfishEncoder::setiv(const void *_iv)
00047 {
00048     memcpy(ivec, _iv, sizeof(ivec));
00049     ivecoff = 0;
00050 }
00051 
00052 
00053 void WvBlowfishEncoder::preparekey()
00054 {
00055     delete bfkey;
00056     bfkey = new BF_KEY;
00057     BF_set_key(bfkey, keysize, key);
00058     memset(ivec, 0, sizeof(ivec));
00059     ivecoff = 0;
00060 }
00061 
00062 
00063 bool WvBlowfishEncoder::_encode(WvBuf &in, WvBuf &out, bool flush)
00064 {
00065     size_t len = in.used();
00066     bool success = true;
00067     switch (mode) {
00068         case ECBEncrypt:
00069         case ECBDecrypt:
00070         {
00071             size_t remainder = len & 7;
00072             len -= remainder;
00073             if (remainder != 0 && flush)
00074             {
00075                 if (mode == ECBEncrypt)
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     if (len == 0) return success;
00092     
00093     const unsigned char *data = in.get(len);
00094     unsigned char *crypt = out.alloc(len);
00095     
00096     switch (mode)
00097     {
00098         case ECBEncrypt:
00099         case ECBDecrypt:
00100             // ECB works 64bits at a time
00101             while (len >= 8)
00102             {
00103                 BF_ecb_encrypt(data, crypt, bfkey,
00104                     mode == ECBEncrypt ? BF_ENCRYPT : BF_DECRYPT);
00105                 len -= 8;
00106                 data += 8;
00107                 crypt += 8;
00108             }
00109             break;
00110 
00111         case CFBEncrypt:
00112         case CFBDecrypt:
00113             // CFB simulates a stream
00114             BF_cfb64_encrypt(data, crypt, len, bfkey, ivec, &ivecoff,
00115                 mode == CFBEncrypt ? BF_ENCRYPT : BF_DECRYPT);
00116             break;
00117     }
00118     return success;
00119 }
00120 
00121 
00122 /***** WvBlowfishStream *****/
00123 
00124 WvBlowfishStream::WvBlowfishStream(WvStream *_cloned,
00125     const void *_key, size_t _keysize,
00126     WvBlowfishEncoder::Mode readmode, WvBlowfishEncoder::Mode writemode) :
00127     WvEncoderStream(_cloned)
00128 {
00129     readchain.append(new WvBlowfishEncoder(readmode,
00130         _key, _keysize), true);
00131     writechain.append(new WvBlowfishEncoder(writemode,
00132         _key, _keysize), true);
00133 }