This is linked to EVP_DecryptFinal_ex Error on OpenSSL
I was trying to find out why the AES decrypt won't work and finally I have found what the problem is and now looking for someone to help me solve it :)
Here is the code that I tested with(from various posts here):
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
int AES_BLOCK_SIZE = 128;
int main(int argc, char **argv)
{
EVP_CIPHER_CTX en;
EVP_CIPHER_CTX de;
EVP_CIPHER_CTX_init(&en);
EVP_CIPHER_CTX_init(&de);
const EVP_CIPHER *cipher_type;
unsigned char *passkey, *passiv, *plaintxt;
char *plain;
char *plaintext;
unsigned char *ciphertext;
int olen, len;
int i =0;
unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f, 0 };
unsigned char key[]= { 0x2b, 0x7e, 0x15, 0x16,
0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88,
0x09, 0xcf, 0x4f, 0x3c , 0 };
unsigned char *input = "hi this is patrick immling\n'Doctor'.\n'Doctor' who ?\nPrecisely! 123910!§$$§% !%%$&$(/=))?=(#ü++Ü**<,.here we go sometimes it i s difficult but 187! 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y";
printf("AES ALGORITHM FOR 128 bit CBC MODE\n");
cipher_type = EVP_aes_128_cbc();
AES_BLOCK_SIZE = 128;
passkey = key;
passiv = iv;
plain = input;
printf("iv=");
for(i = 0; i < sizeof iv; i++){
printf("%02x", iv[i]);
//printf("key[%d]= %02x\n", i, key[i]);
}
printf("\n");
printf("key=");
for(i = 0; i < sizeof key; i++){
printf("%02x", key[i]);
//printf("key[%d]= %02x\n", i, key[i]);
}
printf("\n");
printf("Initializing AES ALGORITHM FOR CBC MODE..\n");
EVP_EncryptInit_ex(&en, cipher_type, NULL, passkey, passiv);
EVP_DecryptInit_ex(&de, cipher_type, NULL, passkey, passiv);
olen = len = strlen(input)+1;
printf("len value before aes_encrypt \"%d\"\n", len);
// max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes
int c_len = len + AES_BLOCK_SIZE - 1;
int f_len = 0;
ciphertext = (unsigned char *)malloc(c_len);
/* allows reusing of 'e' for multiple encryption cycles */
if(!EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL)){
printf("ERROR in EVP_EncryptInit_ex \n");
return NULL;
}
if(!EVP_EncryptUpdate(&en, ciphertext, &c_len, plain, len)){
printf("ERROR in EVP_EncryptUpdate \n");
return NULL;
}
printf("len value after update \"%d\"\n", len);
// printf("size of ciphertext after update \"%d\"\n", sizeof(ciphertext));
printf("strlen value of ciphertext after update \"%d\"\n", strlen(ciphertext));
if(!EVP_EncryptFinal_ex(&en, ciphertext+c_len, &f_len)){
printf("ERROR in EVP_EncryptFinal_ex \n");
return NULL;
}
printf("len value after final \"%d\"\n", len);
printf("strlen value of ciphertext after final \"%d\"\n", strlen(ciphertext));
EVP_CIPHER_CTX_cleanup(&en);
len = c_len + f_len;
printf("len value after aes_encrypt \"%d\"\n", len);
//HERE IS THE PROBLEM: IF I USE len= strlen(ciphertext) I GET ERROR
//len = strlen(ciphertext);
printf("strlen value of ciphertext after aes_encrypt \"%d\"\n", len);
int p_len = len;
f_len = 0;
plaintext = (unsigned char *)malloc(p_len);
// memset(plaintext,0,sizeof(plaintext));
if(!EVP_DecryptInit_ex(&de, NULL, NULL, NULL, NULL)){
printf("ERROR in EVP_DecryptInit_ex \n");
return NULL;
}
EVP_CIPHER_CTX_set_padding(&de, 0);
if(!EVP_DecryptUpdate(&de, plaintext, &p_len, ciphertext, len)){
printf("ERROR in EVP_DecryptUpdate\n");
return NULL;
}
printf("len value after decrypt update \"%d\"\n", len);
if(!EVP_DecryptFinal_ex(&de, plaintext+p_len, &f_len)){
printf("ERROR in EVP_DecryptFinal_ex\n");
ERR_print_errors_fp(stderr);
return NULL;
}
EVP_CIPHER_CTX_cleanup(&de);
len = p_len + f_len;
printf("Decrypted value = %s\n", plaintext);
printf("len value after aes_decrypt \"%d\"\n", len);
if (strncmp(plaintext, input, olen))
printf("FAIL: enc/dec failed for \"%s\"\n", input);
else
printf("OK: enc/dec ok for \"%s\"\n", plaintext); // \"%s\"\n
printf("\n");
free(ciphertext);
free(plaintext);
return 0;
}
What I dont understand:
What should I feed as the "len" parameter for the openSSL EVP Decrypt routines? what is this magic len = c_len+ f_len?
How should I get this in case I am given just the cipher with the key and the iv? This should be always possible right? I know strlen is a bad parametr especially for binary as the ciphertext input to EVP Decrypt is binary: so how should I get this?
I can already see that if I use len= strlen(ciphertext) gives me a wrong answer and sizeof parameter is also not the one as it returns 4.
The stderr shows clearly that the EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH and which I understand as you have all pointed out that the AES data should be 16 byte chunks. So what should I change to feed the length?
First, don't return NULL from main(). Second, I fixed it and annotated it so hopefully you can see what the length variables mean. I think the key point you're missing is that you're giving the OpenSSL functions a buffer where it can write its data. Like many functions that take a buffer, you give it a buffer size and it returns to you the number of bytes it actually wrote into the buffer. Why? Because you have to know when your buffer is full, or if you're filling your buffer incrementally you have to know where to write the next chunk of data.
Also, I think you should read some tutorials on how to work with binary data and how it differs from a C-style string. The OpenSSL EVP functions work with binary data, which is why you need to tell every function how many bytes your data is.