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

OpenSSL调用EVP_DecryptUpdate使用AES_wrap_pad时触发段错误

问题原因

使用EVP_aes_*_wrap_pad(即RFC 5649定义的AES密钥封装算法)时触发段错误,核心是这类算法和ECB等普通分组加密模式的EVP调用逻辑存在差异,未做对应适配,主要有3个必须处理的点:

  • 必须设置Wrap模式允许标志:AES-Wrap系列算法默认不支持分块调用EVP_DecryptUpdate/EVP_EncryptUpdate,必须在上下文初始化后立刻调用EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW)开启分块调用支持,否则内部逻辑会走一次性处理分支,传入分块数据时很容易触发内存越界导致段错误。
  • IV长度要求不同:普通AES分组模式(ECB/CBC等)的块大小是16字节,对应IV长度也是16字节,其中ECB模式本身不使用IV,传入的IV参数会被直接忽略,所以之前传16字节IV不会报错。但AES-Wrap系列算法使用的是64位(8字节)的默认IV(RFC标准定义的固定值0xA6A6A6A6A6A6A6A6),传入16字节的IV会导致内部读取IV时内存越界。如果不需要自定义IV,直接在Init时给iv参数传NULL即可使用标准默认IV;如果要自定义IV,必须传入长度为8字节的IV缓冲区。
  • 密钥长度必须严格匹配算法:EVP_aes_128_wrap_pad要求密钥长度为16字节,EVP_aes_192_wrap_pad要求24字节,EVP_aes_256_wrap_pad要求32字节,长度不匹配会导致内部读取密钥时越界触发段错误。测试128版本时密钥刚好是16字节所以没触发这个问题,换256版本时如果还沿用16字节密钥会直接崩溃。

另外要注意:测试用的indata是普通字符串,不是合法的AES-Wrap密文(合法密文是经过Wrap加密输出的、符合RFC格式的数据,带pad版本的密文长度至少16字节,且包含校验信息),就算解决了段错误,EVP_DecryptFinal_ex也会因为校验失败返回解密错误,这是测试数据的问题,和接口逻辑无关。

修正后的可运行示例(以EVP_aes_128_wrap_pad为例)
#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)
{
    // 注意:换EVP_aes_256_wrap_pad时,key必须改成32字节长度
    unsigned char key[] = "0123456789abcdef";
    unsigned char indata[32] = "0123456789abcdeffedcba9876543210";
    unsigned char buf[4096];
    int out_len;
    EVP_CIPHER_CTX *ctx;

    ctx = EVP_CIPHER_CTX_new();
    // 初始化解密上下文,iv传NULL使用默认标准IV
    EVP_DecryptInit_ex(ctx, EVP_aes_128_wrap_pad(), NULL, key, NULL);
    // 必须设置这个flag,允许分块调用Update接口
    EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
    
    // 注意:这里的indata如果不是合法Wrap密文,后续Final会报错
    if(!EVP_DecryptUpdate(ctx, buf, &out_len, indata, 32)) {
        printf("DecryptUpdate failed\n");
        EVP_CIPHER_CTX_free(ctx);
        return 1;
    }
    printf("Got %d from Update\n", out_len);
    dump_head(buf, sizeof(buf));
        
    printf("Final!\n");
    memset(buf, 0, sizeof(buf));
    if(!EVP_DecryptFinal_ex(ctx, buf, &out_len)) {
        printf("DecryptFinal failed, input is not valid wrap ciphertext\n");
        EVP_CIPHER_CTX_free(ctx);
        return 1;
    }
    printf("Got %d from Final\n", out_len);
    dump_head(buf, sizeof(buf));

    EVP_CIPHER_CTX_free(ctx);
    return 0;
}
切换到EVP_aes_256_wrap_pad的注意点
  1. 将EVP_aes_128_wrap_pad()替换为EVP_aes_256_wrap_pad()
  2. 将key缓冲区长度改为32字节,填入对应256位密钥
  3. 其余逻辑(设置flag、IV传NULL或传8字节自定义IV)保持不变即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:06:22