使用 (LibreSSL) libcrypto 使用 AES-256-GCM 加密
Encryption with AES-256-GCM using (LibreSSL) libcrypto
给定适当的 key
和 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
可能是哪里出了问题导致它这样说?
这里的问题是,您没有按照 PKCS#7 的要求实施适当的填充。 openssl
期望解码消息中存在正确的填充。规则是:
- 必须总是至少 1 个字节的填充
- 它必须被填充到密码的块大小
现在使用 AES-256,您的块大小为 128 位(16 字节)。这意味着,您必须添加 1-16 个填充字节。要添加的填充字节始终是填充的 大小,因此如果必须添加 9 个字节的填充,则应添加 9 0x09
个字节。
如果您正确地将此填充添加到您的原始明文中,则 openssl 应该停止对解密的抱怨。
我完全没有在加密后获取 GCM 身份验证标签,然后在解密时提供它。
"bad decrypt" 消息具有误导性 — 解密正常,但未提供提供身份验证的标签。
使用
调用EVP_EncryptFinal_ex
后可以在获取标签
unsigned char *tag = malloc(TAGSIZE);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAGSIZE, tag);
TAGSIZE
是标签的字节大小,可以是多个不同的值。 Wikipedia 和其他地方对此进行了讨论。
给定适当的 key
和 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
可能是哪里出了问题导致它这样说?
这里的问题是,您没有按照 PKCS#7 的要求实施适当的填充。 openssl
期望解码消息中存在正确的填充。规则是:
- 必须总是至少 1 个字节的填充
- 它必须被填充到密码的块大小
现在使用 AES-256,您的块大小为 128 位(16 字节)。这意味着,您必须添加 1-16 个填充字节。要添加的填充字节始终是填充的 大小,因此如果必须添加 9 个字节的填充,则应添加 9 0x09
个字节。
如果您正确地将此填充添加到您的原始明文中,则 openssl 应该停止对解密的抱怨。
我完全没有在加密后获取 GCM 身份验证标签,然后在解密时提供它。
"bad decrypt" 消息具有误导性 — 解密正常,但未提供提供身份验证的标签。
使用
调用EVP_EncryptFinal_ex
后可以在获取标签
unsigned char *tag = malloc(TAGSIZE);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAGSIZE, tag);
TAGSIZE
是标签的字节大小,可以是多个不同的值。 Wikipedia 和其他地方对此进行了讨论。