From 04ef028372bb19656ae8734c6eedabc65af2b77d Mon Sep 17 00:00:00 2001 From: Gabriel Tofvesson Date: Mon, 16 Oct 2017 20:37:06 +0200 Subject: [PATCH] Added asynchronous key generation to network library Replaced malloc() calls with new[] calls to make code more consistent Fixed memory leaks KeyData is now generated as a pointer --- CPPTools/CPPTools.vcxproj | 6 ++-- CPPTools/Crypto.cpp | 65 ++++++++++++++++++++++++++---------- CPPTools/Crypto.h | 2 +- CPPTools/Net.cpp | 69 +++++++++++++++++++++++++++++++-------- CPPTools/Net.h | 34 +++++++++++++------ 5 files changed, 132 insertions(+), 44 deletions(-) diff --git a/CPPTools/CPPTools.vcxproj b/CPPTools/CPPTools.vcxproj index dbeee4e..c7957f2 100644 --- a/CPPTools/CPPTools.vcxproj +++ b/CPPTools/CPPTools.vcxproj @@ -72,9 +72,7 @@ 64.lib - - .lib - + Level3 @@ -130,6 +128,8 @@ true true + $(SolutionDir)libs\win_crypto++\;%(AdditionalLibraryDirectories) + cryptlib.lib;winsqlite3.lib;shlwapi.lib;Crypt32.lib;Ws2_32.lib;Mswsock.lib;AdvApi32.lib;%(AdditionalDependencies) $(SolutionDir)libs\win_crypto++\;%(AdditionalLibraryDirectories) diff --git a/CPPTools/Crypto.cpp b/CPPTools/Crypto.cpp index 734a7ea..887dad9 100644 --- a/CPPTools/Crypto.cpp +++ b/CPPTools/Crypto.cpp @@ -7,6 +7,21 @@ namespace Crypto { + static unsigned long x = 123456789, y = 362436069, z = 521288629; + + unsigned long xorshf96(void) { //period 2^96-1 + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; + } namespace AES { // -------- AES START -------- @@ -38,7 +53,7 @@ namespace Crypto { (*resultingSize) = t; - char* cipher = (char*)malloc(t); + char* cipher = (char*)new char[t]; memcpy(cipher, ciphertext.c_str(), t); return cipher; @@ -61,11 +76,11 @@ namespace Crypto { *resultSize = decryptedtext.size(); - char* c = (char*)malloc(*resultSize); + char* c = (char*)new char[*resultSize]; //memset(c, 0, decryptedtext.size()); memcpy(c, decryptedtext.c_str(), decryptedtext.size()); - decryptedtext.~basic_string(); + //decryptedtext.~basic_string(); return c; } @@ -74,9 +89,15 @@ namespace Crypto { Payload aes_auto_encrypt(void* msg, ulong_64b size) { char* message = (char*)msg; Payload p; - srand(time(NULL)); - p.key = (char*)malloc(sizeof(AES_KEY)); + // Generate random number 'n stuff + for (volatile unsigned int i = ((unsigned int)rand())%4096; i > 0; --i) xorshf96(); + time_t t = (time_t) xorshf96(); + if (sizeof(long) < sizeof(time_t)) t ^= xorshf96() << ((sizeof(time_t) / 2) + (sizeof(time_t)%2)); // Fill ALL the bits! + srand(time(NULL)+(signed long long)t); + + + p.key = (char*)new char[sizeof(AES_KEY)]; AES_KEY k = (AES_KEY)rand(); p.keySize = sizeof(AES_KEY); @@ -143,8 +164,8 @@ namespace Crypto { namespace RSA { // -------- RSA START -------- - KeyData rsa_gen_keys() { - KeyData k; + KeyData* rsa_gen_keys() { + KeyData* k = new KeyData(); CryptoPP::InvertibleRSAFunction params; CryptoPP::RandomPool rng; @@ -153,8 +174,8 @@ namespace Crypto { rng.IncorporateEntropy((const byte*)&t, sizeof(t) * 8); params.GenerateRandomWithKeySize(rng, 3072); - k.privKey = CryptoPP::RSA::PrivateKey(params); - k.publKey = CryptoPP::RSA::PublicKey(params); + k->privKey = CryptoPP::RSA::PrivateKey(params); + k->publKey = CryptoPP::RSA::PublicKey(params); return k; } @@ -164,7 +185,7 @@ namespace Crypto { //func.DEREncodePublicKey(queue); - byte* shortened = (byte*)malloc(*rSize=queue.TotalBytesRetrievable()); + byte* shortened = (byte*)new byte[*rSize=queue.TotalBytesRetrievable()]; memset(shortened, 0, *rSize); std::vector spk; @@ -191,9 +212,10 @@ namespace Crypto { *resultingSize = cipher.size(); - char* c = (char*)malloc(cipher.size()); - memset(c, 0, cipher.size()); + char* c = (char*)new char[cipher.size()]; + //memset(c, 0, cipher.size()); memcpy(c, cipher.c_str(), cipher.size()); + return c; } @@ -210,9 +232,11 @@ namespace Crypto { *resultingSize = clear.size(); - char* c = (char*)malloc(clear.size()); - memset(c, 0, clear.size()); + char* c = (char*)new char[clear.size()]; + //memset(c, 0, clear.size()); memcpy(c, clear.c_str(), clear.size()); + + return c; } // -------- RSA END -------- @@ -220,14 +244,21 @@ namespace Crypto { char* full_auto_encrypt(void* msg, ulong_64b mSize, CryptoPP::RSA::PublicKey& pk, ulong_64b* rSize) { AES::Payload p = AES::aes_auto_encrypt(msg, mSize); - p.key = RSA::rsa_encrypt(p.key, p.keySize, pk, &p.keySize); + char *c = RSA::rsa_encrypt(p.key, p.keySize, pk, &p.keySize); + delete[] p.key; + p.key = c; return p.serialize(rSize); } char* full_auto_decrypt(void* msg, CryptoPP::RSA::PrivateKey& pk, ulong_64b* rSize) { ulong_64b size; AES::Payload p = AES::deserializePayload(msg, &size); - p.key = RSA::rsa_decrypt(p.key, p.keySize, pk, &p.keySize); - return AES::aes_auto_decrypt(p, rSize); + char *c = RSA::rsa_decrypt(p.key, p.keySize, pk, &p.keySize); + delete[] p.key; + p.key = c; + c = AES::aes_auto_decrypt(p, rSize); + delete[] p.key; + delete[] p.ldPayload; + return c; } } \ No newline at end of file diff --git a/CPPTools/Crypto.h b/CPPTools/Crypto.h index fc84b6b..2ccf88e 100644 --- a/CPPTools/Crypto.h +++ b/CPPTools/Crypto.h @@ -56,7 +56,7 @@ namespace Crypto { char* serializeKey(CryptoPP::RSA::PublicKey&, ulong_64b* rSize); - KeyData rsa_gen_keys(); + KeyData* rsa_gen_keys(); char* rsa_encrypt(void* message, ulong_64b size, CryptoPP::RSA::PublicKey& pubKey, ulong_64b* resultingSize); char* rsa_decrypt(void* message, ulong_64b size, CryptoPP::RSA::PrivateKey& privKey, ulong_64b* resultingSize); } diff --git a/CPPTools/Net.cpp b/CPPTools/Net.cpp index 0acb70b..df87119 100644 --- a/CPPTools/Net.cpp +++ b/CPPTools/Net.cpp @@ -1,6 +1,7 @@ #include "Net.h" #include "Support.h" +#include #include #include #include @@ -9,6 +10,26 @@ namespace IO { + + AsyncKeys::AsyncKeys() { + gen = std::async(std::launch::async, [this]() { + Crypto::RSA::KeyData *data = Crypto::RSA::rsa_gen_keys(); + done = true; + return data; + }); + done = suppressDelete = false; + } + AsyncKeys::AsyncKeys(Crypto::RSA::KeyData* predef) { + done = suppressDelete = true; + keys = predef; + } + AsyncKeys::~AsyncKeys() { if (!suppressDelete) delete keys; } + Crypto::RSA::KeyData* AsyncKeys::get() { + if (!done) keys = gen.get(); + return keys; + } + + bool cryptoLevelsAreCompatible(CryptoLevel l1, CryptoLevel l2) { return !(((l1 == CryptoLevel::None) && (l2 == CryptoLevel::Force)) || ((l2 == CryptoLevel::None) && (l1 == CryptoLevel::Force))); } @@ -45,7 +66,7 @@ namespace IO { void NetClient::sharedSetup(bool setupKeys) { - if (setupKeys && (preferEncrypted != CryptoLevel::None)) keys = Crypto::RSA::rsa_gen_keys(); + if (setupKeys && (preferEncrypted != CryptoLevel::None)) keyData = new AsyncKeys(); packets = new std::vector(); sparse = new std::vector(); outPacketBuf = new std::vector(); @@ -106,17 +127,26 @@ namespace IO { sharedSetup(setupKeys); } - NetClient::NetClient(char* ipAddr, char* port, Crypto::RSA::KeyData& keys, CryptoLevel level) : NetClient(ipAddr, port, level, false) { this->keys = keys; } + NetClient::NetClient(char* ipAddr, char* port, AsyncKeys *keyData, CryptoLevel level) : NetClient(ipAddr, port, level, false) { this->keyData = keyData; } - NetClient::NetClient(SOCKET wrap, bool noThread, Crypto::RSA::KeyData& keys, CryptoLevel preferEncrypted, bool startNegotiate) : + NetClient::NetClient(SOCKET wrap, bool noThread, AsyncKeys &keyData, CryptoLevel preferEncrypted, bool startNegotiate) : preferEncrypted(preferEncrypted), startNegotiate(startNegotiate) { _socket = wrap; this->noThread = noThread; - sharedSetup(true); + this->keyData = new AsyncKeys(keyData.get()); + sharedSetup(false); } NetClient::~NetClient() { + delete keyData; + for (std::pair*> *p : associatedData) { + delete[] p->first; + delete[] p->second->second; + delete p->second; + delete p; + } + associatedData.clear(); packets->clear(); delete packets; sparse->clear(); @@ -144,6 +174,7 @@ namespace IO { else if (i == 0) --wIdx; } commTime = time(nullptr); + delete[] c; return true; } @@ -155,14 +186,24 @@ namespace IO { char* c = new char[sizeof(ulong_64b)]; memcpy(c, &size, sizeof(ulong_64b)); for (ulong_64b wIdx = 0; wIdx < sizeof(ulong_64b); ++wIdx) { - if ((i = send(_socket, c + wIdx, 1, 0)) == SOCKET_ERROR) return false; + if ((i = send(_socket, c + wIdx, 1, 0)) == SOCKET_ERROR) { + delete[] message; + delete[] c; + return false; + } else if (i == 0) --wIdx; } for (ulong_64b wIdx = 0; wIdx < size; ++wIdx) { - if ((i = send(_socket, message + wIdx, 1, 0)) == SOCKET_ERROR) return false; + if ((i = send(_socket, message + wIdx, 1, 0)) == SOCKET_ERROR) { + delete[] message; + delete[] c; + return false; + } else if (i == 0) --wIdx; } commTime = time(nullptr); + if(autoDelete) delete[] message; + delete[] c; return true; } bool NetClient::write(void* message, ulong_64b size) { @@ -234,7 +275,7 @@ namespace IO { delete[] size; p.message = readSparse(sparse, p.size); - if (encrypted) p.message = Crypto::full_auto_decrypt(p.message, keys.privKey, &p.size); + if (encrypted) p.message = Crypto::full_auto_decrypt(p.message, keyData->get()->privKey, &p.size); p.packetUID = p.message[0]; if (p.packetUID != expectedNextPUID) continue; // Detect packet replay/mismatch @@ -267,7 +308,7 @@ namespace IO { } else { ulong_64b size; - char* c = Crypto::RSA::serializeKey(keys.publKey, &size); + char* c = Crypto::RSA::serializeKey(keyData->get()->publKey, &size); _write(c, size); // This shouldn't be encrypted delete[] c; } @@ -428,7 +469,7 @@ namespace IO { if (_open) throw new std::exception(); else break; } - NetClient* cli = new NetClient(client, true, keys, this->pref, false); + NetClient* cli = new NetClient(client, true, *keyData, this->pref, false); clients->push_back(cli); for (ulong_64b t = 0; t < handlers->size(); ++t) if (handlers->at(t)(cli)) @@ -455,21 +496,23 @@ namespace IO { } NetServer::NetServer(char* port, std::function f, CryptoLevel pref) : pref(pref) { - if (pref != CryptoLevel::None) keys = Crypto::RSA::rsa_gen_keys(); + if (pref != CryptoLevel::None) keyData = new AsyncKeys(); sharedSetup(port, f); } - NetServer::NetServer(char* port, std::function f, Crypto::RSA::KeyData& keys, CryptoLevel level) : pref(level) { - this->keys = keys; + NetServer::NetServer(char* port, std::function f, AsyncKeys &keyData, CryptoLevel level) : pref(level) { + this->keyData = new AsyncKeys(keyData.get()); sharedSetup(port, f); } NetServer::~NetServer() { + delete keyData; if (_open) close(); handlers->clear(); delete handlers; - clients->clear(); + for (NetClient *cli : *clients) delete cli; + clients->clear(); delete clients; onDestroy(); } diff --git a/CPPTools/Net.h b/CPPTools/Net.h index d11921b..0e63a7b 100644 --- a/CPPTools/Net.h +++ b/CPPTools/Net.h @@ -26,10 +26,24 @@ #include #include #include +#include namespace IO { + class AsyncKeys { + private: + std::future gen; + Crypto::RSA::KeyData* keys; + volatile bool done; + bool suppressDelete; + public: + AsyncKeys(); + AsyncKeys(Crypto::RSA::KeyData* predef); + ~AsyncKeys(); + Crypto::RSA::KeyData* get(); + }; + enum CryptoLevel { None, Prefer, Force }; struct Packet { @@ -51,25 +65,24 @@ namespace IO { volatile bool _open; // Whether or not connection is open bool canWrite; // Whether or not writing to peer is possible bool noThread; // Whether or not reading incoming data should be / is being done in a separate thread - //char rBuf[BUFSIZE]; // Recieve buffer std::vector rBuf; CryptoLevel preferEncrypted = CryptoLevel::None;// Whether or not the socket should attempt to request an encrypted channel bool encrypted = false; // Whether or not negotiation determined the use of an encrypted channel bool firstMessage = true; // Whether or not negotiation has yet ocurred - ulong_64b fm_neg_size; - bool fm_neg_hasLevel = false; - bool fm_neg_hasSize = false; - bool startNegotiate = false; + ulong_64b fm_neg_size; // First message negotiation size + bool fm_neg_hasLevel = false; // First message has crypto level + bool fm_neg_hasSize = false; // Got negotiation size from first message + bool startNegotiate = false; // Whether or not to initiate negotiation char expectedNextPUID = 0; char remotePUID = 0; std::vector* sparse; std::vector* outPacketBuf; - Crypto::RSA::KeyData keys; // Client's keysets (if using encryption) + AsyncKeys *keyData; // Client's keysets (if using encryption) CryptoPP::RSAFunction pK; // Remote host's public key (if using encryption) NetClient(char*, char*, CryptoLevel, bool); // Underlying setup for regular constructors NetClient(SOCKET, bool, CryptoLevel, bool);// Special setup constructor - NetClient(SOCKET, bool, Crypto::RSA::KeyData&, CryptoLevel = CryptoLevel::None, bool = false);// Create wrapper for existing socket + NetClient(SOCKET, bool, AsyncKeys&, CryptoLevel = CryptoLevel::None, bool = false);// Create wrapper for existing socket void sharedSetup(bool); // Setup function for all constructor bool _write(char*, ulong_64b); // Internal write function. Doesn't do any of the fancy auto encryption: just raw write... bool writeBufferedPackets(); // Flushes and deletes buffer @@ -85,9 +98,10 @@ namespace IO { std::function onDestroy; // Event handler called when NetClient object is destroyed public: bool autoPing = true; // Whether or not client should actively check connection state + bool autoDelete = false; time_t commTime; // Latest time a transaction occurred NetClient(char* ipAddr, char* port, CryptoLevel = CryptoLevel::None);// Standard constructor for creating connection - NetClient(char* ipAddr, char* port, Crypto::RSA::KeyData&, CryptoLevel);// Standard constructor for creating connection with predefined keys + NetClient(char* ipAddr, char* port, AsyncKeys*, CryptoLevel);// Standard constructor for creating connection with predefined keys ~NetClient(); bool close(); void closeWrite(); @@ -113,7 +127,7 @@ namespace IO { friend class NetClient; private: CryptoLevel pref; - Crypto::RSA::KeyData keys; // Server's keysets (if using encryption) + AsyncKeys *keyData; // Server's keysets (if using encryption) std::function onDestroy; volatile bool _open; @@ -126,7 +140,7 @@ namespace IO { public: std::function timeoutHandler; NetServer(char* port, std::function = nullptr, CryptoLevel = CryptoLevel::None); - NetServer(char* port, std::function, Crypto::RSA::KeyData&, CryptoLevel); + NetServer(char* port, std::function, AsyncKeys&, CryptoLevel); ~NetServer(); bool isOpen(); CryptoLevel getCryptoPreference();