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
This commit is contained in:
parent
79d518f97e
commit
04ef028372
@ -72,9 +72,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TargetExt>64.lib</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetExt>.lib</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
@ -130,6 +128,8 @@
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)libs\win_crypto++\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>cryptlib.lib;winsqlite3.lib;shlwapi.lib;Crypt32.lib;Ws2_32.lib;Mswsock.lib;AdvApi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)libs\win_crypto++\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
|
@ -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<byte> 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "Net.h"
|
||||
#include "Support.h"
|
||||
|
||||
#include <future>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
@ -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<Packet>();
|
||||
sparse = new std::vector<char>();
|
||||
outPacketBuf = new std::vector<Packet>();
|
||||
@ -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<char*, std::pair<ulong_64b, char*>*> *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<bool(NetClient*)> 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<bool(NetClient*)> f, Crypto::RSA::KeyData& keys, CryptoLevel level) : pref(level) {
|
||||
this->keys = keys;
|
||||
NetServer::NetServer(char* port, std::function<bool(NetClient*)> 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();
|
||||
}
|
||||
|
@ -26,10 +26,24 @@
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
|
||||
|
||||
namespace IO {
|
||||
|
||||
class AsyncKeys {
|
||||
private:
|
||||
std::future<Crypto::RSA::KeyData*> 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<char> 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<char>* sparse;
|
||||
std::vector<Packet>* 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<void()> 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<void()> onDestroy;
|
||||
volatile bool _open;
|
||||
|
||||
@ -126,7 +140,7 @@ namespace IO {
|
||||
public:
|
||||
std::function<bool(NetClient*)> timeoutHandler;
|
||||
NetServer(char* port, std::function<bool(NetClient*)> = nullptr, CryptoLevel = CryptoLevel::None);
|
||||
NetServer(char* port, std::function<bool(NetClient*)>, Crypto::RSA::KeyData&, CryptoLevel);
|
||||
NetServer(char* port, std::function<bool(NetClient*)>, AsyncKeys&, CryptoLevel);
|
||||
~NetServer();
|
||||
bool isOpen();
|
||||
CryptoLevel getCryptoPreference();
|
||||
|
Loading…
x
Reference in New Issue
Block a user