You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EVP_DecryptUpdate()传32返回0传64返回1问题排查

问题表现
  • 调用EVP_DecryptUpdate()时,若传入参数声明输出缓冲区可用大小为32字节,函数返回0(执行失败);将声明的可用大小改为64字节时函数返回1(执行成功),但两种场景下输出参数cipher_len的值始终为0,实际定义的输出缓冲区大小为4096字节,不存在空间不足的问题。
  • 根据OpenSSL官方文档说明,EVP_DecryptUpdate()解密操作执行成功时返回值应为1。

复现代码如下:

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

void dump_head(unsigned char *buf, size_t len)
{
    unsigned end, i;
    for (end = len; end > 0; end--)
        if (buf[end-1] != 0)
            break;
    printf("buf = {");
    for (i = 0; i < end; i++)
        printf(" %02hhx,", buf[i]);
    printf(" }\n");
}

int main(void)
{
    unsigned char key[] = "0123456789abcdef";
    unsigned char iv[] = "1234567887654321";
    unsigned char indata[32] = "0123456789abcdeffedcba9876543210";
    unsigned char buf[4096];
    unsigned pos;
    int cipher_len;
    EVP_CIPHER_CTX *ctx;

    ctx = EVP_CIPHER_CTX_new();
    EVP_CIPHER_CTX_init(ctx);
    EVP_CIPHER_CTX_set_padding(ctx, 0);
    EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);  
    printf("decrypt init: %d\n", EVP_DecryptInit_ex(ctx, EVP_aes_256_wrap_pad(), NULL, key, iv));

    printf("decrypt update: %d\n", EVP_DecryptUpdate(ctx, (unsigned char *)buf, &cipher_len, indata, 32));
        
    printf("Got %d\n", cipher_len);
    dump_head(buf, sizeof(buf));
        
    printf("Final!\n");
    memset(buf, 0, sizeof(buf));
    EVP_DecryptFinal_ex(ctx, buf, &cipher_len);
    printf("Got %d\n", cipher_len);
    dump_head(buf, sizeof(buf));

    return 0;
}
根因分析

不存在遗漏配置的参数,问题来自现有参数配置不符合所选算法的强制要求,共3处错误:

  1. 密钥长度与选用算法不匹配:选用的EVP_aes_256_wrap_pad()是AES-256密钥封装算法,要求密钥长度必须为32字节,代码中定义的key有效长度仅16字节,不符合算法初始化要求。
  2. 错误关闭了填充配置:EVP_aes_256_wrap_pad()本身是带填充的密钥封装算法,内置了填充处理逻辑,代码中调用EVP_CIPHER_CTX_set_padding(ctx, 0)强制关闭填充,会导致算法内部长度计算逻辑异常,无法正常输出解密后的明文、也无法更新输出长度参数,这就是cipher_len始终为0的直接原因。
  3. 传入的输出缓冲区长度不符合算法校验规则:AES密钥封装类算法(含带pad版本)在EVP_DecryptUpdate调用时,强制要求声明的输出缓冲区可用长度至少为输入密文长度 + 8字节——该预留空间用于存放算法内部处理时的临时校验值,和最终输出的明文长度无关。代码中输入密文长度为32字节,要求声明的缓冲区长度至少为40字节,传入32时直接触发长度校验失败返回0;传入64时仅满足了长度校验要求,但因为填充配置错误,仍然无法正常输出结果。

另外代码中EVP_CIPHER_CTX_new()已经完成了上下文的初始化操作,后续调用EVP_CIPHER_CTX_init(ctx)属于冗余调用,虽然不会直接触发错误,但无实际意义。

修正方法
  • 匹配密钥与算法:如果使用16字节长度的密钥,将算法替换为EVP_aes_128_wrap_pad();如果要使用EVP_aes_256_wrap_pad(),则将密钥长度调整为32字节。
  • 删除EVP_CIPHER_CTX_set_padding(ctx, 0)这行代码,保留算法默认的填充配置。
  • 调用EVP_DecryptUpdate前,先给cipher_len赋值为输出缓冲区的实际可用大小(即4096,满足至少输入长度+8的要求即可),不需要额外缩小缓冲区。

内容的提问来源于stack exchange,提问作者Kivuos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 23:21:32