0
votes

I'm trying to decrypt in C++ a file that have been encrypted with the Linux command : openssl enc -aes-256-cbc -nosalt -K "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855" -iv "5DF6E0E2761359D30A8275058E299FCC" -p -in file.json -out file.enc
The decryption works well, but unexpected symbols appear at the end of the file when I print it in the terminal, as in the following image Image
Here is my C++ code, can someone help me ?

int main(int argc, char **argv)
{
  EVP_CIPHER_CTX *en, *de;
  en = EVP_CIPHER_CTX_new();
  de = EVP_CIPHER_CTX_new();

  unsigned char key_data[] = {0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B,0x78, 0x52, 0xB8, 0x55};
  int key_data_len = 32;

  std::ifstream in("file.enc");
  std::string contents((std::istreambuf_iterator<char>(in)), 
  std::istreambuf_iterator<char>());


  unsigned char iv[] = {0x5D, 0xF6, 0xE0, 0xE2, 0x76, 0x13, 0x59, 0xD3, 0x0A, 0x82, 0x75, 0x05, 0x8E, 0x29, 0x9F, 0xCC};

  EVP_CIPHER_CTX_init(en);
  EVP_EncryptInit_ex(en, EVP_aes_256_cbc(), NULL, key_data, iv);
  EVP_CIPHER_CTX_init(de);
  EVP_DecryptInit_ex(de, EVP_aes_256_cbc(), NULL, key_data, iv);


  char *plaintext;
  int len = strlen(contents.c_str())+1;

  plaintext = (char *)aes_decrypt(de, (unsigned char *)contents.c_str(), &len);
  printf("%s", plaintext);


  free(plaintext);
  EVP_CIPHER_CTX_cleanup(en);
  EVP_CIPHER_CTX_cleanup(de);
}

And the function to decrypt :

unsigned char *aes_decrypt(EVP_CIPHER_CTX *e, unsigned char *ciphertext, int *len)
{
  int p_len = *len, f_len = 0;
  unsigned char *plaintext = (unsigned char *)calloc(sizeof(char*), p_len);

  EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);
  EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len);
  EVP_DecryptFinal_ex(e, plaintext+p_len, &f_len);

  *len = p_len + f_len;
  return plaintext;
}

SOLVED : I had to remove the PKCS#7 padding added by the encoder PKCS#7 Padding

1
You malloc plaintext but you never zero out the bytes so I suspect the last character is a random character or null-terminator.. Either use calloc or do memset on plaintext right after the malloc call and see if it helps? Also, why don't you use new operator instead of malloc since this is C++ after all? Perhaps you also need to have different lengths for the data and the decrypted data? Maybe the malloc needs to be len+1 but the parameters to decrypt don't need to be..Brandon
@Brandon I modified the above code with a calloc, but nothing changes... The last byte is a '0x01'...user11222840
Data is padded using PKCS#7 padding, which needs to be stripped after decryptionyachoor
@yachoor Can you explain me how to do this ?user11222840
Check last byte and remove/ignore that many bytes at the end. The padding is x bytes with value x, where x is between 1 and 8.yachoor

1 Answers

0
votes

The input length is incorrect - strlen(contents.c_str()) + 1 will either return length including additional null byte which should not be included as it is not part of encrypted data, or length of data to the first null byte in encrypted data if there is one. You should use contents.size() instead. This causes EVP_DecryptUpdate to decrypt all data including last block with padding and expect more data and EVP_DecryptFinal_ex to fail after that. With correct length the padding from last block will be stripped as expected.

There's also issue with output buffer length - it's sizeof(char*) * p_len instead of sizeof(char) * (p_len + EVP_CIPHER_block_size(EVP_aes_256_cbc())). EVP_DecryptUpdate requires output buffer to be large enough to hold input length + cipher block size.

You should also make sure to use only len data in plaintext buffer - printf will output data until null byte, which might not be included in decrypted data.