3

给定一个适当的keyand iv,这个 C 程序应该加密stdin,输出到stdout

EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit(ctx, EVP_aes_256_gcm(), key, iv);

const size_t block_size = 128;
unsigned char inbuf[block_size];
unsigned char outbuf[block_size + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
for (;;)
{
        inlen = fread(inbuf, 1, block_size, stdin);
        if (inlen <= 0)
                break;

        EVP_EncryptUpdate(ctx, outbuf, &outlen, inbuf, inlen)
        fwrite(outbuf, 1, outlen, stdout);
}
EVP_EncryptFinal_ex(ctx, outbuf, &outlen)
fwrite(outbuf, 1, outlen, stdout);

(为简洁起见,删除了错误检查。)

我正在通过运行验证此代码的输出

openssl aes-256-gcm -in ciphertext.txt -K <key> -iv <iv> -d

例如,这成功且可靠地解密了密文,但随后写入了错误的解密

$ openssl aes-256-gcm ...
Hello World.
bad decrypt

有什么问题会导致它这样说?

4

2 回答 2

1

我完全无法在加密后获得 GCM 身份验证标签,然后在解密期间提供它。

“错误解密”消息具有误导性——解密进行得很好,但没有提供提供身份验证的标签。

调用with可以获取标签EVP_EncryptFinal_ex

unsigned char *tag = malloc(TAGSIZE);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAGSIZE, tag);

TAGSIZE是标签的字节大小,可以是多个不同的值。这在维基百科等地方进行了讨论。

于 2017-11-22T01:19:37.223 回答
-1

这里的问题是,您没有按照 PKCS#7 的要求实现正确的填充。openssl期望正确的填充出现在解码的消息中。规则是:

  • 必须始终有至少 1 个字节的填充
  • 它必须填充到密码的块大小

现在使用 AES-256,您的块大小为 128 位(16 字节)。这意味着,您必须添加 1-16 个填充字节。要添加的填充字节始终是填充的大小,因此如果必须添加 9 个字节的填充,则应添加 90x09个字节。

如果您将此填充正确地添加到原始明文中,则 openssl 应该停止抱怨解密。

于 2017-11-15T19:23:01.877 回答