Я пытаюсь расшифровать данные, используя метод 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;
}
}