I have problem with OpenSSL AES ( I use aes.h ) :
get binary file (.pdf , .jpg ) or some .xml , .txt about 5000 chars , then i enrypt base64.
When I try enrypt AES i get bad size ( Random 400 , 200 , 50 ) , my AESKey is random 128bits from chars : [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.-##&*oeOE¯_ ]
I think that problem is '\0' enrypted char but i don't know can I extort entry
(string can save char array with \0 element but unsigned char* and char* is aborted )
this is my code :
std::string PFHelper::ASE_encode(std::string in, wchar_t* KS)
{
//const unsigned char* aes_input = reinterpret_cast<const unsigned char *> (in.c_str());
unsigned char* aes_input = new unsigned char[in.length()];
strcpy((char*)aes_input, in.c_str());
std::string KS_string = PFHelper::ConvertFromUtf8ToString(KS);
unsigned char* aes_key = new unsigned char[16];
strcpy((char*)aes_key, KS_string.c_str());
/* Input data to encrypt */
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0x00, AES_BLOCK_SIZE);
const size_t encslength = ((in.length() + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
/* Buffers for Encryption and Decryption */
unsigned char * enc_out = new unsigned char [encslength];
//unsigned char * dec_out = new unsigned char[in.length()];
memset(enc_out, 0, encslength);
//memset(dec_out, 0, in.length());
AES_KEY enc_key;
AES_set_encrypt_key(aes_key, 128, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, encslength, &enc_key, iv, AES_ENCRYPT);
//AES_KEY decrypt;
//memset(iv, 0x00, AES_BLOCK_SIZE);
//AES_cbc_encrypt((unsigned char*)enc_out, dec_out, encslength, &decrypt, iv, AES_DECRYPT);
//std::string returned = ConvertFromUnsignedCharToString(enc_out);
memset(aes_key, 0x00, 16);
memset(aes_input, 0x00, in.length());
return ConvertFromUnsignedCharToString(enc_out);
}
Sample value :
KS (AESKey) : L"F-ZTNW meOJLK1s5"
in(5464chars) : PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVR.....
out(51chars) : "©¦ľ‘Ň·rnoŚ8nžęwřëůl2ěY ßJ2¨ßňO× ohX‚Ž~ŚČ”E
I try EVP and typical char key and problem is the same
//set back to normal
unsigned char* aes_input = new unsigned char[in.length()];
strcpy((char*)aes_input, in.c_str());
unsigned char* dec_out = new unsigned char[in.length()];
memset(dec_out, 0, in.length());
dec_out[in.length()] = '\0';
/* A 256 bit key */
unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"01234567890123456";
int lenght;
int c_len = in.length() + AES_BLOCK_SIZE;
//Set up encryption
int f_len = 0;
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
{
wcout << L"1";
}
if (EVP_EncryptUpdate(ctx, dec_out, &lenght, aes_input, in.length()) != 1)
{
wcout << L"2";
}
if (EVP_EncryptFinal_ex(ctx, dec_out, &lenght) != 1)
{
wcout << L"3";
}
return ConvertFromUnsignedCharToString(dec_out);
}
Here's an example which demonstrates how to use std::strings to manage buffers while using OpenSSL's EVP interfaces. It also avoids the extra copying you are doing. You still need to improve your keying strategy.
You should provide a zeroize'ing allocator. You should consider an Authenticated Encryption mode.
Compile it with g++ -std=c++11 test.cxx -o test.exe -lcrypto.
#include <iostream>
#include <string>
#include <memory>
#include <stdexcept>
using namespace std;
#include <openssl/evp.h>
#include <openssl/rand.h>
static const unsigned int KEY_SIZE = 16;
static const unsigned int BLOCK_SIZE = 16;
typedef unsigned char byte;
using EVP_CIPHER_CTX_free_ptr = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;
void gen_keys(byte key[KEY_SIZE], byte iv[BLOCK_SIZE]);
void encrypt(const byte key[KEY_SIZE], const byte iv[BLOCK_SIZE], const string& ptext, string& ctext);
void decrypt(const byte key[KEY_SIZE], const byte iv[BLOCK_SIZE], const string& ctext, string& rtext);
int main(int argc, char* argv[])
{
// plaintext, ciphertext, recovered text
string ptext = "Now is the time for all good men to come to the aide of their country";
string ctext, rtext;
byte key[KEY_SIZE], iv[BLOCK_SIZE];
gen_keys(key, iv);
encrypt(key, iv, ptext, ctext);
decrypt(key, iv, ctext, rtext);
cout << "Recovered message:\n" << rtext << endl;
return 0;
}
void gen_keys(byte key[KEY_SIZE], byte iv[BLOCK_SIZE])
{
int rc = RAND_bytes(key, KEY_SIZE);
if (rc != 1)
throw runtime_error("RAND_bytes key failed");
rc = RAND_bytes(iv, BLOCK_SIZE);
if (rc != 1)
throw runtime_error("RAND_bytes for iv failed");
}
void encrypt(const byte key[KEY_SIZE], const byte iv[BLOCK_SIZE], const string& ptext, string& ctext)
{
EVP_CIPHER_CTX_free_ptr ctx(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
int rc = EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_cbc(), NULL, key, iv);
if (rc != 1)
throw runtime_error("EVP_EncryptInit_ex failed");
// Cipher text will be upto 16 bytes larger than plain text
ctext.resize(ptext.size()+16);
int out_len1 = (int)ctext.size();
rc = EVP_EncryptUpdate(ctx.get(), (byte*)&ctext[0], &out_len1, (const byte*)&ptext[0], (int)ptext.size());
if (rc != 1)
throw runtime_error("EVP_EncryptUpdate failed");
int out_len2 = (int)ctext.size() - out_len1;
rc = EVP_EncryptFinal_ex(ctx.get(), (byte*)&ctext[0]+out_len1, &out_len2);
if (rc != 1)
throw runtime_error("EVP_EncryptFinal_ex failed");
ctext.resize(out_len1 + out_len2);
}
void decrypt(const byte key[KEY_SIZE], const byte iv[BLOCK_SIZE], const string& ctext, string& rtext)
{
EVP_CIPHER_CTX_free_ptr ctx(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
int rc = EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_cbc(), NULL, key, iv);
if (rc != 1)
throw runtime_error("EVP_DecryptInit_ex failed");
// Recovered text will be smaller than cipher text, not larger
rtext.resize(ctext.size());
int out_len1 = (int)rtext.size();
rc = EVP_DecryptUpdate(ctx.get(), (byte*)&rtext[0], &out_len1, (const byte*)&ctext[0], (int)ctext.size());
if (rc != 1)
throw runtime_error("EVP_DecryptUpdate failed");
int out_len2 = (int)rtext.size() - out_len1;
rc = EVP_DecryptFinal_ex(ctx.get(), (byte*)&rtext[0]+out_len1, &out_len2);
if (rc != 1)
throw runtime_error("EVP_DecryptFinal_ex failed");
rtext.resize(out_len1 + out_len2);
}
Related
I have some openssl code that encrypts and decrypts a file.
Initially I wrote it so the encrypted file is base64 encoded. The problem is certain file sizes are reduced on decryption. i.e I lose upto 16 characters in the decrypted based on the original file
If the file is less that 16 bytes it is fine, greater than that and I start losing characters on decryption with and error on the final decrypt step.
I assumed initially it was a padding issue, but adding padding does bot fix however If I remove the base64 encoding it is fine however.
This is based on open_ssl 1.1.1s
int BIO_enc_header(BIO* file, unsigned char* Salt)
{
RAND_bytes(Salt, SALTSIZE);
int len=BIO_write(file,MAGIC, MAGIC_SIZE);
len=BIO_write(file,Salt, SALTSIZE);
return 0;
}
int BIO_dec_header(BIO* file, unsigned char* Salt)
{
int mlen = 0;
char mBuff[MAGIC_SIZE + 1] = { 0 };
mlen = BIO_read(file,mBuff, MAGIC_SIZE);
if (mlen == MAGIC_SIZE) {
/* Check Magic size */
int salt_len = BIO_read(file,Salt,SALTSIZE);
if (salt_len != SALTSIZE) {
return -1;
}
}
return 0;
}
//#define BASE64 1
int do_crypt_bio(BIO* bio_in, BIO* bio_out, int do_encrypt, unsigned char* szPassword)
{
int Result = OK;
unsigned char salt[8] = { 0 };
int inByte = 0, outByte = 0;
//int Padding;
#ifdef BASE64
BIO *b64 = BIO_new(BIO_f_base64());
if (!b64) {
return ERROR;
}
#endif
#ifdef BASE64
if (do_encrypt) {
/*out base64*/
bio_out = BIO_push(b64, bio_out);
BIO_set_flags(bio_out, BIO_FLAGS_BASE64_NO_NL);
}else {
/* read base 64*/
bio_in = BIO_push(b64, bio_in);
BIO_set_flags(bio_in, BIO_FLAGS_BASE64_NO_NL);
}
#endif
/* Allow enough space in output buffer for additional block */
unsigned char inbuf[ENC_BUFF_SIZE+ EVP_MAX_BLOCK_LENGTH], outbuf[ENC_BUFF_SIZE + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
EVP_CIPHER_CTX* ctx=NULL;
#define AES_256_KEY_SIZE 32
unsigned char key[AES_256_KEY_SIZE] = { 0 };
unsigned char iv[AES_BLOCK_SIZE] = { 0 };
int rounds = 5;
int Size=EVP_CIPHER_block_size(EVP_aes_256_cbc());
if (do_encrypt) {
BIO_enc_header(bio_out, salt);
}else {
BIO_dec_header(bio_in, salt);
}
if (!EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), salt, szPassword, strlen((char*)szPassword), rounds, key, iv)) {
#ifdef BASE64
BIO_free(b64);
#endif
return ERROR;
}
/* Don't set key or IV right away; we want to check lengths */
ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
#ifdef BASE64
BIO_free(b64);
#endif
return ERROR;
}
int CipherResult=EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL, NULL, NULL, do_encrypt);
CipherResult =EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt); /* Now we can set key and IV */
//EVP_CIPHER_CTX_set_padding(ctx, 32);
int len;
for (;;) {
memset(inbuf, 0, ENC_BUFF_SIZE+EVP_MAX_BLOCK_LENGTH);
inlen = BIO_read(bio_in,inbuf, ENC_BUFF_SIZE);
//inByte += inlen;
if (inlen <= 0)break;
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
/* Error */
Result = ERROR;
goto error;
}
len=BIO_write(bio_out,outbuf,outlen);
//outByte += outlen;
}
int f_len;
if (!EVP_CipherFinal_ex(ctx, outbuf, &f_len)) {
/* Error */
Result = ERROR;
ERR_print_errors_fp(stderr);
goto error;
}
len= BIO_write(bio_out, outbuf, f_len);
//outByte += f_len;
len = len;
error:
EVP_CIPHER_CTX_free(ctx);
#ifdef BASE64
BIO_free(b64);
#endif
return Result;
}
int EncryptFile(char* input, char *encrypted,char* password)
{
int Result = OK;
BIO* bio_in = BIO_new_file(input, "rb");
if (!bio_in) {
return ERROR;
}
BIO* bio_out = BIO_new_file(encrypted, "wb+");
if (!bio_out) {
BIO_free(bio_in);
return ERROR;
}
Result=do_crypt_bio(bio_in, bio_out, 1, (unsigned char*)password);
BIO_free(bio_in);
BIO_free(bio_out);
return Result;
}
int DecryptFile(char* encrypted, char* output, char* password)
{
int Result = OK;
BIO* bio_in = BIO_new_file(encrypted, "rb");
if (!bio_in) {
return ERROR;
}
BIO* bio_out = BIO_new_file(output, "wb+");
if (!bio_out) {
BIO_free(bio_in);
return ERROR;
}
Result=do_crypt_bio(bio_in, bio_out, 0, (unsigned char*)password);
BIO_free(bio_in);
BIO_free(bio_out);
return Result;
}
I recently started a small side-project to recreate the Minecraft Server in C++ but I stumbled on a problem.
I need to use the AES/CFB8 Cipher according to this link with continuous updating (not finished and restarted every packet).
I surfed trough the internet to try to find a proper solution but could not figure out one that was actually working or it was using the command line interface.
Any help is welcomed !
Cipher.h
class Cipher {
public:
enum CipherType {
ENCRYPT,
DECRYPT
};
private:
EVP_CIPHER_CTX* ctx;
CipherType type;
bool hasFinished;
public:
Cipher(const char* key, const char* iv, CipherType type);
~Cipher();
int update(char* in, int inl, char* out);
int final(char* out);
int getMinimumBufLength(int size);
};
Cipher.cpp
Cipher::Cipher(const char* key, const char* iv, CipherType type) : type(type), hasFinished(false)
{
ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
if(type == CipherType::ENCRYPT)
EVP_EncryptInit_ex(ctx, EVP_aes_256_cfb8(), nullptr, (unsigned char*)key, (unsigned char*)iv);
else
EVP_DecryptInit_ex(ctx, EVP_aes_256_cfb8(), nullptr, (unsigned char*)key, (unsigned char*)iv);
}
Cipher::~Cipher()
{
EVP_CIPHER_CTX_free(ctx);
}
int Cipher::getMinimumBufLength(int size)
{
return type == CipherType::DECRYPT ? size : size + AES_BLOCK_SIZE * 2;
}
int Cipher::update(char* in, int inl, char* out)
{
int len;
EVP_CipherUpdate(ctx, (unsigned char*)out, &len, (unsigned char*)in, inl);
return len;
}
int Cipher::final(char* out)
{
int len;
EVP_EncryptFinal_ex(ctx, (unsigned char*)out, &len);
return len;
}
Cipher-test.cpp
TEST_CASE("Cipher AES/CFB8")
{
char* key = "AAAAAAAAAZEFRGUINJFKDFIVJ";
char* iv = "AUJVFEUB";
Cipher encryptionCipher(key, iv, Cipher::CipherType::ENCRYPT);
Cipher decryptionCipher(key, iv, Cipher::CipherType::DECRYPT);
std::string data = "Hello World ! This is some soon to be encrypted string !";
char encData[encryptionCipher.getMinimumBufLength(data.size() + 1)];
int outLen = encryptionCipher.update(data.data(), data.size() + 1, encData);
int fLen = encryptionCipher.final(encData + outLen);
CHECK(data != std::string(encData));
char decData[decryptionCipher.getMinimumBufLength(outLen + fLen)];
outLen = decryptionCipher.update(encData, outLen + fLen, decData);
decryptionCipher.final(decData + outLen);
CHECK(data == std::string(decData));
}
Thanks in advance
EDIT: I am just wondering if there was a need for supplementary code because of the "continuous" aspect of the Cipher.
This is a follow up question from this one:
OpenSSL EVP_DecryptFinal_ex returns "wrong final block length" error when decrypting a file
I am trying to decrypt a file. At first I was reading it as ASCII file instead of binary. Having this fixed (I hope) and reading it as a binary I always get the an "bad decrypt" error:
15208:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:crypto\evp\evp_enc.c:570:
Here is a sample for how I am encrypting and decrypting:
Encryption:
Cipher cipher;
ifstream f("d:/test.YML");
ofstream out("d:/temp.YML");
byte key[KEY_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2};
byte iv[BLOCK_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};
secure_string line;
secure_string temp;
while (getline(f, line)) {
cipher.Encrypt(key, iv, line, temp);
out << temp << endl;
}
Decryption:
Cipher cipher;
ifstream f("d:/temp.YML", ifstream::binary);
ofstream out("d:/tempDecrypt.YML");
byte key[KEY_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2};
byte iv[BLOCK_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};
secure_string temp;
vector<char> buffer(1024, 0);
while (!f.eof()) {
f.read(buffer.data(), buffer.size());
streamsize dataSize = f.gcount();
secure_string chunk = { buffer.begin(), buffer.begin() + dataSize };
cipher.Decrypt(key, iv, chunk, temp);
}
Now I am not sure where start with this investigation:
Is there an encryption problem ? The encrypted file is generated, I am not seeing anything wrong with it.
Is there a problem with how I am reading chunks of file and decrypt them ? Again I don't see the issue here.(the error is on EVP_DecryptFinal_ex)
I also heard there could be a problem with padding. I am not doing anything related to padding, so I am not sure if this is an issue.
I am using same version of OpenSsl, on Windows, I have 2 Visual Studio projects, so there shouldn,t be an issue with imcompatible OpenSsl libraries.
If someone has any pointers pleaase let me know. I never worked with encryption before so some things are hard to understand.
PS: I haven't included the Encrypt and Decrypt methods, they are the same as on the Openssl Wiki website, let me know if I should.
There are a number of issues in your code... to name a few:
ofstream out("d:/temp.YML"); should be opened in binary mode.
out << temp << endl; will damage binary (encrypted) data by adding newlines unnecessarily.
Output buffer should contain enough space to fit (input buffer + block_size).
Encryption/decryption in chunks must follow the update/final pattern. You can't encrypt/decrypt chunks independently.
The IV should be random and should be stored with the ciphertext.
Have a look at the following sample application, which works:
#include <cstdint>
#include <fstream>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <string.h>
#include <stdio.h>
static const size_t KEY_SIZE = 256 / 8, BLOCK_SIZE = 128 / 8;
class AESBase {
protected:
const uint8_t *key, *iv;
EVP_CIPHER_CTX *ctx;
AESBase(const uint8_t *key, const uint8_t *iv) : key(key), iv(iv) {
if (!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
}
~AESBase() {
EVP_CIPHER_CTX_free(ctx);
}
static void handleErrors(void) {
ERR_print_errors_fp(stderr);
abort();
}
};
class Encrypt : AESBase {
public:
Encrypt(const uint8_t *key, const uint8_t *iv) : AESBase(key, iv) {
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
}
int update(const char *plaintext, int plaintext_len, char *ciphertext) {
int len;
if (1 != EVP_EncryptUpdate(ctx, (uint8_t*)ciphertext, &len, (const uint8_t*)plaintext, plaintext_len))
handleErrors();
return len;
}
int final(char *ciphertext) {
int len;
if (1 != EVP_EncryptFinal_ex(ctx, (uint8_t*)ciphertext, &len))
handleErrors();
return len;
}
};
class Decrypt : AESBase {
public:
Decrypt(const uint8_t *key, const uint8_t *iv) : AESBase(key, iv) {
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
}
int update(const char *ciphertext, int ciphertext_len, char *plaintext) {
int len;
if (1 != EVP_DecryptUpdate(ctx, (uint8_t*)plaintext, &len, (const uint8_t*)ciphertext, ciphertext_len))
handleErrors();
return len;
}
int final(char *plaintext) {
int len;
if (1 != EVP_DecryptFinal_ex(ctx, (uint8_t*)plaintext, &len))
handleErrors();
return len;
}
};
void test_encrypt(const uint8_t *key, const char* in, const char* out) {
std::ifstream fin(in, std::ios_base::binary);
std::ofstream fout(out, std::ios_base::binary);
uint8_t iv[BLOCK_SIZE];
RAND_bytes(iv, sizeof(iv));
char buf[1024], temp[sizeof(buf) + BLOCK_SIZE];
Encrypt aes(key, iv);
fout.write((char*)iv, sizeof(iv));
while (fin) {
fin.read(buf, sizeof(buf));
int len = (int)fin.gcount();
if (len <= 0)
break;
len = aes.update(buf, len, temp);
fout.write(temp, len);
}
int len = aes.final(temp);
fout.write(temp, len);
}
void test_decrypt(const uint8_t *key, const char* in, const char* out) {
std::ifstream fin(in, std::ios_base::binary);
std::ofstream fout(out, std::ios_base::binary);
uint8_t iv[BLOCK_SIZE];
fin.read((char*)iv, sizeof(iv));
char buf[1024], temp[sizeof(buf) + BLOCK_SIZE];
Decrypt aes(key, iv);
while (fin) {
fin.read(buf, sizeof(buf));
int len = (int)fin.gcount();
if (len <= 0)
break;
len = aes.update(buf, len, temp);
fout.write(temp, len);
}
int len = aes.final(temp);
fout.write(temp, len);
}
int main()
{
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
uint8_t key[KEY_SIZE] = { 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2 };
test_encrypt(key, "main.cpp", "main.cpp.enc");
test_decrypt(key, "main.cpp.enc", "main.cpp.txt");
}
I need some help with decrypt a char array in C++ using AES decrypt with Open SSL library. I already done encryption mode and works fine, but decryption is not working.
This is the Encrypt Function:
string Encrypt(char *Key, char *Msg, int size)
{
static char* Res;
static const char* const lut = "0123456789ABCDEF";
string output;
AES_KEY enc_key;
Res = (char *)malloc(size);
AES_set_encrypt_key((unsigned char *)Key, 128, &enc_key);
for(int vuelta = 0; vuelta <= size; vuelta += 16)
{
AES_ecb_encrypt((unsigned char *)Msg + vuelta, (unsigned char *)Res + vuelta, &enc_key, AES_ENCRYPT);
}
output.reserve(2 * size);
for (size_t i = 0; i < size; ++i)
{
const unsigned char c = Res[i];
output.push_back(lut[c >> 4]);
output.push_back(lut[c & 15]);
}
free(Res);
return output;
}
This is the Decrypt Function (not working):
char * Decrypt( char *Key, char *Msg, int size)
{
static char* Res;
AES_KEY dec_key;
Res = ( char * ) malloc( size );
AES_set_decrypt_key(( unsigned char * ) Key, 128, &dec_key);
for(int vuelta= 0; vuelta<=size; vuelta+=16)
{
AES_ecb_encrypt(( unsigned char * ) Msg+vuelta, ( unsigned char * ) Res+vuelta, &dec_key, AES_DECRYPT);
}
return (Res);
}
This is an Example of the Main function that call the methods, the problem is thar no mather how i print the "Res" variable in the Decrypt function, it always show random ASCII values, and i like to show the result in a string like the Encrypt function:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "openSSL/aes.h"
using namespace std;
int main(int argc, char const *argv[])
{
char key[16];
char message[128];
char enc_message[128];
string s_key = "THIS_IS_THE_KEY_";
string s_message = "Hello World !!!";
memset(key, 0, sizeof(key));
strcpy(key, s_key.c_str());
memset(message, 0, sizeof(message));
strcpy(message, s_message.c_str());
string response = Encrypt(key, message, sizeof(message));
cout<<"This is the Encrypted Message: "<<response<<endl;
memset(enc_message, 0, sizeof(enc_message));
strcpy(enc_message, response.c_str());
Decrypt(key, enc_message, sizeof(enc_message));
return 0;
}
Any improve in this methods?
I wanted to put the answer to how I solved it: The problem with my example was that I was trying to use the decrypt function with a HEXADECIMAL STRING and it should be done with an ASCII STRING with the values as delivered by the encryption function.
That is, instead of trying to decrypt a string like this: 461D019896EFA3
It must be decrypted with a string like this: #(%_!#$
After that, the decryption will be delivered in ASCII values. They must be passed to Hexadecimal and finally to a String.
Here is the example that worked for me:
string Decrypt_string(char *Key, string HEX_Message, int size)
{
static const char* const lut = "0123456789ABCDEF";
int i = 0;
char* Res;
AES_KEY dec_key;
string auxString, output, newString;
for(i = 0; i < size; i += 2)
{
string byte = HEX_Message.substr(i, 2);
char chr = (char) (int)strtol(byte.c_str(), NULL, 16);
auxString.push_back(chr);
}
const char *Msg = auxString.c_str();
Res = (char *)malloc(size);
AES_set_decrypt_key((unsigned char *)Key, 128, &dec_key);
for(i = 0; i <= size; i += 16)
{
AES_ecb_encrypt((unsigned char *)Msg + i, (unsigned char *)Res + i, &dec_key, AES_DECRYPT);
}
output.reserve(2 * size);
for (size_t i = 0; i < size; ++i)
{
const unsigned char c = Res[i];
output.push_back(lut[c >> 4]);
output.push_back(lut[c & 15]);
}
int len = output.length();
for(int i = 0; i < len; i += 2)
{
string byte = output.substr(i, 2);
char chr = (char) (int)strtol(byte.c_str(), NULL, 16);
newString.push_back(chr);
}
free(Res);
return newString;
}
I'm using VC++/OPENSSL and AES-256-CBC, and I noticed that since AES is automatic padding by OPENSSL and when I try to decryption , the data I got is with the padding bytes. not just original data.
is there anyway to get length of the original data at decryption so I can cut the padding bytes?
here is my code
void Cryptology::OpenSSLAESDecodeByMapleArray(MapleByteArray& source, MapleByteArray& ba,MapleByteArray &res,bool nosalt)
{
EVP_CIPHER_CTX de;
unsigned int salt[] = { 56756, 352466 };
int i, nrounds = 7;
unsigned char key[32] = { 0 }, iv[32] = { 0 };
if (nosalt)
{
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), NULL, ba.data_ptr(), ba.GetLength(), nrounds, key, iv);
}
else
{
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), (unsigned char *)salt, ba.data_ptr(), ba.GetLength(), nrounds, key, iv);
}
if (i != 32) {
exit(0);
}
EVP_CIPHER_CTX_init(&de);
EVP_DecryptInit_ex(&de, EVP_aes_256_cbc(), NULL, key, iv);
int p_len = source.GetLength(), f_len = 0;
unsigned char *plaintext = (unsigned char *)malloc(p_len + AES_BLOCK_SIZE);
ZeroMemory(plaintext, p_len + AES_BLOCK_SIZE);
EVP_DecryptInit_ex(&de, NULL, NULL, NULL, NULL);
EVP_DecryptUpdate(&de, plaintext, &p_len, (unsigned char *)source.data_ptr(), source.GetLength());
EVP_DecryptFinal_ex(&de, plaintext + p_len, &f_len);
int len = p_len + f_len;
//qDebug() << QString::number(len);
EVP_CIPHER_CTX_cleanup(&de);
res.fromByte((BYTE*)plaintext, p_len + AES_BLOCK_SIZE);
ZeroMemory(plaintext, p_len + AES_BLOCK_SIZE);
free(plaintext);
ZeroMemory(key, 32);
ZeroMemory(iv, 32);
return;
}
If padding is enabled - then EVP_DecryptFinal(..) will verify the padding but not return it in the result. Those the decrypted data would be slightly shorter than the encrypted data.
The actual length of decrypted data is returned in the outl variable with each call to EVP_CipherUpdate(..) and EVP_CipherFinal_ex(..)
int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
int *outl, unsigned char *in, int inl);
int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm,
int *outl);
In your code, the value of len is properbly the length of your decrypted data.