/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011-2016 Martin Raiber * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **************************************************************************/ #include "../vld.h" #include "CryptoFactory.h" #include "../Interface/Server.h" #include "../Interface/ThreadPool.h" #include "AESEncryption.h" #include "AESDecryption.h" #include "ZlibCompression.h" #include "ZlibDecompression.h" #include "AESGCMDecryption.h" #include "AESGCMEncryption.h" #include "cryptopp_inc.h" #include "ECDHKeyExchange.h" IAESEncryption* CryptoFactory::createAESEncryption(const std::string &password) { return new AESEncryption(password, true); } IAESDecryption* CryptoFactory::createAESDecryption(const std::string &password) { return new AESDecryption(password, true); } IAESEncryption* CryptoFactory::createAESEncryptionNoDerivation(const std::string &password) { return new AESEncryption(password, false); } IAESDecryption* CryptoFactory::createAESDecryptionNoDerivation(const std::string &password) { return new AESDecryption(password, false); } IAESGCMEncryption* CryptoFactory::createAESGCMEncryption(const std::string &password) { return new AESGCMEncryption(password, true); } IAESGCMDecryption* CryptoFactory::createAESGCMDecryption(const std::string &password) { return new AESGCMDecryption(password, true); } IAESGCMEncryption* CryptoFactory::createAESGCMEncryptionNoDerivation(const std::string &password) { return new AESGCMEncryption(password, false); } IAESGCMDecryption* CryptoFactory::createAESGCMDecryptionNoDerivation(const std::string &password) { return new AESGCMDecryption(password, false); } bool CryptoFactory::generatePrivatePublicKeyPair(const std::string &keybasename) { CryptoPP::AutoSeededRandomPool rnd; CryptoPP::ECDSA::PrivateKey privateKey; privateKey.Initialize(rnd, CryptoPP::ASN1::sect409k1()); Server->Log("Calculating public key...", LL_INFO); CryptoPP::ECDSA::PublicKey publicKey; privateKey.MakePublicKey( publicKey ); if (!privateKey.Validate(rnd, 3) || !publicKey.Validate(rnd, 3)) { Server->Log("Validating key pair failed", LL_ERROR); return false; } privateKey.Save(CryptoPP::FileSink((keybasename+".priv").c_str()).Ref()); publicKey.Save(CryptoPP::FileSink((keybasename+".pub").c_str()).Ref()); return true; } bool CryptoFactory::generatePrivatePublicKeyPairDSA(const std::string &keybasename) { CryptoPP::AutoSeededRandomPool rnd; CryptoPP::DSA::PrivateKey dsaPrivate; dsaPrivate.GenerateRandomWithKeySize(rnd, 1024); Server->Log("Calculating public key...", LL_INFO); CryptoPP::DSA::PublicKey dsaPublic; dsaPublic.AssignFrom(dsaPrivate); if (!dsaPrivate.Validate(rnd, 3) || !dsaPublic.Validate(rnd, 3)) { Server->Log("Validating key pair failed", LL_ERROR); return false; } dsaPrivate.Save(CryptoPP::FileSink((keybasename+".priv").c_str()).Ref()); dsaPublic.Save(CryptoPP::FileSink((keybasename+".pub").c_str()).Ref()); return true; } bool CryptoFactory::signFile(const std::string &keyfilename, const std::string &filename, const std::string &sigfilename) { CryptoPP::ECDSA::PrivateKey privateKey; CryptoPP::AutoSeededRandomPool rnd; try { privateKey.Load(CryptoPP::FileSource(keyfilename.c_str(), true).Ref()); CryptoPP::ECDSA::Signer signer( privateKey ); CryptoPP::FileSource( filename.c_str(), true, new CryptoPP::SignerFilter( rnd, signer, new CryptoPP::FileSink( sigfilename.c_str() ) ) // SignerFilter ); return true; } catch(const CryptoPP::Exception& e) { Server->Log("Exception occured in CryptoFactory::signFile: " + e.GetWhat(), LL_ERROR); } return false; } bool CryptoFactory::signFileDSA(const std::string &keyfilename, const std::string &filename, const std::string &sigfilename) { CryptoPP::DSA::PrivateKey privateKey; CryptoPP::AutoSeededRandomPool rnd; try { privateKey.Load(CryptoPP::FileSource(keyfilename.c_str(), true).Ref()); CryptoPP::DSA::Signer signer( privateKey ); CryptoPP::FileSource( filename.c_str(), true, new CryptoPP::SignerFilter( rnd, signer, new CryptoPP::FileSink( sigfilename.c_str() ) ) // SignerFilter ); return true; } catch(const CryptoPP::Exception& e) { Server->Log("Exception occured in CryptoFactory::signFile: " + e.GetWhat(), LL_ERROR); } return false; } bool CryptoFactory::verifyFile(const std::string &keyfilename, const std::string &filename, const std::string &sigfilename) { CryptoPP::ECDSA::PublicKey PublicKey; CryptoPP::AutoSeededRandomPool rnd; try { PublicKey.Load(CryptoPP::FileSource(keyfilename.c_str(), true).Ref()); CryptoPP::ECDSA::Verifier verifier( PublicKey ); CryptoPP::SignatureVerificationFilter svf(verifier); CryptoPP::FileSource( sigfilename.c_str(), true, new CryptoPP::Redirector( svf, CryptoPP::Redirector::PASS_WAIT_OBJECTS ) ); CryptoPP::FileSource( filename.c_str(), true, new CryptoPP::Redirector( svf ) ); return svf.GetLastResult(); } catch(const CryptoPP::Exception& e) { Server->Log("Exception occured in CryptoFactory::verifyFile: " + e.GetWhat(), LL_ERROR); } return false; } std::string CryptoFactory::generatePasswordHash(const std::string &password, const std::string &salt, size_t iterations) { CryptoPP::SecByteBlock derived; derived.resize(CryptoPP::SHA256::DIGESTSIZE); CryptoPP::PKCS5_PBKDF2_HMAC pkcs; pkcs.DeriveKey(derived, CryptoPP::SHA256::DIGESTSIZE, 0, (byte*)password.c_str(), password.size(), (byte*)salt.c_str(), salt.size(), (unsigned int)iterations, 0); CryptoPP::HexEncoder hexEncoder; hexEncoder.Put(derived,derived.size()); hexEncoder.MessageEnd(); std::string ret; ret.resize(hexEncoder.MaxRetrievable()); hexEncoder.Get((byte*)&ret[0],ret.size()); return ret; } std::string CryptoFactory::generateBinaryPasswordHash(const std::string &password, const std::string &salt, size_t iterations) { std::string derived; derived.resize(CryptoPP::SHA512::DIGESTSIZE); CryptoPP::PKCS5_PBKDF2_HMAC pkcs; pkcs.DeriveKey((byte*)derived.data(), CryptoPP::SHA512::DIGESTSIZE, 0, (byte*)password.c_str(), password.size(), (byte*)salt.c_str(), salt.size(), (unsigned int)iterations, 0); return derived; } IZlibCompression* CryptoFactory::createZlibCompression(int compression_level) { return new ZlibCompression(compression_level); } IZlibDecompression* CryptoFactory::createZlibDecompression(void) { return new ZlibDecompression; } bool CryptoFactory::signData(const std::string &pubkey, const std::string &data, std::string &signature) { CryptoPP::ECDSA::PrivateKey PrivateKey; CryptoPP::AutoSeededRandomPool rnd; try { PrivateKey.Load(CryptoPP::StringSource(reinterpret_cast(pubkey.c_str()), pubkey.size(), true).Ref()); CryptoPP::ECDSA::Signer signer( PrivateKey ); CryptoPP::StringSource( reinterpret_cast(data.c_str()), data.size(), true, new CryptoPP::SignerFilter( rnd, signer, new CryptoPP::StringSink( signature ) ) // SignerFilter ); return true; } catch(const CryptoPP::Exception& e) { Server->Log("Exception occured in CryptoFactory::signDataDSA: " + e.GetWhat(), LL_ERROR); } return false; } bool CryptoFactory::signDataDSA(const std::string &pubkey, const std::string &data, std::string &signature) { CryptoPP::DSA::PrivateKey PrivateKey; CryptoPP::AutoSeededRandomPool rnd; try { PrivateKey.Load(CryptoPP::StringSource(reinterpret_cast(pubkey.c_str()), pubkey.size(), true).Ref()); CryptoPP::DSA::Signer signer( PrivateKey ); CryptoPP::StringSource( reinterpret_cast(data.c_str()), data.size(), true, new CryptoPP::SignerFilter( rnd, signer, new CryptoPP::StringSink( signature ) ) // SignerFilter ); return true; } catch(const CryptoPP::Exception& e) { Server->Log("Exception occured in CryptoFactory::signData: " + e.GetWhat(), LL_ERROR); } return false; } bool CryptoFactory::verifyData( const std::string &pubkey, const std::string &data, const std::string &signature ) { CryptoPP::ECDSA::PublicKey PublicKey; CryptoPP::AutoSeededRandomPool rnd; try { PublicKey.Load(CryptoPP::StringSource(reinterpret_cast(pubkey.c_str()), pubkey.size(), true).Ref()); CryptoPP::ECDSA::Verifier verifier( PublicKey ); CryptoPP::SignatureVerificationFilter svf(verifier); CryptoPP::StringSource( reinterpret_cast(signature.c_str()), signature.size(), true, new CryptoPP::Redirector( svf, CryptoPP::Redirector::PASS_WAIT_OBJECTS ) ); CryptoPP::StringSource( reinterpret_cast(data.c_str()), data.size(), true, new CryptoPP::Redirector( svf ) ); return svf.GetLastResult(); } catch(const CryptoPP::Exception& e) { Server->Log("Exception occured in CryptoFactory::verifyData: " + e.GetWhat(), LL_ERROR); } return false; } bool CryptoFactory::verifyDataDSA( const std::string &pubkey, const std::string &data, const std::string &signature ) { CryptoPP::DSA::PublicKey PublicKey; CryptoPP::AutoSeededRandomPool rnd; try { PublicKey.Load(CryptoPP::StringSource(reinterpret_cast(pubkey.c_str()), pubkey.size(), true).Ref()); CryptoPP::DSA::Verifier verifier( PublicKey ); CryptoPP::SignatureVerificationFilter svf(verifier); CryptoPP::StringSource( reinterpret_cast(signature.c_str()), signature.size(), true, new CryptoPP::Redirector( svf, CryptoPP::Redirector::PASS_WAIT_OBJECTS ) ); CryptoPP::StringSource( reinterpret_cast(data.c_str()), data.size(), true, new CryptoPP::Redirector( svf ) ); return svf.GetLastResult(); } catch(const CryptoPP::Exception& e) { Server->Log("Exception occured in CryptoFactory::verifyDataDSA: " + e.GetWhat(), LL_ERROR); } return false; } std::string CryptoFactory::encryptAuthenticatedAES(const std::string& data, const std::string &password, size_t iterations/*=20000*/ ) { const size_t iv_size=CryptoPP::AES::BLOCKSIZE; std::string ciphertext; ciphertext.resize(iv_size); Server->secureRandomFill(&ciphertext[0], iv_size); CryptoPP::SecByteBlock key; key.resize(CryptoPP::SHA256::DIGESTSIZE); CryptoPP::PKCS5_PBKDF2_HMAC gen; gen.DeriveKey(key.BytePtr(), CryptoPP::SHA256::DIGESTSIZE, 0, reinterpret_cast(password.c_str()), password.size(), reinterpret_cast(ciphertext.data()), iv_size, static_cast(iterations), 0); CryptoPP::EAX::Encryption enc; enc.SetKeyWithIV(key.BytePtr(), CryptoPP::AES::BLOCKSIZE, reinterpret_cast(ciphertext.data()), iv_size); CryptoPP::ArraySource( reinterpret_cast(data.data()), data.size(), true, new CryptoPP::AuthenticatedEncryptionFilter( enc, new CryptoPP::StringSink( ciphertext ) ) ); return ciphertext; } std::string CryptoFactory::decryptAuthenticatedAES(const std::string& data, const std::string &password, size_t iterations) { const size_t iv_size=CryptoPP::AES::BLOCKSIZE; if(data.size() gen; gen.DeriveKey(key.BytePtr(), CryptoPP::SHA256::DIGESTSIZE, 0, reinterpret_cast(password.c_str()), password.size(), reinterpret_cast(data.data()), iv_size, static_cast(iterations), 0); CryptoPP::EAX::Decryption dec; dec.SetKeyWithIV(key.BytePtr(), CryptoPP::AES::BLOCKSIZE, reinterpret_cast(data.data()), iv_size); try { std::string ret; CryptoPP::ArraySource( reinterpret_cast(data.data()+iv_size), data.size()-iv_size, true, new CryptoPP::AuthenticatedDecryptionFilter( dec, new CryptoPP::StringSink( ret ) ) ); return ret; } catch(const CryptoPP::HashVerificationFilter::HashVerificationFailed&) { return std::string(); } } IECDHKeyExchange* CryptoFactory::createECDHKeyExchange() { return new ECDHKeyExchange(); }