使用(LibreSSL)libcrypto使用AES-256-GCM进行加密

时间:2017-11-15 18:15:00

标签: c aes libcrypto libressl

如果有适当的keyiv,此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

这成功且可靠地解密了密文,但之后写了 bad decrypt ,例如

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

导致它说出来可能会出错?

2 个答案:

答案 0 :(得分:0)

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

“解密错误”消息具有误导性 - 解密正常,但未提供提供身份验证的标记。

使用

调用EVP_EncryptFinal_ex 后可以获取标记
unsigned char *tag = malloc(TAGSIZE);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAGSIZE, tag);

TAGSIZE是标记的大小(以字节为单位),可以是许多不同的值。这在Wikipedia以及其他地方进行了讨论。

答案 1 :(得分:-1)

这里的问题是,您没有像PKCS#7那样实现正确的填充。 openssl期望在解码的消息中存在正确的填充。规则是:

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

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

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