我正在尝试使用openssl AES GCM方法解密数据。但是,这总是失败,返回码为0。
我确实在堆栈溢出时进行了搜索,并看到许多关于同一问题的问题。但是建议的答案都没有对我有用。
因此再次询问相同的问题。
这是我要使用的代码
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();
}
以上代码将加密以及填充和标记。加密完成后,我将加密的数据+标记+填充写入输出缓冲区。这个对吗?或者我应该只将唯一的加密数据写入输出缓冲区。
解密代码如下
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;
}
}