I am having some trouble decrypting a string correctly. What is infuriating about it is that it is only the first few bytes that are messed up, the remaining characters are correct.
So I had my test program working fine when I was just using a hard coded IV for encrypting and decrypting. The program takes a String, encrypts it (using AES), and then I get a hex representation of the encrypted binary. The problem arose when I tried to append the IV onto the end of the cipher text. Peculiarly, the length of the hex String did not increase after appending the IV. But, the decryption function seems to be obtaining the IV from the end of the cipher text, otherwise it wouldn't be able to decrypt any of it, right?
I have tried a bunch of different things, like creating a buffer of the exact size it needs to be, and adding the cipher text and IV using memcpy
. Here is the code:
AES Encryption
int encryptAes(const char *plainText, char *cipherText, const char *key) {
unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
int plainTextLength = strlen(plainText);
int cipherTextLength = 0;
int blockLength = 0;
static const int MAX_PADDING_LENGTH = 16;
EVP_CIPHER_CTX encryptCtx;
EVP_CIPHER_CTX_init(&encryptCtx);
EVP_EncryptInit_ex(&encryptCtx, EVP_aes_256_cbc(), NULL, key, iv);
if (!EVP_EncryptUpdate(&encryptCtx, cipherText, &blockLength, (unsigned char *) plainText, plainTextLength) ) {
printf("Error in EVP_EncryptUpdate \n");
return 1;
}
cipherTextLength += blockLength;
if (!EVP_EncryptFinal_ex(&encryptCtx, cipherText + cipherTextLength, &blockLength)) {
printf("Error in EVP_EncryptFinal_ex \n");
return 1;
}
cipherTextLength += blockLength;
// Append the IV
memcpy(cipherText + cipherTextLength, iv, 16);
EVP_CIPHER_CTX_cleanup(&encryptCtx);
return cipherTextLength;
}
AES Decryption
int decryptAes(const char *cipherText, char *decipheredPlainText, const size_t cipherTextLength, const char *key) {
// unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
unsigned char iv[16];
memcpy(iv, cipherText + cipherTextLength, 16);
int plainTextLength = 0;
int blockLength = 0;
EVP_CIPHER_CTX decryptCtx;
EVP_CIPHER_CTX_init(&decryptCtx);
EVP_DecryptInit_ex(&decryptCtx, EVP_aes_256_cbc(), NULL, key, iv);
if (!EVP_DecryptUpdate(&decryptCtx, decipheredPlainText, &blockLength, cipherText, cipherTextLength)) {
printf("Error in EVP_DecryptUpdate\n");
return 1;
}
plainTextLength += blockLength;
if (!EVP_DecryptFinal_ex(&decryptCtx, decipheredPlainText + plainTextLength, &blockLength)) {
printf("Error in EVP_DecryptFinal_ex\n");
return 1;
}
plainTextLength += blockLength;
decipheredPlainText[plainTextLength] = '\0';
EVP_CIPHER_CTX_cleanup(&decryptCtx);
return plainTextLength;
}
This produces the output:
Original Plain Text [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
Hexadecimal is [be1c1aaa5827be124023a96a3360da922c244acd845e8914d03cfac69d312948e10f8ef7a99a64acbc6996724315f6cb0bf441ba3b08ab25cae64389f6ded77b1579e847d3e18ca89e71a3c4ec5ca4e3089b7bc2e6bc9ef8d175406bf4b53005a91e285d117e5990176d85793bd75853]
Decrypted Plain Text [�}kaw&d��~C�Rmfpher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
If I remove the line memcpy(cipherText + cipherTextLength, iv, 16);
from the encryption function, and uncomment the hardcoded IV at the beginning of the decryption function (and comment the following two lines), the output is correct:
Original Plain Text [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
Hexadecimal is [be1c1aaa5827be124023a96a3360da922c244acd845e8914d03cfac69d312948e10f8ef7a99a64acbc6996724315f6cb0bf441ba3b08ab25cae64389f6ded77b1579e847d3e18ca89e71a3c4ec5ca4e3089b7bc2e6bc9ef8d175406bf4b53005a91e285d117e5990176d85793bd75853]
Decrypted Plain Text [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
Note!, the hexadecimal is the same in both cases.
Can anyone see where I'm going wrong here. I encountered something similar to this before, but can't seem to remember how I got around it. Obviously there is something afoot when trying to append the IV. There is ample space in cipherText
to accommodate the addition of the IV.
Thanks in advance.
What is the return value from the
encryptAes()
supposed to represent? It looks to me like it's supposed to represent the length in bytes of the data produced by the encryption process. Are you accounting for the fact that the data you need to deal with is sixteen bytes longer than that? If you're encrypting your data in one place, and copying it to another place to calldecryptAes()
on, you're probably forgetting to account for the extra sixteen bytes.If this is the case, then what you're doing, effectively, is this:
encryptAes()
, passing it the text to encrypt, the output buffer, and the encryption key.encryptAes()
, you generate the IV, perform the encryption, writing the encrypted data to the output buffer, calculating the length as you go.cipherTextLength
counter.encryptAes()
, returningcipherTextLength
to the caller. Note, this is a value sixteen bytes shorter than your actual data.decryptAes()
, passing it the text to decrypt, the output buffer, the size of the encrypted data, and the key.decryptAes()
, copy the sixteen random bytes of data that immediately follow the encrypted data, into the IV.The is the likeliest explanation I can think of for why your IV is getting corrupted.