Here is a source code with repoduce the bug :
First of all odfaeg is not a problem, it encrypt and decrypt everything well, here is the code of the encryptions class that I wrote :
#include "../../../include/odfaeg/Network/rsa.h"
#include <stdlib.h>
#include <iostream>
namespace odfaeg {
int Rsa::size = 0;
X509* Rsa::x = X509_new();
EVP_PKEY* Rsa::evp_pkey = EVP_PKEY_new();
BIO* Rsa::pub = BIO_new(BIO_s_mem());
size_t Rsa::pub_len = 0;
char* Rsa::pub_key = NULL;
RSA* Rsa::keypair = generateKeys(2048);
int Rsa::getCertificate (unsigned char **out) {
int len= i2d_X509(x, out);
return len;
}
void Rsa::setCertificate(const unsigned char* in, int length) {
x = d2i_X509(NULL,&in,length);
evp_pkey = X509_get_pubkey(x);
keypair = EVP_PKEY_get1_RSA(evp_pkey);
PEM_write_bio_RSAPublicKey(pub, keypair);
pub_len = BIO_pending(pub);
free(pub_key);
pub_key = (char*)malloc(pub_len + 1);
BIO_read(pub, pub_key, pub_len);
pub_key[pub_len] = '\0';
}
int Rsa::encryptWithPrKey (const char *data, size_t dataSize, char **encData) {
*encData = new char[RSA_size(keypair)];
int encDataLen = RSA_private_encrypt(dataSize, (unsigned char*) data, (unsigned char*)*encData, keypair, RSA_PKCS1_PADDING);
if (encDataLen == -1) {
char* err = (char*) malloc(130);
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
free(err);
return FAILURE;
}
return encDataLen;
}
int Rsa::decryptWithPrKey (const char *encData, size_t dataSize, char **data) {
char *msg = new char[dataSize];
int dataLen = RSA_private_decrypt(RSA_size(keypair), (unsigned char*) encData, (unsigned char*)msg, keypair, RSA_PKCS1_OAEP_PADDING);
if (dataLen == -1) {
char* err = (char*) malloc(130);
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
free(err);
}
*data = new char[dataLen+1];
memcpy(*data, msg, dataLen);
(*data)[dataLen] = '\0';
delete[] msg;
return dataLen;
}
int Rsa::encryptWithPbKey (const char *data, size_t dataSize, char **encData) {
*encData = new char[RSA_size(keypair)];
int encDataLen = RSA_public_encrypt(dataSize, (unsigned char*) data, (unsigned char*) *encData, keypair, RSA_PKCS1_OAEP_PADDING);
if (encDataLen == -1) {
char* err = (char*) malloc(130);
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
free(err);
return FAILURE;
}
return encDataLen;
}
int Rsa::decryptWithPbKey (const char *encData, size_t dataSize, char **data) {
char *msg = new char[dataSize];
int dataLen = RSA_public_decrypt(RSA_size(keypair), (unsigned char*) encData, (unsigned char*) msg, keypair, RSA_PKCS1_PADDING);
if (dataLen == -1) {
char* err = (char*) malloc(130);
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
free(err);
return FAILURE;
}
*data = new char[dataLen+1];
memcpy(*data, msg, dataLen);
(*data)[dataLen] = '\0';
delete[] msg;
return dataLen;
}
}
#include "../../../include/odfaeg/Network/aes.h"
namespace odfaeg {
using namespace std;
int AES_ENC::size = 0;
unsigned char* AES_ENC::key = new unsigned char[32];
unsigned char* AES_ENC::iv = new unsigned char[32];
unsigned char* AES_ENC::aesSalt = new unsigned char[8];
EVP_CIPHER_CTX* AES_ENC::e_ctx = new EVP_CIPHER_CTX;
EVP_CIPHER_CTX* AES_ENC::d_ctx = new EVP_CIPHER_CTX;
unsigned char* AES_ENC::aesPass = generateKey(256);
int AES_ENC::encrypt(const char* data, size_t dataSize, char **encData) {
int blockLen = 0;
int encDataLen = 0;
*encData = new char[dataSize + AES_BLOCK_SIZE];
if (!EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), nullptr, key, iv))
return FAILURE;
if (!EVP_EncryptUpdate(e_ctx, (unsigned char*) *encData, &blockLen, (unsigned char*) data, (int) dataSize))
return FAILURE;
encDataLen += blockLen;
if(!EVP_EncryptFinal_ex(e_ctx, (unsigned char*) (*encData+encDataLen), &blockLen)) {
return FAILURE;
}
EVP_CIPHER_CTX_cleanup(e_ctx);
return encDataLen + blockLen;
}
int AES_ENC::decrypt(const char* encData, size_t dataSize, char **data) {
int dataLen = 0;
int blockLen = 0;
*data = new char[dataSize+AES_BLOCK_SIZE];
if (!EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), nullptr, key, iv))
return FAILURE;
if (!EVP_DecryptUpdate(d_ctx, (unsigned char*) *data, &blockLen, (unsigned char*) encData, (int) dataSize))
return FAILURE;
dataLen += blockLen;
if (!EVP_DecryptFinal_ex(d_ctx, (unsigned char*) (*data+dataLen), &blockLen)) {
return FAILURE;
}
dataLen += blockLen;
EVP_CIPHER_CTX_cleanup(d_ctx);
return dataLen;
}
void AES_ENC::setKey(char* sKey) {
strncpy((char*) key, sKey, size / 8);
}
void AES_ENC::setIv(char* sIv) {
strncpy((char*) iv, sIv, size / 8);
}
char* AES_ENC::getKey() {
return (char*) key;
}
char* AES_ENC::getIv() {
return (char*) iv;
}
}
Here is the redefinition of the sf::Packet :
#include "../../../include/odfaeg/Network/symEncPacket.h"
namespace odfaeg {
using namespace std;
using namespace sf;
const void* SymEncPacket::onSend (size_t& dataSize) {
char* buffer = "";
dataSize = AES_ENC::encrypt(static_cast<const char*> (getData()), getDataSize(), &buffer);
return &buffer[0];
}
void SymEncPacket::onReceive (const void* data, size_t dataSize) {
char* buffer = "";
std::size_t dstSize = 0;
dstSize = AES_ENC::decrypt(static_cast<const char*> (data), dataSize, &buffer);
append(&buffer[0], dstSize);
}
}
#include "../../../include/odfaeg/Network/encryptedPacket.h"
#include "../../../include/odfaeg/Network/network.h"
namespace odfaeg {
using namespace std;
using namespace sf;
const void* EncryptedPacket::onSend (size_t& dataSize) {
char* buffer = NULL;
if (Network::getCliInstance().isRunning())
dataSize = Rsa::encryptWithPbKey(static_cast<const char*> (getData()), getDataSize(), &buffer);
else
dataSize = Rsa::encryptWithPrKey(static_cast<const char*> (getData()), getDataSize(), &buffer);
return &buffer[0];
}
void EncryptedPacket::onReceive (const void* data, size_t dataSize) {
char* buffer = NULL;
int newDataSize = 0;
if (Network::getCliInstance().isRunning())
newDataSize = Rsa::decryptWithPbKey(static_cast<const char*> (data), dataSize, &buffer);
else
newDataSize = Rsa::decryptWithPrKey(static_cast<const char*> (data), dataSize, &buffer);
append(&buffer[0], newDataSize);
}
}
It extract and put data in packets very well, the problem is when I want to send the packet with the sf::TcpSocket :
The server :
int main() {
Network::startSrv(10000, 10001);
/*MyServerAppli app;
return app.exec();*/
SocketSelector selector;
TcpListener listener;
listener.listen(9999);
selector.add(listener);
TcpSocket socket;
bool running = true;
std::vector<TcpSocket*> clients;
std::vector<TcpSocket*>::iterator it;
bool keyReceived = false, pbKeyReceived = false;
while (running) {
if (selector.wait()) {
if (selector.isReady(listener)) {
TcpSocket *client = new TcpSocket();
if (listener.accept(*client) == Socket::Done) {
std::cout<<"connect"<<std::endl;
selector.add(*client);
clients.push_back(client);
}
}
for (it = clients.begin(); it != clients.end();it++) {
TcpSocket& client = **it;
if (selector.isReady(client)) {
if (keyReceived && pbKeyReceived) {
SymEncPacket packet;
if (client.receive(packet) == Socket::Done) {
std::string message;
packet>>message;
std::cout<<"received : "<<message<<std::endl;
packet.clear();
message = "SENDRESOURCES";
packet<<message;
client.send(packet);
} else {
std::cout<<"disconnect"<<std::endl;
selector.remove(client);
it = clients.erase(it);
delete &client;
it--;
keyReceived = pbKeyReceived = false;
}
} else if (!keyReceived) {
Packet packet;
if (client.receive(packet) == Socket::Done) {
std::string message;
packet>>message;
if (message == "GETKEY") {
unsigned char* out = NULL;
int length = Rsa::getCertificate(&out);
string key ((char*) out, length);
Packet resp;
resp<<key;
client.send(resp);
keyReceived = true;
}
} else {
selector.remove(client);
it = clients.erase(it);
delete &client;
it--;
keyReceived = pbKeyReceived = false;
}
} else {
EncryptedPacket packet;
if (client.receive(packet) == Socket::Done) {
std::string message;
packet>>message;
packet.clear();
if (message == "GETPBKEY") {
message = std::string(AES_ENC::getKey())+"-"+std::string(AES_ENC::getIv());
packet<<message;
client.send(packet);
pbKeyReceived = true;
}
} else {
selector.remove(client);
it = clients.erase(it);
delete &client;
it--;
keyReceived = pbKeyReceived = false;
}
}
}
}
}
}
}
The client :
int main() {
Network::startCli(10000, 10001, sf::IpAddress::LocalHost);
TcpSocket socket;
socket.connect(IpAddress::LocalHost, 9999);
Packet packet;
std::string message = "GETKEY";
packet<<message;
socket.send(packet);
packet.clear();
if (socket.receive(packet) == Socket::Done) {
message = "";
packet>>message;
Rsa::setCertificate(reinterpret_cast<const unsigned char*>(message.c_str()), message.length());
message = "GETPBKEY";
EncryptedPacket req;
req<<message;
socket.send(req);
}
EncryptedPacket ep;
if (socket.receive(ep) == Socket::Done) {
message = "";
ep>>message;
std::vector<string> parts = split(message, "-");
AES_ENC::setKey(const_cast<char*>(parts[0].c_str()));
AES_ENC::setIv(const_cast<char*>(parts[1].c_str()));
SymEncPacket sep;
message = "GETRESOURCES";
sep<<message;
message = "";
sep>>message;
std::cout<<message<<std::endl;
socket.send(sep);
}
SymEncPacket sep;
if (socket.receive(sep) == Socket::Done) {
message = "";
sep>>message;
std::cout<<message<<std::endl;
}
return 0;
}
Sometimes the message is not transfered correctly, it seems that SFML fails to send some special caracters.