cryptography.cpp

00001 // --*-c++-*-- 00002 /* 00003 $Id: cryptography_8cpp-source.html,v 1.1 2004/10/05 21:12:01 mentat Exp $ 00004 00005 GNU Messenger - The secure instant messenger 00006 Copyright (C) 2001-2004 Jesse Lovelace 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00021 */ 00022 00023 #include <string> 00024 #include <memory> 00025 #include <cmath> 00026 00027 #include "cryptopp/misc.h" 00028 #include "cryptopp/idea.h" 00029 #include "cryptopp/rng.h" 00030 #include "cryptopp/osrng.h" 00031 #include "cryptopp/files.h" 00032 #include "cryptopp/rsa.h" 00033 #include "cryptopp/queue.h" 00034 #include "cryptopp/randpool.h" 00035 #include "cryptopp/hex.h" 00036 #include "cryptopp/osrng.h" 00037 #include "cryptopp/rijndael.h" 00038 #include "cryptopp/mars.h" 00039 #include "cryptopp/des.h" 00040 #include "cryptopp/3way.h" 00041 #include "cryptopp/idea.h" 00042 #include "cryptopp/serpent.h" 00043 #include "cryptopp/rc2.h" 00044 #include "cryptopp/rc5.h" 00045 #include "cryptopp/blowfish.h" 00046 #include "cryptopp/rc6.h" 00047 #include "cryptopp/camellia.h" 00048 #include "cryptopp/twofish.h" 00049 #include "cryptopp/tea.h" 00050 #include "cryptopp/modes.h" 00051 #include "cryptopp/sha.h" 00052 #include "cryptopp/md2.h" 00053 #include "cryptopp/md5.h" 00054 #include "cryptopp/haval.h" 00055 #include "cryptopp/ripemd.h" 00056 #include "cryptopp/tiger.h" 00057 #include "cryptopp/default.h" 00058 #include "cryptopp/base64.h" 00059 #include "cryptopp/base32.h" 00060 #include "cryptopp/panama.h" 00061 #include "cryptopp/gzip.h" 00062 #include "cryptopp/zlib.h" 00063 #include "cryptopp/filters.h" 00064 #include "cryptopp/secblock.h" 00065 00066 #include "gm/cryptography.h" 00067 #include "gm/crypto_defs.h" 00068 #include "gm/misc.h" 00069 00070 namespace GNUMessenger { 00071 00072 using namespace CryptoPP; 00073 using namespace std; 00074 00080 /* template<class T> 00081 StreamTransformationFilter* getMode(CryptDefines::Mode mode) 00082 throw (CryptoManager::AlgoError) 00083 { 00084 SecByteBlock key; 00085 switch (mode) { 00086 case(CryptDefines::CBC_CTS): 00087 CBC_CTS_Mode<T>::Encryption enc(key, key.size()); 00088 return new StreamTransformationFilter(enc); 00089 case(CryptDefines::CBC): 00090 CBC_Mode<T>::Encryption enc(key, key.size()); 00091 return new StreamTransformationFilter(enc); 00092 case(CryptDefines::CFB): 00093 CFB_Mode<T>::Encryption enc(key, key.size()); 00094 return new StreamTransformationFilter(enc); 00095 case(CryptDefines::CTR): 00096 CTR_Mode<T>::Encryption enc(key, key.size()); 00097 return new StreamTransformationFilter(enc); 00098 case(CryptDefines::ECB): 00099 ECB_Mode<T>::Encryption enc(key, key.size()); 00100 return new StreamTransformationFilter(enc); 00101 case(CryptDefines::OFB): 00102 OFB_Mode<T>::Encryption enc(key, key.size()); 00103 return new StreamTransformationFilter(enc); 00104 default: throw CryptoManager::AlgoError("Invalid cipher mode"); 00105 } 00106 }*/ 00107 00108 00109 #if 0 // dunno if i need these 00110 void Cryptography::compressFile(const string& data, const string& filename) 00111 { 00112 00113 try { 00114 StringSource f(data.c_str(), true, 00115 new Gzip( 00116 new FileSink(filename.c_str()) 00117 ) 00118 ); 00119 } catch (CryptoPP::Exception &e) { 00120 throw DiskError(e.what()); 00121 } 00122 00123 } 00124 00125 string Cryptography::decompressFile(const string& infile) 00126 { 00127 00128 string decryptedFile; 00129 try { 00130 FileSource f(infile.c_str(), true, 00131 new Gunzip( 00132 new StringSink(decryptedFile) 00133 ) 00134 ); 00135 } catch (CryptoPP::Exception &e) { 00136 throw DiskError(e.what()); 00137 } 00138 return decryptedFile; 00139 00140 } 00141 #endif 00142 00143 HashTransformation * CryptoManager::getHash(CryptDefines::Hashes type) 00144 throw (AlgoError) 00145 { 00146 switch (type) 00147 { 00148 case(CryptDefines::SHA1): return new SHA(); 00149 case(CryptDefines::SHA_256): return new SHA256(); 00150 case(CryptDefines::SHA_384): return new SHA384(); 00151 case(CryptDefines::SHA_512): return new SHA512(); 00152 case(CryptDefines::MD_2): return new MD2(); 00153 case(CryptDefines::MD_5): return new MD5(); 00154 case(CryptDefines::HAVAL_3): return new HAVAL3(); 00155 case(CryptDefines::HAVAL_4): return new HAVAL4(); 00156 case(CryptDefines::HAVAL_5): return new HAVAL5(); 00157 case(CryptDefines::RIPEMD_160): return new RIPEMD160(); 00158 case(CryptDefines::_TIGER): return new Tiger(); 00159 #ifdef IS_LITTLE_ENDIAN 00160 case(CryptDefines::PANAMA_HASH): 00161 return new PanamaHash<LittleEndian>(); 00162 #else 00163 case(CryptDefines::PANAMA_HASH): 00164 return new PanamaHash<BigEndian>(); 00165 #endif 00166 default: throw AlgoError("Invalid Hash Algorithm."); 00167 } 00168 } 00169 00170 byte * CryptoManager::hash(const string& data, unsigned int& len, 00171 CryptDefines::Hashes hashType) throw (AlgoError) 00172 { 00173 auto_ptr<HashTransformation> theHash(getHash(hashType)); 00174 00175 byte * result = new byte[theHash->DigestSize()]; 00176 theHash->CalculateDigest(result, (byte *)data.c_str(), data.length()); 00177 00178 return result; 00179 } 00180 00181 byte * CryptoManager::generateIV(const SecByteBlock& data, 00182 CryptDefines::Hashes hash) 00183 { 00184 auto_ptr<HashTransformation> theHash(getHash(hash)); 00185 00186 byte * result = new byte[theHash->DigestSize()]; 00187 00188 SecByteBlock hashed(theHash->DigestSize()); 00189 theHash->CalculateDigest(hashed, data, data.size()); 00190 00191 // digestsize should always be 2a = b 00192 for (unsigned int i = 0; i < theHash->DigestSize() / 2; i++) 00193 result[i] = hashed[i] ^ hashed[i+ (theHash->DigestSize() / 2)]; 00194 00195 return result; 00196 } 00197 00198 unsigned int CryptoManager::testRNG(const unsigned int insize) 00199 throw (RNGError) 00200 { 00201 unsigned int result = 0; 00202 00203 byte * randomData = generateRandom(insize); 00204 byte * compressedData = compress(SecByteBlock(randomData, insize), 00205 result); 00206 delete [] compressedData; 00207 delete [] randomData; 00208 00209 return result; 00210 00211 } 00212 00213 byte * CryptoManager::generateRandom(const unsigned int size) 00214 throw (RNGError) 00215 { 00216 00217 byte * result = new byte[size]; 00218 00219 AutoSeededRandomPool rng; 00220 try { 00221 rng.GenerateBlock(result, size); 00222 } catch (OS_RNG_Err &e) { 00223 delete [] result; 00224 throw RNGError(e.what()); 00225 } 00226 return result; 00227 00228 } 00229 00230 byte * CryptoManager::compress(const SecByteBlock& data, 00231 unsigned int& resultLen, 00232 const unsigned int level) 00233 { 00234 ZlibCompressor z(NULL, level); 00235 z.Put(data, data.size()); 00236 z.MessageEnd(); 00237 00238 resultLen = z.MaxRetrievable(); 00239 byte * out = new byte[resultLen]; 00240 z.Get(out, z.MaxRetrievable()); 00241 00242 return out; 00243 } 00244 00245 byte * CryptoManager::decompress(const SecByteBlock& data, 00246 unsigned int& resultLen) 00247 { 00248 ZlibDecompressor inflate; 00249 inflate.Put(data, data.size()); 00250 inflate.MessageEnd(); 00251 00252 resultLen = inflate.MaxRetrievable(); 00253 byte * out = new byte[resultLen]; 00254 inflate.Get(out, inflate.MaxRetrievable()); 00255 00256 return out; 00257 } 00258 00259 byte * CryptoManager::encrypt(const SecByteBlock& data, 00260 const SecByteBlock& key, 00261 unsigned int& resultLen, 00262 const unsigned int blockSize, 00263 CryptDefines::BlockCipher cipher, 00264 CryptDefines::Mode mode) 00265 throw (RNGError, AlgoError, KeySizeError, BlockSizeError) 00266 { 00267 00268 auto_ptr<SymmetricCipher> theCipher(getEncryptor(cipher,mode)); 00269 00270 if (!theCipher->IsValidKeyLength(key.size())) 00271 throw KeySizeError("Invalid key size for this cipher", 00272 theCipher->MinKeyLength(), 00273 theCipher->MaxKeyLength()); 00274 00275 if (theCipher->IVRequirement() == theCipher->RANDOM_IV) 00276 LOG_DEBUG("Requires random IV"); 00277 00278 SecByteBlock iv( 00279 generateIV( 00280 SecByteBlock( 00281 generateRandom(theCipher->MandatoryBlockSize()), 00282 theCipher->MandatoryBlockSize() 00283 ) 00284 ), 00285 theCipher->MandatoryBlockSize() 00286 ); 00287 00288 theCipher->SetKeyWithIV(key, key.size(), iv); 00289 ArraySink cipherText; 00290 00291 StreamTransformationFilter encryptor(*theCipher, &cipherText); 00292 encryptor.Put(data, data.size()); 00293 // input more plaintext here if needed 00294 encryptor.MessageEnd(); 00295 return NULL; 00296 } 00297 00298 string CryptoManager::encode(const SecByteBlock& data, 00299 CryptDefines::Encoding type) throw (AlgoError) 00300 { 00301 string result; 00302 auto_ptr<SimpleProxyFilter> encoder; 00303 00304 switch (type) { // @todo This isn't optimal 00305 case(CryptDefines::Base64): 00306 encoder.reset(new Base64Encoder(new StringSink(result))); 00307 break; 00308 case(CryptDefines::Base32): 00309 encoder.reset(new Base32Encoder(new StringSink(result))); 00310 break; 00311 case(CryptDefines::Hex): 00312 encoder.reset(new HexEncoder(new StringSink(result))); 00313 break; 00314 default: throw AlgoError("No such encoding system."); 00315 } 00316 00317 encoder->Put(data, data.size()); 00318 encoder->MessageEnd(); 00319 return result; 00320 } 00321 00322 SymmetricCipher * CryptoManager::getEncryptor( 00323 CryptDefines::BlockCipher cipher, 00324 CryptDefines::Mode mode) 00325 throw (AlgoError) 00326 { 00327 00328 00329 return NULL; 00330 } 00331 00332 00333 bool CryptoManager::encryptFile(const string& filename, const VBuffer& key, 00334 const string& data) throw (IOError) 00335 { 00336 00337 // generating random seed for iv 00338 SecByteBlock ivSeed(CryptDefines::IV_SEED_LENGTH); 00339 SecByteBlock realIv(CryptDefines::IV_LENGTH); 00340 00341 AutoSeededRandomPool rng; 00342 rng.GenerateBlock(ivSeed, CryptDefines::IV_SEED_LENGTH); 00343 00344 //creating actual iv, thanks to denis bider for this method 00345 SecByteBlock ivHash(SHA256::DIGESTSIZE); 00346 SHA256().CalculateDigest(ivHash, ivSeed, CryptDefines::IV_SEED_LENGTH); 00347 00348 for (unsigned int i = 0; i != CryptDefines::IV_LENGTH; ++i) 00349 realIv[i] = ivHash[i] ^ ivHash[i+16]; 00350 00351 //compress 00352 ZlibCompressor z(NULL,9); 00353 z.Put((const unsigned char *)data.c_str(), 00354 static_cast<unsigned int>(data.length())); 00355 z.MessageEnd(); 00356 00357 SecByteBlock compressedPlainText(z.MaxRetrievable()); 00358 z.Get(compressedPlainText, compressedPlainText.size()); 00359 00360 //encrypting 00361 SecByteBlock cipherText(compressedPlainText.size()); 00362 00363 CBC_Mode<MARS>::Encryption enc(key.data(), key.size(), realIv.data()); 00364 StreamTransformationFilter encryptor(enc); 00365 encryptor.Put(compressedPlainText, compressedPlainText.size()); 00366 encryptor.MessageEnd(); 00367 00369 cipherText.CleanGrow(encryptor.MaxRetrievable()); 00370 encryptor.Get(cipherText, cipherText.size()); 00371 00372 // create HMAC 00373 SecByteBlock myMac(HMAC<SHA>::DIGESTSIZE); 00374 HMAC<SHA> themac(key.data(), key.size()); 00375 themac.Update(cipherText, cipherText.size()); 00376 themac.Final(myMac); 00377 00378 // setup output file and encode the file as base64 00379 try { 00380 Base64Encoder encoder(new FileSink(filename.c_str(), false)); 00381 encoder.Put(realIv, CryptDefines::IV_LENGTH); 00382 encoder.Put(cipherText, cipherText.size()); 00383 encoder.Put(myMac, HMAC<SHA>::DIGESTSIZE); 00384 encoder.MessageEnd(); 00385 00386 } catch(CryptoPP::Exception &e) { 00387 throw IOError(e.what()); 00388 } 00389 00390 return true; 00391 00392 } 00393 00394 string CryptoManager::decryptFile(const string& filename, 00395 const VBuffer &key) 00396 throw (InvalidPassword, AuthFailed) 00397 { 00398 // read from file 00399 FileSource inputFile(filename.c_str(), true); 00400 SecByteBlock dataFromFile(inputFile.MaxRetrievable()); 00401 inputFile.Get(dataFromFile, dataFromFile.size()); 00402 00403 // decode from base64 00404 Base64Decoder decoder64; 00405 decoder64.Put(dataFromFile, dataFromFile.size()); 00406 decoder64.MessageEnd(); 00407 00408 SecByteBlock iv(CryptDefines::IV_LENGTH); 00409 SecByteBlock payload(decoder64.MaxRetrievable() - 00410 CryptDefines::IV_LENGTH - HMAC<SHA>::DIGESTSIZE); 00411 SecByteBlock hmac(HMAC<SHA>::DIGESTSIZE); 00412 00413 //SecByteBlock decodedData(decoder64.MaxRetrievable()); 00414 decoder64.Get(iv, CryptDefines::IV_LENGTH); 00415 decoder64.Get(payload, payload.size()); 00416 decoder64.Get(hmac, HMAC<SHA>::DIGESTSIZE); 00417 00418 // decrypt, dat becomes new compressed cipher text. 00419 CBC_Mode<MARS>::Decryption dec(key.data(), key.size(), iv.data()); 00420 StreamTransformationFilter decf(dec); 00421 00422 try { 00423 decf.Put(payload, payload.size()); 00424 decf.MessageEnd(); 00425 } catch (CryptoPP::Exception& e) { 00426 throw InvalidPassword(e.what()); 00427 } 00428 00429 // verify hmac digest 00430 00431 if (!HMAC<SHA>(key.data(), key.size()).VerifyDigest(hmac, payload, 00432 payload.size())) 00433 throw AuthFailed("File digest not verified."); 00434 00435 // create object to store compressed plain text 00436 SecByteBlock compressedPlaintext(decf.MaxRetrievable()); 00437 00438 // put decrypted data in 00439 decf.Get(compressedPlaintext, compressedPlaintext.size()); 00440 00441 string output; 00442 ZlibDecompressor zDecompressor(new StringSink(output)); 00443 zDecompressor.Put(compressedPlaintext, compressedPlaintext.size()); 00444 zDecompressor.MessageEnd(); 00445 00446 return output; 00447 00448 } 00449 00450 string CryptoManager::hashEncode(const VBuffer& toHash, 00451 CryptDefines::Hashes hashf, 00452 CryptDefines::Encoding enc) 00453 { 00454 VBuffer block(hash(toHash, hashf)); 00455 auto_ptr<Filter> encoding; 00456 00457 string outString; 00458 00459 switch (enc) { 00460 case (CryptDefines::Hex): 00461 encoding.reset(new HexEncoder(new StringSink(outString))); 00462 break; 00463 case (CryptDefines::Base64): 00464 encoding.reset(new Base64Encoder(new StringSink(outString), false)); 00465 break; 00466 case (CryptDefines::Base32): 00467 encoding.reset(new Base32Encoder(new StringSink(outString), false)); 00468 break; 00469 default: break; 00470 }; 00471 00472 encoding->Put(block.data(), block.size()); 00473 encoding->MessageEnd(); 00474 00475 return outString; 00476 } 00477 00478 00479 VBuffer CryptoManager::hash(const VBuffer& toHash, CryptDefines::Hashes hashf) 00480 { 00481 auto_ptr<HashTransformation> hash; 00482 00483 switch (hashf) 00484 { 00485 case(CryptDefines::SHA1): hash.reset(new SHA); break; 00486 case(CryptDefines::SHA_256): hash.reset(new SHA256); break; 00487 case(CryptDefines::SHA_384): hash.reset(new SHA384); break; 00488 case(CryptDefines::SHA_512): hash.reset(new SHA512); break; 00489 case(CryptDefines::MD_2): hash.reset(new MD2); break; 00490 case(CryptDefines::MD_5): hash.reset(new MD5); break; 00491 case(CryptDefines::HAVAL_3): hash.reset(new HAVAL3); break; 00492 case(CryptDefines::HAVAL_4): hash.reset(new HAVAL4); break; 00493 case(CryptDefines::HAVAL_5): hash.reset(new HAVAL5); break; 00494 case(CryptDefines::RIPEMD_160): hash.reset(new RIPEMD160); break; 00495 case(CryptDefines::_TIGER): hash.reset(new Tiger); break; 00496 } 00497 00498 SecByteBlock retBlock(hash->DigestSize()); 00499 hash->CalculateDigest(retBlock, toHash.data(), toHash.size()); 00500 00501 VBuffer ret(retBlock.begin(), retBlock.size()); 00502 00503 return ret; 00504 00505 } 00506 00507 } 00508 00509

Generated on Tue Oct 5 14:41:47 2004 for GNU Messenger by doxygen 1.3.8