bad decrypt Error OpenSSL C++ & QT AES 256 CBC - c++

I'm trying to add plaintext encryption/decryption (AES 256 CBC) functionality to a personal project built using QT and C++. I'm using OpenSSL v1.1.1. I followed few guides and build a class to handle encryption and decryption. Encryption seems to work fine. But decryption function sometimes throws error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
This works:
sample text here....
These does not ( . = newline ):
i.
sample text here...
.
.
.
.
.
ii.
sample text here... sample text here...
I'm new to QT, C++ and OpenSSL so I have no idea how to fix this.
My Class:
#define KEYSIZE 32
#define IVSIZE 32
#define BLOCKSIZE 256
#define SALTSIZE 8
QByteArray Encryptor::randBytes(int size) {
unsigned char array[size];
RAND_bytes(array, size);
QByteArray output = QByteArray(reinterpret_cast<char*> (array), size);
return output;
}
QByteArray Encryptor::encrypt(QByteArray passphrase, QByteArray &content) {
QByteArray msalt = randBytes(SALTSIZE);
int rounds = 1;
unsigned char key[KEYSIZE];
unsigned char iv[IVSIZE];
const unsigned char *password = (const unsigned char*) passphrase.constData();
const unsigned char *salt = (const unsigned char*) msalt.constData();
int i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, password, passphrase.length(), rounds, key, iv);
if (i != KEYSIZE) {
qCritical() << "EVP_BytesToKey() -- " << ERR_error_string(ERR_get_error(), NULL);
return QByteArray();
}
EVP_CIPHER_CTX *en = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(en);
if (!EVP_EncryptInit_ex(en, EVP_aes_256_cbc(), NULL, key, iv)) {
qCritical() << "EVP_EncryptInit_ex() -- " << ERR_error_string(ERR_get_error(), NULL);
return QByteArray();
}
char *input = content.data();
char *out;
int length = content.size();
int cLength = length + AES_BLOCK_SIZE;
int fLength = 0;
unsigned char *cipherText = (unsigned char*) malloc(cLength);
if (!EVP_EncryptInit_ex(en, NULL, NULL, NULL, NULL)) {
qCritical() << "EVP_EncryptInit_ex() -- " << ERR_error_string(ERR_get_error(), NULL);
return QByteArray();
}
if (!EVP_EncryptUpdate(en, cipherText, &cLength, (unsigned char*) input, length)) {
qCritical() << "EVP_EncryptUpdate() -- " << ERR_error_string(ERR_get_error(), NULL);
free(cipherText);
return QByteArray();
}
if (!EVP_EncryptFinal(en, cipherText + cLength, &fLength)) {
qCritical() << "EVP_EncryptFinal() -- " << ERR_error_string(ERR_get_error(), NULL);
free(cipherText);
return QByteArray();
}
length = cLength + fLength;
out = (char*) cipherText;
EVP_CIPHER_CTX_cipher(en);
free(cipherText);
QByteArray output;
output.append("Salted__");
output.append(msalt);
output.append(out, length);
return output;
}
QByteArray Encryptor::decrypt(QByteArray passphrase, QByteArray &content) {
QByteArray msalt;
if (QString(content.mid(0, 8)) != "Salted__") {
qCritical() << "can not extrect the salt...";
return QByteArray();
}
msalt = content.mid(8, 8);
content = content.mid(16);
int rounds = 1;
unsigned char key[KEYSIZE];
unsigned char iv[IVSIZE];
const unsigned char *password = (const unsigned char*) passphrase.constData();
const unsigned char *salt = (const unsigned char*) msalt.constData();
int i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, password, passphrase.length(), rounds, key, iv);
if (i != KEYSIZE) {
qCritical() << "EVP_BytesToKey() -- " << ERR_error_string(ERR_get_error(), NULL);
return QByteArray();
}
EVP_CIPHER_CTX *de = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(de);
if (!EVP_DecryptInit_ex(de, EVP_aes_256_cbc(), NULL, key, iv)) {
qCritical() << "EVP_DecryptInit_ex() -- " << ERR_error_string(ERR_get_error(), NULL);
return QByteArray();
}
char *input = content.data();
int length = content.size();
int pLength = length;
int fLength = 0;
unsigned char *plainText = (unsigned char*) malloc(pLength + AES_BLOCK_SIZE);
if (!EVP_DecryptUpdate(de, plainText, &pLength, (unsigned char*) input, length)) {
qCritical() << "EVP_DecryptUpdate() -- " << ERR_error_string(ERR_get_error(), NULL);
free(plainText);
return QByteArray();
}
if (!EVP_DecryptFinal_ex(de, plainText + pLength, &fLength)) {
qCritical() << "EVP_DecryptFinal_ex() -- " << ERR_error_string(ERR_get_error(), NULL);
free(plainText);
return QByteArray();
}
length = pLength + fLength;
EVP_CIPHER_CTX_cleanup(de);
QByteArray output = QByteArray(reinterpret_cast<char*> (plainText), length);
free(plainText);
return output;
}

Related

RSA_Verify fails returns Bad signature error

I can't get the message verified after signing it.
I'm writing a project to simulate signing and verifying data from files with OpenSSL.
the signing process seems to work great, but on the verification process RSA_Verify always return 0. which is not verified.
I can't get it. what am I missing here?
#include <string>
#include <fstream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/applink.c>
#include <openssl/err.h>
#define PRIKEY_FILENAME "private"
#define PUBKEY_FILENAME "public"
using namespace std;
typedef struct _INFO
{
unsigned char *sig;
unsigned int nLen;
}INFO, *pINFO;
bool ReadFileContent(string fileName, char** out, size_t &nLen)
{
if (NULL == out)
return false;
ifstream file(fileName, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
nLen = (int)file.tellg();
*out = new char[nLen];
file.seekg(0, ios::beg);
file.read(*out, nLen);
file.close();
}
else
{
cout << "Unable to open file \"" << fileName << " \"\n";
return false;
}
return true;
}
bool WriteFileContent(const char* data, int nLen, string fileName)
{
if (NULL == data)
return false;
ofstream file(fileName, ios::out | ios::binary | ios::ate);
if (file.is_open())
{
file.write(data, nLen);
file.close();
}
else
{
cout << "Unable to open file \"" << fileName << " \"\n";
return false;
}
return true;
}
bool GenerateKeyPairs()
{
int ret = 0;
RSA *r = NULL;
BIGNUM *bne = NULL;
BIO *bp_public = NULL, *bp_private = NULL;
int bits = 2048;
unsigned long e = RSA_F4;
// 1. generate rsa key
bne = BN_new();
ret = BN_set_word(bne, e);
if (ret != 1)
{
goto free_all;
}
r = RSA_new();
ret = RSA_generate_key_ex(r, bits, bne, NULL);
if (ret != 1)
{
goto free_all;
}
// 2. save public key
bp_public = BIO_new_file(PUBKEY_FILENAME, "w+");
ret = PEM_write_bio_RSAPublicKey(bp_public, r);
if (ret != 1)
{
goto free_all;
}
// 3. save private key
bp_private = BIO_new_file(PRIKEY_FILENAME, "w+");
ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
// 4. free
free_all:
BIO_free_all(bp_public);
BIO_free_all(bp_private);
RSA_free(r);
BN_free(bne);
return (ret == 1);
}
bool DoSign(string priKeyFile, pINFO pInfo, string fileName)
{
int ret;
unsigned char* data = NULL;
unsigned char* encodedData = NULL;
size_t nFileSize = 0;
unsigned int nEncodedDataLen = 0;
RSA* priKey = NULL;
FILE* fp = NULL;
if (!ReadFileContent(fileName, (char**)&data, nFileSize))
{
return false;
}
if (data == NULL || nFileSize <= 0)
return false;
//SHA512(data, nFileSize, pInfo->sig);
fp = fopen(PRIKEY_FILENAME, "r");
priKey = PEM_read_RSAPrivateKey(fp, &priKey, NULL, NULL);
pInfo->sig = (unsigned char*)malloc(RSA_size(priKey));
/* Sign */
ret = RSA_sign(NID_sha512, data, nFileSize, pInfo->sig, &pInfo->nLen, priKey);
WriteFileContent((char*)pInfo->sig, pInfo->nLen, fileName + ".sign");
return true;
}
bool DoVerify(string pubKeyFile, pINFO pInfo, string fileName)
{
int ret = 0;
unsigned char* data = NULL;
unsigned char* encodedData = NULL;
size_t nFileSize = 0;
FILE* fp = NULL;
RSA* pubkey = NULL;
unsigned int nEncodedDataLen = 0;
if (!ReadFileContent(fileName, (char**)&data, nFileSize))
{
return false;
}
if (data == NULL || nFileSize <= 0)
return false;
fp = fopen(PUBKEY_FILENAME, "r");
pubkey = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
ret = RSA_verify(NID_sha512, data, nFileSize, pInfo->sig, pInfo->nLen, pubkey);
char buf[512];
ERR_error_string(ERR_get_error(), buf);
//Error here says bad signature
return true;
}
int main()
{
INFO info = { 0 };
GenerateKeyPairs();
DoSign(PRIKEY_FILENAME, &info, "Hello.txt");
DoVerify(PUBKEY_FILENAME, &info, "Hello.txt.sign");
return 0;
}
It should return 1 in RSA_Sign.
DoVerify(PUBKEY_FILENAME, &info, "Hello.txt.sign");
This should be:
DoVerify(PUBKEY_FILENAME, &info, "Hello.txt");
The signature itself is being passed through the &info parameter. The last parameter is supposed to be the actual thing signed, not the signature.

How to get privatekey in openssl ecc with the format hex

code:
EC_KEY *key;
if (NULL == (key = EC_KEY_new_by_curve_name(NID_secp224r1)))
handleErrors();
if (1 > EC_KEY_generate_key(key)) handleErrors();
const BIGNUM *prv = EC_KEY_get0_private_key(key);
const EC_GROUP *group = EC_KEY_get0_group(key);
const EC_POINT *pub = EC_KEY_get0_public_key(key);
char* hexPubkey = EC_POINT_point2hex(group, pub, EC_KEY_get_conv_form(key), NULL);
char* hexPrikey=BN_bn2hex(prv);
my result:
hexPubkey:04EAD3AF4BA89F513B2D89FC749C43CC7B95523F1BD40A5713C5228F91B5F928D43B396C64A3293053550065C02E9A06B4FB078C4944BD0933
length:57
hexPrikey:5D5356F3551602A89710DA40CC24FB6CDBB851FE612C977C9AB0F393
length:114
correct result:
hexPubkey:04381987517AEEDB6F83FAA0EB60EFF4C1B7A78D66FF17CB04D92B37588826A64B78E0B3A965C72438860D4B3897893BB31397D1625EEA0E41
length:57
hexPrikey:30820144020101041C20F21D6B7FE0D5E1D21C6B57AFE6FAD8A5A5AC31AE0596B972E01877A081E23081DF020101302806072A8648CE3D0101021D00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000013053041CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE041CB4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4031500BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5043904B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34021D00FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D020101A13C033A0004381987517AEEDB6F83FAA0EB60EFF4C1B7A78D66FF17CB04D92B37588826A64B78E0B3A965C72438860D4B3897893BB31397D1625EEA0E41
length:328
From the length of the private key, my private key is obviously wrong, isn't it my writing method wrong?
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_ECPrivateKey(bio, key, NULL, NULL, 0, NULL, NULL);
int keylen = BIO_pending(bio);
char *pem_key = (char *) calloc(keylen + 1, 1);
BIO_read(bio, pem_key, keylen);
cout << pem_key << endl;
BIO_free_all(bio);
EC_KEY_free(key);
free(pem_key);

decrypt/encrypt large data using RSA public key

I wan encrypt large DATA using an RSA public key then decrypt it using the private key
So my encryption function is :
unsigned char* encryptFile::rsaEncrypt( RSA *pubKey, const unsigned char* msg, int msg_len, int *enc_len )
{
int rsa_size = RSA_size(pubKey);
int block_size = rsa_size - 12;
int blocks = msg_len/block_size;
int rest = msg_len % block_size;
unsigned char* enc = 0;
int curr_len = 0;
int i = 0;
if (0 == rest) {
enc = (unsigned char*)malloc(blocks*rsa_size + 1);
}
else {
enc = (unsigned char*)malloc((blocks+1)*rsa_size + 1);
}
for (i = 0; i < blocks; i++) {
if (0 > (curr_len = RSA_public_encrypt(block_size , msg + i*block_size, enc + i*rsa_size, pubKey, RSA_PKCS1_PADDING))) {
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
*enc_len += curr_len;
}
if (0 != rest) {
if (0 > (curr_len = RSA_public_encrypt(rest , msg + i*block_size, enc + i*rsa_size, pubKey, RSA_PKCS1_PADDING))) {
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
*enc_len += curr_len;
}
if( *enc_len == -1 )
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
cout << *enc_len << endl;
return enc;
}
And it's working fine !
Now when i want decrypt it i'm using this code
int rsa_size = RSA_size(privKey);
int msg_len = encBinLen;
int block_size = rsa_size;
int blocks = msg_len/block_size;
int rest = msg_len % block_size;
unsigned char* enc = 0;
int curr_len = 0;
enc_len = 0;
int i = 0;
if (0 == rest) {
enc = (unsigned char*)malloc(blocks*rsa_size + 1);
}
else {
enc = (unsigned char*)malloc((blocks+1)*rsa_size + 1);
}
for (i = 0; i < blocks; i++) {
if (0 > (curr_len = RSA_private_decrypt(block_size , msg + i*block_size, enc + i*rsa_size, privKey, RSA_PKCS1_PADDING))) {
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
enc_len += curr_len;
}
if (0 != rest) {
if (0 > (curr_len = RSA_private_decrypt(rest , msg + i*block_size, enc + i*rsa_size, privKey, RSA_PKCS1_PADDING))) {
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
enc_len += curr_len;
}
if( enc_len == -1 )
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
cout << enc;
Anyway when i run that some of the data got decrypted but i still see some weird chars as in seen in this picture
So i just want understand what i'm doing wrong ?
The solution is to use hybrid encryption !
Thnks to Artjom B. & zaph
I think you should use enc_len instead of i*rsa_size as shifter for output in RSA_private_decrypt(block_size , msg + i*block_size, enc + i*rsa_size, privKey, RSA_PKCS1_PADDING) call.

Generate encrypted data with size not multiple of 16

I want to develop functions for encrypt and decrypt. the key size should be at least 128 bits (16 bytes).
I used the AES* api functions from the OpenSSL. but there is some restriction in the AES* functions: the input data buffers should be multiple of 16!
Here after my functions:
unsigned char encrypt_aes_key[]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
static inline int enc_array_decrypt(unsigned char *encarray, unsigned char *decarray, int size)
{
int i;
AES_KEY dec_key;
unsigned char apibuf[512] = {0};
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0x00, AES_BLOCK_SIZE);
AES_set_decrypt_key(encrypt_aes_key, sizeof(encrypt_aes_key)*8, &dec_key); // Size of key is in bits
AES_cbc_encrypt(encarray, apibuf, size, &dec_key, iv, AES_DECRYPT);
memcpy(decarray, apibuf, size);
return 0;
}
static inline int enc_array_encrypt(unsigned char *array, unsigned char *encarray, int size)
{
int i;
AES_KEY enc_key;
unsigned char apibuf[512] = {0};
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0x00, AES_BLOCK_SIZE);
AES_set_encrypt_key(encrypt_aes_key, sizeof(encrypt_aes_key)*8, &enc_key); // Size of key is in bits
AES_cbc_encrypt((unsigned char *)array, apibuf, size, &enc_key, iv, AES_ENCRYPT);
memcpy(encarray, apibuf, size);
return 0;
}
if I call my functions with buffer size 9 for example, the functions will return wron output
example:
int main(int argc, char *argv[] )
{
char buf[9] = {0}, encbuf[9] = {0}, decbuf[9] = {0};
strcpy(buf, argv[1]);
enc_array_encrypt(buf, encbuf, 9);
enc_array_decrypt(encbuf, decbuf, 9);
printf("%s \n%s\n", buf, decbuf);
return 0;
}
The program returns:
$ ./myprogram any
any
2�����S�
How I can fix that?
by the way I can not force the buffer to be 16x multiplier size. because I will integrate my functions in a big source code (SDK) in which I will call my functions in many places with different input buffer sizes.
I m open to use any other kind of encryption (other than AES), but should support key of 128 bits length. The input buffer and the encrypted buffer should have the same size
It's generally not recommended to use the AES* function directly in OpenSSL. It's better to use the EVP family of functions. These will allow you to give an input buffer of any length.
void log_ssl_err(const char *mes)
{
unsigned long err;
char errstr[1000];
while ((err = ERR_get_error())) {
ERR_error_string(err, errstr);
printf("%s: %s", mes, errstr);
}
}
int encrypt_block(const unsigned char *IV, const unsigned char *key,
const unsigned char *src, unsigned int srclen,
unsigned char *dest, unsigned int *destlen)
{
EVP_CIPHER_CTX ctx;
const EVP_CIPHER *cipher = EVP_get_cipherbyname("AES-256-CBC");
int mode, len;
if (cipher == NULL) {
printf("Invalid keytype");
return 0;
}
mode = EVP_CIPHER_mode(cipher);
EVP_CIPHER_CTX_init(&ctx);
if (!EVP_EncryptInit_ex(&ctx, cipher, NULL, NULL, NULL)) {
log_ssl_err("EncryptInit for cipher failed");
return 0;
}
if (!EVP_EncryptInit_ex(&ctx, NULL, NULL, key, IV)) {
log_ssl_err("EncryptInit for key/IV failed");
return 0;
}
len = 0;
if (!EVP_EncryptUpdate(&ctx, dest, &len, src, srclen)) {
log_ssl_err("EncryptUpdate for data failed");
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
*destlen = len;
if (!EVP_EncryptFinal_ex(&ctx, dest + *destlen, &len)) {
log_ssl_err("EncryptFinal failed");
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
*destlen += len;
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}
int decrypt_block(const unsigned char *IV, const unsigned char *key,
unsigned char *src, unsigned int srclen,
unsigned char *dest, unsigned int *destlen)
{
EVP_CIPHER_CTX ctx;
const EVP_CIPHER *cipher = EVP_get_cipherbyname("AES-256-CBC");
int mode, len;
if (cipher == NULL) {
printf("Invalid keytype");
return 0;
}
mode = EVP_CIPHER_mode(cipher);
EVP_CIPHER_CTX_init(&ctx);
if (!EVP_DecryptInit_ex(&ctx, cipher, NULL, NULL, NULL)) {
log_ssl_err("DecryptInit for cipher failed");
return 0;
}
if (!EVP_DecryptUpdate(&ctx, dest, &len, src, srclen)) {
log_ssl_err("DecryptUpdate for data failed");
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
*destlen = len;
if (!EVP_DecryptFinal_ex(&ctx, dest + *destlen, &len)) {
log_ssl_err("DecryptFinal failed");
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
*destlen += len;
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}

how to correct convert char to byte in C++

I have some problem.
I write next code.
z=recv(conn,buff,512,0);//"Hi VahagnAAAAAAA" - but encrypted for example "zЖWЙЇ%ЂАЊ"S]яАAЧ0АбЯ.Щk5S¤Oц", length 32
BYTE messageLen = (BYTE)strlen(buff);// messageLen = 32
BYTE encryptedMessage[32];
memcpy(encryptedMessage, buff, messageLen);//!!!!!!!!!!!
DWORD encryptedMessageLen = messageLen;
CryptDecrypt(hSessionKeyRSA_2,NULL,TRUE,0,encryptedMessage, &encryptedMessageLen);
cout<<encryptedMessage<<endl;
I recv to buffer char array 32 length.
Where I copy encrypted text
"zЖWЙЇ%ЂАЊ"S]яАAЧ0АбЯ.Щk5S¤Oц"
to byte array, on the encryptedMessage have next value
"zЖWЙЇ%ЂАЊ"S]яАAЧ0АбЯ.Щk5S¤OцMMMMMMMMMMMMMMMMMMM"
where I decrypted I don't get start text, I get
"Ik VqagnеAAcS]‰МММММММММММ ММММММММ"
How I can fix it? please help me.
UPDATE
Client main()
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
const char* servername="127.0.0.1";
Sleep(2000);
setlocale(LC_ALL, "Russian");
WSADATA wsaData;
struct hostent *hp;
unsigned int addr;
struct sockaddr_in server;
int wsaret=WSAStartup(0x101,&wsaData);
if(wsaret)
return 0;
SOCKET conn;
conn=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(conn==INVALID_SOCKET)
return 0;
if(inet_addr(servername)==INADDR_NONE)
{
hp=gethostbyname(servername);
}
else
{
addr=inet_addr(servername);
hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
}
if(hp==NULL)
{
closesocket(conn);
return 0;
}
server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
server.sin_family=AF_INET;
server.sin_port=htons(20248);
if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
{
closesocket(conn);
return 0;
}
std::cout<<"Connected to server";
char buff[512];
memset(buff,'\0',512);
int z;
z=recv(conn,(char*)exportRSAKey,140,0);//Import RSA key
z=recv(conn,(char*)exportAESKey,140,0);//Import AES key
z=recv(conn,buff,512,0);//Get encryption text
importKey();//import key to client
BYTE messageLen = (BYTE)strlen(buff);
BYTE encryptedMessage[33];
memcpy(encryptedMessage, buff, messageLen);
DWORD encryptedMessageLen = messageLen;
CryptDecrypt(hSessionKeyRSA_2,NULL,FALSE,0,encryptedMessage, &encryptedMessageLen);
cout<<encryptedMessage<<endl;
// buff[z]=0;
}
Import key to client
if (CryptAcquireContext(&hCryptProv_RSA_2, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0))
{
printf("A cryptographic provider has been acquired.\r\n");
}
else
{
DWORD d = GetLastError();
return -1;
}
int iii = CryptImportKey(hCryptProv_RSA_2,(BYTE *)&exportAESKey,140,NULL,NULL,&hSessionKeyRSA_2);
if(CryptSetKeyParam(hSessionKeyRSA_2, KP_IV, exportRSAKey, 0))
{
cout<<"ok";
}
Server main()
std::cout<<"Client connected... "<<pParam<<std::endl;
char buff[512];
CString cmd;
CString params;
int n;
int x;
BOOL auth=false;
SOCKET client=(SOCKET)pParam;
strcpy(buff,"#Server Ready.\r\n");
char keybuff[1024];
createRSAPublicKey();//create enc_dec key
//keybuff = exportRSAKey;
//memset(rec,'\0',512);
const char *p = reinterpret_cast<const char*>(exportRSAKey);
send(client,p,140,0);//send RSA
const char *pp = reinterpret_cast<const char*>(exportAESKey);
send(client,pp,140,0);//Send AES
const char *ppp = reinterpret_cast<const char*>(encryptedMessage);
send(client,ppp,512,0);//Send encrypt text
createRSAPublicKey()
BOOL createRSAPublicKey()
{
if (CryptAcquireContext(&hCryptProv_AES, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0))
{
printf("A cryptographic provider has been acquired.\r\n");
}
else
{
DWORD d = GetLastError();
return -1;
}
HCRYPTKEY hSessionKey_AES;
if (!CryptGenKey(hCryptProv_AES, CALG_AES_256, CRYPT_EXPORTABLE, &hSessionKey_AES))
{
DWORD d = GetLastError();
return -1;
}
// Create RSA key to encrypt AES one
HCRYPTKEY hSessionKey;
if (!CryptGenKey(hCryptProv_AES, AT_KEYEXCHANGE, 1024 << 16, &hSessionKey))
{
DWORD d = GetLastError();
return -1;
}
// Export key
DWORD keylen;
BOOL ok = CryptExportKey(hSessionKey_AES, hSessionKey, SIMPLEBLOB, 0, exportRSAKey, &keylen);
if (ok == FALSE)
{
DWORD d = GetLastError();
return -1;
}
BYTE *encKey = (BYTE *)malloc(keylen);
ok = CryptExportKey(hSessionKey_AES, hSessionKey, SIMPLEBLOB, 0, exportAESKey, &keylen);
if (ok == FALSE)
{
DWORD d = GetLastError();
return -1;
}
else
printf("A cryptographic key export succeeded.\r\n");
BYTE messageLen = (BYTE)strlen(mess);
memcpy(encryptedMessage, mess, messageLen);
DWORD encryptedMessageLen = messageLen;
CryptEncrypt(hSessionKey_AES, NULL, TRUE, 0, encryptedMessage, &encryptedMessageLen, sizeof(encryptedMessage));
}
You are using strlen() to get the length of buff, but recv() does not null-terminate the buffer unless a null terminator was actually transmitted and read. You should instead be using the return value of recv(), which is the number of bytes actually read:
z=recv(conn,buff,512,0);
messageLen = z;//(BYTE)strlen(buff);
That being said, TCP is a byte stream, it has no concept of message boundaries. There is no 1-to-1 relationship between send() and recv() in TCP, like there is in UDP, so recv() above could read as little as 1 byte or as many as 512 bytes, and buff could contain a full message, a partial message, pieces of multiple messages, etc. You can't just blindly read and expect to receive everything in one go. You need to take all of that into account.
Design your TCP protocol to delimit messages, either with a preceding header that specifies the message length, or a trailing delimiter that never appears in the message body. Call recv() as many times as it takes, buffering any received data, and only process/decrypt complete messages that are in your buffer, leaving partial message data in the buffer to be completed by later reads.
Try something more like this:
Client main()
int readBuffer(SOCKET s, void *buffer, int buflen)
{
unsigned char *pbuf = (unsigned char*) buffer;
int total = 0;
while (total < buflen)
{
int num = recv(s, pbuf+total, buflen-total, 0);
if (num < 0)
return SOCKET_ERROR;
if (num == 0)
return 0;
total += num;
}
return total;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
const char* servername="127.0.0.1";
setlocale(LC_ALL, "Russian");
WSADATA wsaData;
memset(&wsaData, 0, sizeof(wsaData));
int wsaret = WSAStartup(0x101, &wsaData);
if (wsaret != 0)
return 0;
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_addr.s_addr = inet_addr(servername);
if (server.sin_addr.s_addr == INADDR_NONE)
{
struct hostent *hp = gethostbyname(servername);
if (hp == NULL)
return 0;
server.sin_addr = *((in_addr*)hp->h_addr);
}
server.sin_family = AF_INET;
server.sin_port = htons(20248);
SOCKET conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (conn == INVALID_SOCKET)
return 0;
if (connect(conn, (struct sockaddr*)&server, sizeof(server)) != 0)
{
closesocket(conn);
return 0;
}
std::cout << "Connected to server";
if (readBuffer(conn, exportRSAKey, 140) <= 0) //Import RSA key
{
closesocket(conn);
return 0;
}
if (readBuffer(conn, exportAESKey, 140) <= 0) //Import AES key
{
closesocket(conn);
return 0;
}
importKey();//import key to client
DWORD messageLen;
if (readBuffer(conn, &messageLen, sizeof(messageLen)) <= 0) //Get encryption text length
{
closesocket(conn);
return 0;
}
messageLen = ntohl(messageLen);
std::vector<BYTE> buff(messageLen);
if (messageLen > 0)
{
if (readBuffer(conn, &buff[0], messageLen) <= 0) //Get encryption text
{
closesocket(conn);
return 0;
}
if (!CryptDecrypt(hSessionKeyRSA_2, NULL, FALSE, 0, &buff[0], &messageLen))
{
closesocket(conn);
return 0;
}
}
std::cout << std::string((char*)buff.data(), messageLen) << std::endl;
}
Server main()
int sendBuffer(SOCKET s, void *buffer, int buflen)
{
unsigned char *pbuf = (unsigned char*) buffer;
int total = 0;
while (total < buflen)
{
int num = send(s, pbuf+total, buflen-total, 0);
if (num < 0)
return SOCKET_ERROR;
if (num == 0)
return 0;
total += num;
}
return total;
}
...
SOCKET client = (SOCKET)pParam;
std::cout << "Client connected... " << pParam << std::endl;
...
createRSAPublicKey();//create enc_dec key
...
if (sendBuffer(client, exportRSAKey, 140) <= 0) //send RSA
{
closesocket(client);
return;
}
if (sendBuffer(client, exportAESKey, 140) <= 0) //Send AES
{
closesocket(client);
return;
}
...
DWORD tmpMessageLen = htonl(messageLen);
if (sendBuffer(client, &tmpMessageLen, sizeof(tmpMessageLen)); //Send encrypt text length
{
closesocket(client);
return;
}
if (sendBuffer(client, encryptedMessage, messageLen) <= 0) //Send encrypt text
{
closesocket(client);
return;
}
...