I have a small c++ code to encrypt a file using EVP_Cipher_ APIs.I have a requirement to decrypte the encrypted file using Openssl (command line). When tried to decrypt, it always ends up in Bad decrypt.
Note I can decrypt using EVP_Cipher apis.
openssl command I used
openssl enc -aes-256-cbs -d -K ae0479555eca5b5228a0ee00ecef15aab729f47ee881cf8b1d3ff18561a47290 -iv 3fa6d97f4807e145b37451fc344e58ca -in test.enc -out test.out -nosalt
the EVP API used
I can decrypt using same API, by putting last arugument to 0 in EVP_CIPHERInit_ex.
Also I kept 32 bytes key and iv value same as I would use with openssl cmd line.
Not sure whats going wrong? ANy pointer would help. Thanks!!
PS: The c++ code used:
using namespace std;
void encDecFile(const char * input_filepath, bool encrypt) {
const unsigned char * key = (const unsigned char * )
"ae0479555eca5b5228a0ee00ecef15aab729f47ee881cf8b1d3ff18561a47290";
const unsigned char * iv = (const unsigned char * )
"3fa6d97f4807e145b37451fc344e58ca";
int intent = encrypt ? 1 : 0;
std::string output_filepath = input_filepath;
if (encrypt) {
const char * ext = ".enc";
output_filepath = output_filepath + std::string(".enc");
} else {
auto pos = output_filepath.find_last_of(".");
output_filepath = output_filepath.substr(0, pos) + std::string(".out");
}
//const char *output_filepath = strncat(input_filepath, ext, sizeof(ext));
ifstream input_file(input_filepath, std::ios::binary);
ofstream output_file(output_filepath.c_str(), std::ios::binary);
int out_len = 0;
printf("encDecFile - Entry \n");
if (!(input_file.is_open() && output_file.is_open())) {
const char * whichFile = input_file.is_open() ? output_filepath.c_str() : input_filepath;
printf("encDecFile Failed to open %s \n", whichFile);
return;
}
input_file.seekg(0, std::ios::end);
long long file_size = input_file.tellg();
input_file.seekg(0, std::ios::beg);
printf("encDecFile - Input file %s is of Size %lld is opened! \n", input_filepath, file_size);
EVP_CIPHER_CTX * ctx;
ctx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv, 1);
EVP_CIPHER_CTX_set_padding(ctx, 1);
unsigned int blocksize = EVP_CIPHER_block_size(EVP_aes_256_cbc());
char * in_buf = new char[2048];
char * out_buf = new char[2048 + blocksize];
int count = 0;
while (!input_file.eof()) {
input_file.read(in_buf, (1 << 20));
std::streamsize dataSize = input_file.gcount();
printf("encDecFile - Reading %d chunk of data of size %d \n", ++count, (int) dataSize);
if (1 == EVP_CipherUpdate(ctx, (unsigned char * ) out_buf, & out_len, (const unsigned char * ) in_buf, (int) dataSize)) {
output_file.write(out_buf, out_len);
printf("encDecFile - Written %d bytes of encrypted data \n", out_len);
} else {
printf("Encryption failed after for %d Chunk! \n", count);
break;
}
}
if (1 == EVP_CipherFinal_ex(ctx, (unsigned char * ) out_buf, & out_len)) {
output_file.write(out_buf, out_len);
printf("encDecFile - Written %d bytes of final encrypted data \n", out_len);
} else {
printf("Encryption failed after to update Final \n");
}
input_file.close();
output_file.close();
delete[] out_buf;
EVP_CIPHER_CTX_cleanup(ctx);
EVP_CIPHER_CTX_free(ctx);
printf("encDecFile - Done!! \n");
return;
}
Encrypt decrypt using EVP_Cipher APi worked fine.
It's the hex
-- which is timely in the US, where October is a big advertising/merchandising campaign building up to Halloween on Oct. 31 which is (now) about magic, witchcraft, and the supernatural, or at least the popular conception(s) of them :-}
Commandline openssl ... -K ... -iv ...
treats the strings as hex and converts them to bytes: 0xae 0x04 0x79 ... 0x90 and 0x3f 0xa6 ... 0xca . But your C++ code instead uses the character codes of the first half of the key string -- 0x6a 0x66 0x30 0x34 ... 0x61 0x61 -- and similarly the first half of the iv -- 0x33 0x66 0x61 0x36 ... 0x34 0x35. These are radically different and thus don't interoperate.
You can either have the compiler take the hex and compile to binary:
unsigned char key[] = {0xae,0x04,0x79, ... 0x90};
unsigned char iv[] = {0x3f,0xa6, ... 0xca};
or write code to convert the hex-character form to binary such as:
char * key_hex = "ae0479555eca5b5228a0ee00ecef15aab729f47ee881cf8b1d3ff18561a47290";
unsigned char key_bin[32];
for(int i = 0; i < sizeof key_bin; i++ ) sscanf(&key_hex[i*2], "%2hhx", &key_bin[i]);
// and similarly for iv, and use the _bin versions when calling EVP