summaryrefslogtreecommitdiffstats
path: root/src/modules/rijndael/libkvirijndael.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/rijndael/libkvirijndael.cpp')
-rw-r--r--src/modules/rijndael/libkvirijndael.cpp853
1 files changed, 853 insertions, 0 deletions
diff --git a/src/modules/rijndael/libkvirijndael.cpp b/src/modules/rijndael/libkvirijndael.cpp
new file mode 100644
index 00000000..0a678437
--- /dev/null
+++ b/src/modules/rijndael/libkvirijndael.cpp
@@ -0,0 +1,853 @@
+//
+// File : libkvirijndael.cpp
+// Creation date : Sat Now 4 2000 15:33:12 CEST by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2000 Till Bush ([email protected])
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// This program is distributed in the HOPE that it will be USEFUL,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+
+#include "libkvirijndael.h"
+
+#include "rijndael.h"
+
+#include "kvi_module.h"
+#include "kvi_debug.h"
+#include "kvi_locale.h"
+
+#include "kvi_mirccntrl.h"
+#include "kvi_time.h"
+
+//#warning "Other engines: mircStrip koi2win colorizer lamerizer etc.."
+
+/*
+ @doc: rijndael
+ @type:
+ module
+ @short:
+ The Rijndael cryptographic engines
+ @title:
+ The rijndael module
+ @body:
+ The rijndael module exports six [doc:crypt_engines]cryptographic engines[/doc] based
+ on the Advanced Encryptiong Standard algorithm called Rijndael. Rijndael was
+ originally written by Joan Daemen and Vincent Rijmen. The original Rijndael
+ description is available at http://www.esat.kuleuven.ac.be/~rijmen/rijndael/.[br]
+ It is a private key block cipher that has been designed to replace
+ the widely used DES, and it should provide at leas a decent security agains
+ common attacks. Theoretically the best attack that one can perform on this cipher
+ is the "brute force" attack that requires a really massive parallel computation:
+ actually out of the possibilities of a common "hacker".[br]
+ My implementation allows the usage of 128, 192 and 256 bit keys
+ on 128 bit data blocks. The encrypted binary data buffer is then converted
+ into an ascii-string by using the base64 conversion or hex-digit-string rappresentation.
+ The six engines are the six possible combinations of the key lengths and ascii-string
+ conversions.
+*/
+
+
+
+#ifdef COMPILE_CRYPT_SUPPORT
+
+ #include "kvi_memmove.h"
+ #include "kvi_malloc.h"
+
+ #include "kvi_pointerlist.h"
+
+ static KviPointerList<KviCryptEngine> * g_pEngineList = 0;
+
+
+
+
+ KviRijndaelEngine::KviRijndaelEngine()
+ : KviCryptEngine()
+ {
+ g_pEngineList->append(this);
+ m_pEncryptCipher = 0;
+ m_pDecryptCipher = 0;
+ }
+
+ KviRijndaelEngine::~KviRijndaelEngine()
+ {
+ g_pEngineList->removeRef(this);
+ if(m_pEncryptCipher)delete m_pEncryptCipher;
+ if(m_pDecryptCipher)delete m_pDecryptCipher;
+ }
+
+ bool KviRijndaelEngine::init(const char *encKey,int encKeyLen,const char *decKey,int decKeyLen)
+ {
+ if(m_pEncryptCipher)
+ {
+ delete m_pEncryptCipher;
+ m_pEncryptCipher = 0;
+ }
+ if(m_pDecryptCipher)
+ {
+ delete m_pDecryptCipher;
+ m_pDecryptCipher = 0;
+ }
+
+ if(encKey && (encKeyLen > 0))
+ {
+ if(!(decKey && (decKeyLen > 0)))
+ {
+ decKey = encKey;
+ decKeyLen = encKeyLen;
+ } // else all
+ } else {
+ // no encrypt key specified...
+ if(decKey && decKeyLen)
+ {
+ encKey = decKey;
+ encKeyLen = decKeyLen;
+ } else {
+ // both keys missing
+ setLastError(__tr("Missing both encrypt and decrypt key: at least one is needed"));
+ return false;
+ }
+ }
+
+ int defLen = getKeyLen();
+
+ char * encryptKey = (char *)kvi_malloc(defLen);
+ char * decryptKey = (char *)kvi_malloc(defLen);
+
+ if(encKeyLen > defLen)encKeyLen = defLen;
+ kvi_memmove(encryptKey,encKey,encKeyLen);
+ if(encKeyLen < defLen)kvi_memset(encryptKey + encKeyLen,'0',defLen - encKeyLen);
+
+ if(decKeyLen > defLen)decKeyLen = defLen;
+ kvi_memmove(decryptKey,decKey,decKeyLen);
+ if(decKeyLen < defLen)kvi_memset(decryptKey + decKeyLen,'0',defLen - decKeyLen);
+
+ m_pEncryptCipher = new Rijndael();
+ int retVal = m_pEncryptCipher->init(Rijndael::CBC,Rijndael::Encrypt,(unsigned char *)encryptKey,getKeyLenId());
+ kvi_free(encryptKey);
+ if(retVal != RIJNDAEL_SUCCESS)
+ {
+ kvi_free(decryptKey);
+ delete m_pEncryptCipher;
+ m_pEncryptCipher = 0;
+ setLastErrorFromRijndaelErrorCode(retVal);
+ return false;
+ }
+
+ m_pDecryptCipher = new Rijndael();
+ retVal = m_pDecryptCipher->init(Rijndael::CBC,Rijndael::Decrypt,(unsigned char *)decryptKey,getKeyLenId());
+ kvi_free(decryptKey);
+ if(retVal != RIJNDAEL_SUCCESS)
+ {
+ delete m_pEncryptCipher;
+ m_pEncryptCipher = 0;
+ delete m_pDecryptCipher;
+ m_pDecryptCipher = 0;
+ setLastErrorFromRijndaelErrorCode(retVal);
+ return false;
+ }
+
+ return true;
+ }
+
+ void KviRijndaelEngine::setLastErrorFromRijndaelErrorCode(int errCode)
+ {
+ switch(errCode)
+ {
+ case RIJNDAEL_SUCCESS: setLastError(__tr("Error 0: Success ?")); break;
+ case RIJNDAEL_UNSUPPORTED_MODE: setLastError(__tr("Unsupported crypt mode")); break;
+ case RIJNDAEL_UNSUPPORTED_DIRECTION: setLastError(__tr("Unsupported direction")); break;
+ case RIJNDAEL_UNSUPPORTED_KEY_LENGTH: setLastError(__tr("Unsupported key length")); break;
+ case RIJNDAEL_BAD_KEY: setLastError(__tr("Bad key data")); break;
+ case RIJNDAEL_NOT_INITIALIZED: setLastError(__tr("Engine not initialized")); break;
+ case RIJNDAEL_BAD_DIRECTION: setLastError(__tr("Invalid direction for this engine")); break;
+ case RIJNDAEL_CORRUPTED_DATA: setLastError(__tr("Corrupted message data or invalid decrypt key")); break;
+ default: setLastError(__tr("Unknown error")); break;
+ }
+ }
+
+ KviCryptEngine::EncryptResult KviRijndaelEngine::encrypt(const char * plainText,KviStr &outBuffer)
+ {
+ if(!m_pEncryptCipher)
+ {
+ setLastError(__tr("Ops...encrypt cipher not initialized"));
+ return KviCryptEngine::EncryptError;
+ }
+ int len = (int)kvi_strLen(plainText);
+ char * buf = (char *)kvi_malloc(len + 16);
+
+ int retVal = m_pEncryptCipher->padEncrypt((const unsigned char *)plainText,len,(unsigned char *)buf);
+ if(retVal < 0)
+ {
+ kvi_free(buf);
+ setLastErrorFromRijndaelErrorCode(retVal);
+ return KviCryptEngine::EncryptError;
+ }
+
+ if(!binaryToAscii(buf,retVal,outBuffer))
+ {
+ kvi_free(buf);
+ return KviCryptEngine::EncryptError;
+ }
+ kvi_free(buf);
+
+ if(outBuffer.len() > maxEncryptLen())
+ {
+ if(maxEncryptLen() > 0)
+ {
+ setLastError(__tr("Data buffer too long"));
+ return KviCryptEngine::EncryptError;
+ }
+ }
+ outBuffer.prepend(KVI_TEXT_CRYPTESCAPE);
+ return KviCryptEngine::Encrypted;
+ }
+
+ KviCryptEngine::DecryptResult KviRijndaelEngine::decrypt(const char * inBuffer,KviStr &plainText)
+ {
+ if(!m_pDecryptCipher)
+ {
+ setLastError(__tr("Ops...decrypt cipher not initialized"));
+ return KviCryptEngine::DecryptError;
+ }
+
+ if(*inBuffer != KVI_TEXT_CRYPTESCAPE)
+ {
+ plainText = inBuffer;
+ return KviCryptEngine::DecryptOkWasPlainText;
+ }
+
+ inBuffer++;
+
+ if(!*inBuffer)
+ {
+ plainText = inBuffer;
+ return KviCryptEngine::DecryptOkWasPlainText; // empty buffer
+ }
+
+ int len;
+ char * binary;
+
+ if(!asciiToBinary(inBuffer,&len,&binary))return KviCryptEngine::DecryptError;
+
+ char * buf = (char *)kvi_malloc(len + 1);
+
+ int retVal = m_pDecryptCipher->padDecrypt((const unsigned char *)binary,len,(unsigned char *)buf);
+ kvi_free(binary);
+
+ if(retVal < 0)
+ {
+ kvi_free(buf);
+ setLastErrorFromRijndaelErrorCode(retVal);
+ return KviCryptEngine::DecryptError;
+ }
+
+ buf[retVal] = '\0';
+
+ plainText = buf;
+
+ kvi_free(buf);
+ return KviCryptEngine::DecryptOkWasEncrypted;
+ }
+
+ bool KviRijndaelHexEngine::binaryToAscii(const char * inBuffer,int len,KviStr &outBuffer)
+ {
+ outBuffer.bufferToHex(inBuffer,len);
+ return true;
+ }
+
+ bool KviRijndaelHexEngine::asciiToBinary(const char * inBuffer,int * len,char ** outBuffer)
+ {
+ KviStr hex(inBuffer);
+ char * tmpBuf;
+ *len = hex.hexToBuffer(&tmpBuf,false);
+ if(*len < 0)
+ {
+ setLastError(__tr("The message is not a hexadecimal string: this is not my stuff"));
+ return false;
+ } else {
+ if(len > 0)
+ {
+ *outBuffer = (char *)kvi_malloc(*len);
+ kvi_memmove(*outBuffer,tmpBuf,*len);
+ KviStr::freeBuffer(tmpBuf);
+ }
+ }
+ return true;
+ }
+
+ bool KviRijndaelBase64Engine::binaryToAscii(const char * inBuffer,int len,KviStr &outBuffer)
+ {
+ outBuffer.bufferToBase64(inBuffer,len);
+ return true;
+ }
+
+ bool KviRijndaelBase64Engine::asciiToBinary(const char * inBuffer,int * len,char ** outBuffer)
+ {
+ KviStr base64(inBuffer);
+ char * tmpBuf;
+ *len = base64.base64ToBuffer(&tmpBuf,false);
+ if(*len < 0)
+ {
+ setLastError(__tr("The message is not a base64 string: this is not my stuff"));
+ return false;
+ } else {
+ if(len > 0)
+ {
+ *outBuffer = (char *)kvi_malloc(*len);
+ kvi_memmove(*outBuffer,tmpBuf,*len);
+ KviStr::freeBuffer(tmpBuf);
+ }
+ }
+ return true;
+ }
+
+ static KviCryptEngine * allocRijndael128HexEngine()
+ {
+ return new KviRijndael128HexEngine();
+ }
+
+ static KviCryptEngine * allocRijndael192HexEngine()
+ {
+ return new KviRijndael192HexEngine();
+ }
+
+ static KviCryptEngine * allocRijndael256HexEngine()
+ {
+ return new KviRijndael256HexEngine();
+ }
+
+ static KviCryptEngine * allocRijndael128Base64Engine()
+ {
+ return new KviRijndael128Base64Engine();
+ }
+
+ static KviCryptEngine * allocRijndael192Base64Engine()
+ {
+ return new KviRijndael192Base64Engine();
+ }
+
+ static KviCryptEngine * allocRijndael256Base64Engine()
+ {
+ return new KviRijndael256Base64Engine();
+ }
+
+ static void deallocRijndaelCryptEngine(KviCryptEngine * e)
+ {
+ delete e;
+ }
+
+
+
+
+
+ // Mircryption stuff
+
+ #include "ablowfish.h"
+
+ KviMircryptionEngine::KviMircryptionEngine()
+ : KviCryptEngine()
+ {
+ g_pEngineList->append(this);
+ }
+
+ KviMircryptionEngine::~KviMircryptionEngine()
+ {
+ g_pEngineList->removeRef(this);
+ }
+
+ bool KviMircryptionEngine::init(const char * encKey,int encKeyLen,const char * decKey,int decKeyLen)
+ {
+ if(encKey && (encKeyLen > 0))
+ {
+ if(!(decKey && (decKeyLen > 0)))
+ {
+ decKey = encKey;
+ decKeyLen = encKeyLen;
+ } // else all
+ } else {
+ // no encrypt key specified...
+ if(decKey && decKeyLen)
+ {
+ encKey = decKey;
+ encKeyLen = decKeyLen;
+ } else {
+ // both keys missing
+ setLastError(__tr("Missing both encrypt and decrypt key: at least one is needed"));
+ return false;
+ }
+ }
+ m_szEncryptKey = KviStr(encKey,encKeyLen);
+ m_szDecryptKey = KviStr(decKey,decKeyLen);
+ if(kvi_strEqualCIN("cbc:",m_szEncryptKey.ptr(),4) && (m_szEncryptKey.len() > 4))
+ m_szEncryptKey.cutLeft(4);
+ else
+ m_bEncryptCBC = false;
+ if(kvi_strEqualCIN("cbc:",m_szDecryptKey.ptr(),4) && (m_szDecryptKey.len() > 4))
+ m_szDecryptKey.cutLeft(4);
+ else
+ m_bDecryptCBC = false;
+ return true;
+ }
+
+ KviCryptEngine::EncryptResult KviMircryptionEngine::encrypt(const char * plainText,KviStr &outBuffer)
+ {
+ KviStr szPlain = plainText;
+ outBuffer = "";
+ if(m_bEncryptCBC)
+ {
+ if(!doEncryptCBC(szPlain,outBuffer))return KviCryptEngine::EncryptError;
+ } else {
+ if(!doEncryptECB(szPlain,outBuffer))return KviCryptEngine::EncryptError;
+ }
+ outBuffer.prepend("+OK ");
+
+ if(outBuffer.len() > maxEncryptLen())
+ {
+ if(maxEncryptLen() > 0)
+ {
+ setLastError(__tr("Data buffer too long"));
+ return KviCryptEngine::EncryptError;
+ }
+ }
+
+ //outBuffer = MCPS2_STARTTAG;
+ //outBuffer += MCPS2_ENDTAG;
+ return KviCryptEngine::Encrypted;
+ }
+
+ KviCryptEngine::DecryptResult KviMircryptionEngine::decrypt(const char * inBuffer,KviStr &plainText)
+ {
+ plainText = "";
+ KviStr szIn = inBuffer;
+ // various old versions
+ if(kvi_strEqualCSN(inBuffer,"mcps ",5))
+ szIn.cutLeft(5);
+ else if(kvi_strEqualCSN(inBuffer,"+OK ",4))
+ szIn.cutLeft(4);
+ else {
+ plainText = szIn;
+ return KviCryptEngine::DecryptOkWasPlainText;
+ }
+
+ if(m_bDecryptCBC)return doDecryptCBC(szIn,plainText) ? KviCryptEngine::DecryptOkWasEncrypted : KviCryptEngine::DecryptError;
+ return doDecryptECB(szIn,plainText) ? KviCryptEngine::DecryptOkWasEncrypted : KviCryptEngine::DecryptError;
+
+ /*
+ int len1 = kvi_strLen(MCPS2_STARTTAG);
+ int len2 = kvi_strLen(MCPS2_ENDTAG);
+ while(szIn.len() > 0)
+ {
+ int idx = szIn.findFirstIdx(MCPS2_STARTTAG);
+ if(idx == -1)
+ {
+ // no more encrypted stuff
+ plainText += szIn;
+ return true;
+ }
+ if(idx > 0) // a non encrypted block
+ plainText += szIn.left(idx);
+ szIn.cutLeft(idx + len1);
+
+ idx = szIn.findFirstIdx(MCPS2_ENDTAG);
+ if(idx != -1)
+ {
+ KviStr toDecrypt = szIn.left(idx);
+ if(!doDecrypt(toDecrypt,plainText))return false;
+ }
+ szIn.cutLeft(idx + len2);
+ }
+ */
+ }
+
+ static unsigned char fake_base64[]="./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ unsigned int fake_base64dec(unsigned char c)
+ {
+ static char base64unmap[255];
+ static bool didinit=false;
+ int i;
+
+ if(!didinit)
+ {
+ // initialize base64unmap
+ for (i=0;i<255;++i)base64unmap[i]=0;
+ for (i=0;i<64;++i)base64unmap[fake_base64[i]]=i;
+ didinit=true;
+ }
+
+ return base64unmap[c];
+ }
+
+ static void byteswap_buffer(unsigned char * p,int len)
+ {
+ while(len > 0)
+ {
+ unsigned char aux = p[0];
+ p[0] = p[3];
+ p[3] = aux;
+ aux = p[1];
+ p[1] = p[2];
+ p[2] = aux;
+ p += 4;
+ len -= 4;
+ }
+ }
+
+ bool KviMircryptionEngine::doEncryptECB(KviStr &plain,KviStr &encoded)
+ {
+ // make sure it is a multiple of 8 bytes (eventually pad with zeroes)
+ if(plain.len() % 8)
+ {
+ int oldL = plain.len();
+ plain.setLength(plain.len() + (8 - (plain.len() % 8)));
+ char * padB = plain.ptr() + oldL;
+ char * padE = plain.ptr() + plain.len();
+ while(padB < padE)*padB++ = 0;
+ }
+
+ //byteswap_buffer((unsigned char *)plain.ptr(),plain.len());
+
+ unsigned char * out =(unsigned char *)kvi_malloc(plain.len()); // we use this to avoid endiannes problems
+
+ BlowFish bf((unsigned char *)m_szEncryptKey.ptr(),m_szEncryptKey.len());
+ bf.ResetChain();
+ bf.Encrypt((unsigned char *)plain.ptr(),out,plain.len(),BlowFish::ECB);
+
+ // FIXME: this is probably needed only on LittleEndian machines!
+ byteswap_buffer((unsigned char *)out,plain.len());
+
+ // da uglybase64 encoding
+ unsigned char * outb = out;
+ unsigned char * oute = out + plain.len();
+
+ int ll = (plain.len() * 3) / 2;
+ encoded.setLength(ll);
+
+ unsigned char * p = (unsigned char *)encoded.ptr();
+ while(outb < oute)
+ {
+ Q_UINT32 * dd1 = (Q_UINT32 *)outb;
+ outb += 4;
+ Q_UINT32 * dd2 = (Q_UINT32 *)outb;
+ outb += 4;
+ *p++ = fake_base64[*dd2 & 0x3f]; *dd2 >>= 6;
+ *p++ = fake_base64[*dd2 & 0x3f]; *dd2 >>= 6;
+ *p++ = fake_base64[*dd2 & 0x3f]; *dd2 >>= 6;
+ *p++ = fake_base64[*dd2 & 0x3f]; *dd2 >>= 6;
+ *p++ = fake_base64[*dd2 & 0x3f]; *dd2 >>= 6;
+ *p++ = fake_base64[*dd2 & 0x3f];
+
+ *p++ = fake_base64[*dd1 & 0x3f]; *dd1 >>= 6;
+ *p++ = fake_base64[*dd1 & 0x3f]; *dd1 >>= 6;
+ *p++ = fake_base64[*dd1 & 0x3f]; *dd1 >>= 6;
+ *p++ = fake_base64[*dd1 & 0x3f]; *dd1 >>= 6;
+ *p++ = fake_base64[*dd1 & 0x3f]; *dd1 >>= 6;
+ *p++ = fake_base64[*dd1 & 0x3f];
+ }
+
+ kvi_free(out);
+ return true;
+ }
+
+ bool KviMircryptionEngine::doDecryptECB(KviStr &encoded,KviStr &plain)
+ {
+ // encoded is in this strange base64...
+ // make sure its length is multiple of 12 (eventually pad with zeroes)
+ if(encoded.len() % 12)
+ {
+ int oldL = encoded.len();
+ encoded.setLength(encoded.len() + (12 - (encoded.len() % 12)));
+ char * padB = encoded.ptr() + oldL;
+ char * padE = encoded.ptr() + encoded.len();
+ while(padB < padE)*padB++ = 0;
+ }
+
+ // a fake base64 decoding algo, use a different character set
+ // and stuff 6 bytes at a time into a 32 bit long...
+ int ll = (encoded.len() * 2) / 3;
+
+ unsigned char * buf = (unsigned char *)kvi_malloc(ll);
+ unsigned char * p = (unsigned char *)encoded.ptr();
+ unsigned char * e = p + encoded.len();
+ int i;
+ unsigned char * bufp = buf;
+ while(p < e)
+ {
+ Q_UINT32 * dw1 = (Q_UINT32 *)bufp;
+ bufp += 4;
+ Q_UINT32 * dw2 = (Q_UINT32 *)bufp;
+ bufp += 4;
+ *dw2 = 0;
+ for(i=0;i < 6;i++)*dw2 |= (fake_base64dec(*p++)) << (i * 6);
+ *dw1 = 0;
+ for(i=0;i < 6;i++)*dw1 |= (fake_base64dec(*p++)) << (i * 6);
+ }
+
+ // FIXME: this is probably needed only on LittleEndian machines!
+ byteswap_buffer((unsigned char *)buf,ll);
+
+ plain.setLength(ll);
+ BlowFish bf((unsigned char *)m_szDecryptKey.ptr(),m_szDecryptKey.len());
+ bf.ResetChain();
+ bf.Decrypt(buf,(unsigned char *)plain.ptr(),ll,BlowFish::ECB);
+
+ //byteswap_buffer((unsigned char *)plain.ptr(),ll);
+
+ kvi_free(buf);
+
+ return true;
+ }
+
+ bool KviMircryptionEngine::doEncryptCBC(KviStr &plain,KviStr &encoded)
+ {
+ // make sure it is a multiple of 8 bytes (eventually pad with zeroes)
+ if(plain.len() % 8)
+ {
+ int oldL = plain.len();
+ plain.setLength(plain.len() + (8 - (plain.len() % 8)));
+ char * padB = plain.ptr() + oldL;
+ char * padE = plain.ptr() + plain.len();
+ while(padB < padE)*padB++ = 0;
+ }
+
+ int ll = plain.len() + 8;
+ unsigned char * in = (unsigned char *)kvi_malloc(ll);
+
+ // choose an IV
+ static bool bDidInit = false;
+
+ int t = (int)kvi_unixTime();
+
+ if(!bDidInit)
+ {
+ srand(t);
+ bDidInit = true;
+ }
+
+ for(int i=0;i<8;i++)in[i] = (unsigned char)(rand() % 256);
+
+ kvi_fastmove(in+8,plain.ptr(),plain.len());
+
+ // encrypt
+ unsigned char * out = (unsigned char *)kvi_malloc(ll);
+ BlowFish bf((unsigned char *)m_szEncryptKey.ptr(),m_szEncryptKey.len());
+ bf.ResetChain();
+ bf.Encrypt(in,out,ll,BlowFish::CBC);
+ kvi_free(in);
+
+ encoded.bufferToBase64((const char *)out,ll);
+ kvi_free(out);
+
+ encoded.prepend('*'); // prepend the signature
+
+ return true;
+ }
+
+ bool KviMircryptionEngine::doDecryptCBC(KviStr &encoded,KviStr &plain)
+ {
+ if(*(encoded.ptr()) != '*')
+ {
+ debug("WARNING: Specified a CBC key but the incoming message doesn't seem to be a CBC one");
+ return doDecryptECB(encoded,plain);
+ }
+ encoded.cutLeft(1);
+
+ char * tmpBuf;
+ int len = encoded.base64ToBuffer(&tmpBuf,false);
+ if(len < 0)
+ {
+ setLastError(__tr("The message is not a base64 string: this is not my stuff"));
+ return false;
+ }
+ if((len < 8) || (len % 8))
+ {
+ setLastError(__tr("The message doesn't seem to be encoded with CBC Mircryption"));
+ if(len > 0)KviStr::freeBuffer(tmpBuf);
+ return false;
+ }
+
+ plain.setLength(len);
+ BlowFish bf((unsigned char *)m_szDecryptKey.ptr(),m_szDecryptKey.len());
+ bf.ResetChain();
+ bf.Decrypt((unsigned char *)tmpBuf,(unsigned char *)plain.ptr(),len,BlowFish::CBC);
+
+ // kill the first 8 bytes (random IV)
+ plain.cutLeft(8);
+
+ KviStr::freeBuffer(tmpBuf);
+
+ return true;
+ }
+
+
+ static KviCryptEngine * allocMircryptionEngine()
+ {
+ return new KviMircryptionEngine();
+ }
+
+#endif
+
+
+// =======================================
+// module routines
+// =======================================
+static bool rijndael_module_init(KviModule * m)
+{
+#ifdef COMPILE_CRYPT_SUPPORT
+ g_pEngineList = new KviPointerList<KviCryptEngine>;
+ g_pEngineList->setAutoDelete(false);
+
+ KviStr format = __tr("Cryptographic engine based on the\n" \
+ "Advanced Encryption Standard (AES)\n" \
+ "algorithm called Rijndael.\n" \
+ "The text is first encrypted with rijndael\n" \
+ "and then converted to %s notation.\n" \
+ "The keys used are %d bit long and will be padded\n" \
+ "with zeros if you provide shorter ones.\n" \
+ "If only one key is provided, this engine\n" \
+ "will use it for both encrypting and decrypting.\n" \
+ "See the rijndael module documentation\n" \
+ "for more info on the algorithm used.\n");
+
+ // FIXME: Maybe convert this repeated code to a function eh ?
+
+ KviCryptEngineDescription * d = new KviCryptEngineDescription;
+ d->szName = "Rijndael128Hex";
+ d->szAuthor = "Szymon Stefanek";
+ d->szDescription.sprintf(format.ptr(),__tr("hexadecimal"),128);
+ d->iFlags = KVI_CRYPTENGINE_CAN_ENCRYPT | KVI_CRYPTENGINE_CAN_DECRYPT |
+ KVI_CRYPTENGINE_WANT_ENCRYPT_KEY | KVI_CRYPTENGINE_WANT_DECRYPT_KEY;
+ d->allocFunc = allocRijndael128HexEngine;
+ d->deallocFunc = deallocRijndaelCryptEngine;
+ m->registerCryptEngine(d);
+
+ d = new KviCryptEngineDescription;
+ d->szName = "Rijndael192Hex";
+ d->szAuthor = "Szymon Stefanek";
+ d->szDescription.sprintf(format.ptr(),__tr("hexadecimal"),192);
+ d->iFlags = KVI_CRYPTENGINE_CAN_ENCRYPT | KVI_CRYPTENGINE_CAN_DECRYPT |
+ KVI_CRYPTENGINE_WANT_ENCRYPT_KEY | KVI_CRYPTENGINE_WANT_DECRYPT_KEY;
+ d->allocFunc = allocRijndael192HexEngine;
+ d->deallocFunc = deallocRijndaelCryptEngine;
+ m->registerCryptEngine(d);
+
+ d = new KviCryptEngineDescription;
+ d->szName = "Rijndael256Hex";
+ d->szAuthor = "Szymon Stefanek";
+ d->szDescription.sprintf(format.ptr(),__tr("hexadecimal"),256);
+ d->iFlags = KVI_CRYPTENGINE_CAN_ENCRYPT | KVI_CRYPTENGINE_CAN_DECRYPT |
+ KVI_CRYPTENGINE_WANT_ENCRYPT_KEY | KVI_CRYPTENGINE_WANT_DECRYPT_KEY;
+ d->allocFunc = allocRijndael256HexEngine;
+ d->deallocFunc = deallocRijndaelCryptEngine;
+ m->registerCryptEngine(d);
+
+ d = new KviCryptEngineDescription;
+ d->szName = "Rijndael128Base64";
+ d->szAuthor = "Szymon Stefanek";
+ d->szDescription.sprintf(format.ptr(),__tr("base64"),128);
+ d->iFlags = KVI_CRYPTENGINE_CAN_ENCRYPT | KVI_CRYPTENGINE_CAN_DECRYPT |
+ KVI_CRYPTENGINE_WANT_ENCRYPT_KEY | KVI_CRYPTENGINE_WANT_DECRYPT_KEY;
+ d->allocFunc = allocRijndael128Base64Engine;
+ d->deallocFunc = deallocRijndaelCryptEngine;
+ m->registerCryptEngine(d);
+
+ d = new KviCryptEngineDescription;
+ d->szName = "Rijndael192Base64";
+ d->szAuthor = "Szymon Stefanek";
+ d->szDescription.sprintf(format.ptr(),__tr("base64"),192);
+ d->iFlags = KVI_CRYPTENGINE_CAN_ENCRYPT | KVI_CRYPTENGINE_CAN_DECRYPT |
+ KVI_CRYPTENGINE_WANT_ENCRYPT_KEY | KVI_CRYPTENGINE_WANT_DECRYPT_KEY;
+ d->allocFunc = allocRijndael192Base64Engine;
+ d->deallocFunc = deallocRijndaelCryptEngine;
+ m->registerCryptEngine(d);
+
+ d = new KviCryptEngineDescription;
+ d->szName = "Rijndael256Base64";
+ d->szAuthor = "Szymon Stefanek";
+ d->szDescription.sprintf(format.ptr(),__tr("base64"),256);
+ d->iFlags = KVI_CRYPTENGINE_CAN_ENCRYPT | KVI_CRYPTENGINE_CAN_DECRYPT |
+ KVI_CRYPTENGINE_WANT_ENCRYPT_KEY | KVI_CRYPTENGINE_WANT_DECRYPT_KEY;
+ d->allocFunc = allocRijndael256Base64Engine;
+ d->deallocFunc = deallocRijndaelCryptEngine;
+ m->registerCryptEngine(d);
+
+
+ d = new KviCryptEngineDescription;
+ d->szName = "Mircryption";
+ d->szAuthor = "Szymon Stefanek";
+ d->szDescription = __tr("Popular cryptographic engine based on the\n" \
+ "old Blowfish encryption algorithm.\n" \
+ "The text is first encrypted with Blowfish \n" \
+ "and then converted to base64 notation.\n" \
+ "The keys used have variable length and\n" \
+ "are specified as character strings.\n" \
+ "You can specify keys long up to 56 bytes (448 bits).\n" \
+ "If only one key is provided, this engine\n" \
+ "will use it for both encrypting and decrypting.\n" \
+ "This engine works in ECB mode by default:\n" \
+ "if you want to use CBC mode you must prefix\n" \
+ "your key(s) with \"cbc:\".\n");
+ d->iFlags = KVI_CRYPTENGINE_CAN_ENCRYPT | KVI_CRYPTENGINE_CAN_DECRYPT |
+ KVI_CRYPTENGINE_WANT_ENCRYPT_KEY | KVI_CRYPTENGINE_WANT_DECRYPT_KEY;
+ d->allocFunc = allocMircryptionEngine;
+ d->deallocFunc = deallocRijndaelCryptEngine;
+ m->registerCryptEngine(d);
+
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool rijndael_module_cleanup(KviModule *m)
+{
+#ifdef COMPILE_CRYPT_SUPPORT
+ while(g_pEngineList->first())delete g_pEngineList->first();
+ delete g_pEngineList;
+ g_pEngineList = 0;
+ m->unregisterCryptEngines();
+ return true;
+#else
+ return false;
+#endif
+}
+
+static bool rijndael_module_can_unload(KviModule *)
+{
+#ifdef COMPILE_CRYPT_SUPPORT
+ return g_pEngineList->isEmpty();
+#else
+ return true;
+#endif
+}
+
+// =======================================
+// plugin definition structure
+// =======================================
+KVIRC_MODULE(
+ "Rijndael crypt engine",
+ "1.0.0",
+ "Szymon Stefanek <pragma at kvirc dot net>" ,
+ "Exports the rijndael crypt engine",
+ rijndael_module_init ,
+ rijndael_module_can_unload,
+ 0,
+ rijndael_module_cleanup
+)
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ #include "libkvirijndael.moc"
+#endif