I am trying to decrypt data using openssl AES GCM method. However this always fails with return code 0.
I did search for this on stack overflow and see many questions posted on same issue. But none of the suggested answers did work for me.
Hence re asking the same question again.
Here is the code i am trying to use
int gcm_encrypt(std::vector<uint8_t>& key, std::vector<uint8_t>& plainText, std::vector<uint8_t>& encData)
{
unsigned char iv[AES_BLOCK_SIZE] = {'T', 'H', 'I', 'S', 'I', 'S', 'S', 'E', 'C', 'R', 'E', 'T', 'K', 'E', 'Y', 'Y'};
unsigned char tag[AES_BLOCK_SIZE] = {0};
int encDataLen = plainText.size() + EVP_CIPHER_block_size(EVP_aes_256_gcm()) + sizeof(tag);
unsigned char* et = (unsigned char*) calloc(encDataLen, sizeof(unsigned char));
std::cout << "Plain text Len: " << plainText.size() << std::endl;
std::cout << "Tag Len: " << sizeof(tag) << std::endl;
std::cout << "Cipher block Len: " << EVP_CIPHER_block_size(EVP_aes_256_gcm()) << std::endl;
std::cout << "et Len: " << encDataLen << std::endl;
EVP_CIPHER_CTX* ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new()))
{
std::cout << "Failed to initialized ctx -1" << std::endl;
return 0;
}
/* Initialise the encryption operation. */
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
{
std::cout << "Failed to init encrypt ctx -2" << std::endl;
return 0;
}
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(iv), NULL))
{
std::cout << "Failed to init encrypt ctx -3" << std::endl;
return 0;
}
/* Initialise key and IV */
if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key.data(), iv))
{
std::cout << "Failed to init encrypt ctx -4" << std::endl;
return 0;
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
/*if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
{
std::cout << "Failed to init encrypt ctx" << std::endl;
return 0;
}*/
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if (1 != EVP_EncryptUpdate(ctx, et, &len, plainText.data(), plainText.size()))
{
std::cout << "Failed to init encrypt ctx -5" << std::endl;
return 0;
}
ciphertext_len = len;
std::cout << "1. Encrypted text len : " << ciphertext_len << std::endl;
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if (1 != EVP_EncryptFinal_ex(ctx, et, &len))
{
std::cout << "Failed to init encrypt ctx -6" << std::endl;
return 0;
}
ciphertext_len += len;
/* Get the tag */
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
{
std::cout << "Failed to init encrypt ctx -7" << std::endl;
return 0;
}
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
std::cout << "2. ciphertext_len : " << ciphertext_len << std::endl;
auto it = encData.begin();
int l = encDataLen - ciphertext_len - sizeof(tag);
encData.insert(it, et, et + ciphertext_len);
encData.insert(encData.end(), tag, tag + sizeof(tag));
for (auto i = 0; i < l; i++)
encData.push_back(0);
printf("Vector size after copying encData: %ld\n", encData.size());
free(et);
return encData.size();
}
Above code does encryption along with padding and tagging. Once the encryption is done, i am writing encrypted data + tag + padding into the output buffer. Is this correct? Or should i only write the only encrypted data into output buffer.
Code for decryption is as below
int gcm_decrypt(std::vector<uint8_t> cipherText, std::vector<uint8_t> key, std::vector<uint8_t> plaintext)
{
EVP_CIPHER_CTX* ctx;
int len;
int plaintext_len;
int ret;
unsigned char iv[AES_BLOCK_SIZE] = {'T', 'H', 'I', 'S', 'I', 'S', 'S', 'E', 'C', 'R', 'E', 'T', 'K', 'E', 'Y', 'Y'};
unsigned char tag[AES_BLOCK_SIZE] = {0};
int encDataLen = cipherText.size() + EVP_CIPHER_block_size(EVP_aes_256_gcm()) + sizeof(tag);
unsigned char* pt = (unsigned char*) calloc(encDataLen, sizeof(unsigned char));
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new()))
{
std::cout << "Failed to initialize ctx -1" << std::endl;
return 0;
}
/* Initialise the decryption operation. */
if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
{
std::cout << "Failed to initialize ctx -2" << std::endl;
return 0;
}
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(iv), NULL))
{
std::cout << "Failed to initialize ctx -3" << std::endl;
return 0;
}
/* Initialise key and IV */
if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key.data(), iv))
{
std::cout << "Failed to initialize ctx -4" << std::endl;
return 0;
}
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
/*if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
{
std::cout << "Failed to initialize ctx" << std::endl;
return 0;
}*/
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
EVP_CIPHER_CTX_set_padding(ctx, 0);
ret = EVP_DecryptUpdate(ctx, pt, &len, cipherText.data(), cipherText.size());
std::cout << "DecryptUpdate ret: " << ret << std::endl;
if (!ret)
{
std::cout << "Failed to initialize ctx -5" << std::endl;
return 0;
}
plaintext_len = len;
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag);
std::cout << "Set Tag ret: " << ret << std::endl;
if (ret != 1)
{
std::cout << "Failed to initialize ctx -6" << std::endl;
return 0;
}
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
std::cout << "Len of plain text decoded till now: " << plaintext_len << std::endl;
ret = EVP_DecryptFinal_ex(ctx, pt + len, &len);
ERR_print_errors_fp(stderr);
std::cout << "DecryptFinal_ex ret: " << ret << std::endl;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
free(pt);
if (ret > 0)
{
/* Success */
plaintext_len += len;
return plaintext_len;
}
else
{
/* Verify failed */
return -1;
}
}