gpt4 book ai didi

c - EVP_DecryptFinal_ex 中用于解密的最终 block 的正确格式是什么?

转载 作者:太空宇宙 更新时间:2023-11-04 01:04:14 24 4
gpt4 key购买 nike

出于学习目的,我已经实现了一个简单的 AES-256-GCM 加密和解密。在测试我的代码时,如果我输入的字符串长度是 6 的倍数,那么我会得到正确的输出,但对于其他情况,解密后的数据会附加一些垃圾字符。

Case1:
Enter string: abcdef
Enter key: sdasdasdsa
-^%�
abcdef
6

Case2:
Enter string: abcdefghi
Enter key: sadsadsad
򈇢\h�,�[�
abcdefghi�\�
-1

现在我在 https://www.openssl.org/docs/crypto/EVP_EncryptFinal_ex.html 上看到了

EVP_DecryptFinal() will return an error code if padding is enabled and the
final block is not correctly formatted.

但由于在这种情况下默认启用填充,我猜测问题出在最终 block 的正确格式上。我在下面附上了我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>

void handleErrors()
{
printf("Some error occured\n");
}

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *aad,
int aad_len, unsigned char *key, unsigned char *iv,
unsigned char *ciphertext, unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;

int len, ciphertext_len=0;

/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();

/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();

/* Set IV length if default 12 bytes (96 bits) is not appropriate */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
handleErrors();

/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();

/* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();

/* 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, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len+= len;

/* 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, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;

/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();

/* Clean up */
EVP_CIPHER_CTX_free(ctx);

return ciphertext_len;
}


int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad,
int aad_len, unsigned char *tag, unsigned char *key, unsigned char *iv,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len, plaintext_len=0, ret;

/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();

/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();

/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
handleErrors();

/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();

/* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();

/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len+= len;

/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
handleErrors();

/* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);

/* Clean up */
EVP_CIPHER_CTX_free(ctx);

if(ret > 0)
{
/* Success */
plaintext_len += len;
return plaintext_len;
}
else
{
/* Verify failed */
return -1;
}
}


int main (void)
{
unsigned char str[1024],key[10],ciphertext[1024+EVP_MAX_BLOCK_LENGTH],tag[100],pt[1024];
unsigned char iv[]="1234567890abcdef";
unsigned char aad[]="1234567890123456";
int k;
printf("Enter string: ");
scanf("%s",str);
printf("Enter key: ");
scanf("%s",key);

encrypt(str, strlen(str), aad, strlen(aad), key, iv, ciphertext, tag);
printf("%s\n",ciphertext);
k = decrypt(ciphertext, strlen(ciphertext), aad, strlen(aad), tag, key, iv, pt);
printf("%s\n%d\n",pt,k);
}

最佳答案

decrypt(ciphertext, strlen(ciphertext), aad, strlen(aad), tag, key, iv, pt);

decrypt(ciphertext, strlen(ciphertext), ... 是错误的。密文中可能嵌入了 NULL,在这种情况下,它将被截断。在您的情况下,附加字符被馈送到 decrypt 函数。很难说有多少 - 直到 strlen 碰巧在内存中遇到 NULL。

您需要捕获encryptdecrpyt 的返回值来正确设置各种长度:

int x;
...

x = encrypt(str, strlen(str), aad, strlen(aad), key, iv, ciphertext, tag);
...

x = decrypt(ciphertext, x, aad, strlen(aad), tag, key, iv, pt);
...

您可能对 aad, strlen(aad) 有同样的问题,但我认为它还没有暴露出来。


What is the correct format for final block in EVP_DecryptFinal_ex for decryption?

回到标题问题:没有。你的问题出在别处。


decrypt 函数中使用的 unsigned char *plaintext 缓冲区可能发生溢出。您没有传递长度,所以 decrypt 愉快地写入超过它的长度...

关于c - EVP_DecryptFinal_ex 中用于解密的最终 block 的正确格式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27763420/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com