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

使用OpenSSL EVP_CipherFinal_ex解密失败问题求助

问题分析与修复

你的代码存在三个关键问题,导致解密阶段EVP_CipherFinal_ex调用失败:

1. 丢失EVP_CipherUpdate生成的数据

在_cipherMessage函数中,你只将EVP_CipherFinal_ex输出的字节加入结果向量,完全忽略了EVP_CipherUpdate阶段产生的大部分数据。EVP_CipherUpdate会处理输入的核心数据并输出中间结果,EVP_CipherFinal_ex仅处理剩余的块和填充数据。丢失中间数据会导致加密后的缓冲区不完整,解密时无法通过最终的块校验。

2. 未禁用填充(与命令行行为不一致)

你在命令行中使用了-nopad参数禁用填充,但代码中OpenSSL默认启用PKCS#7填充。由于你的输入刚好是16字节(AES-128-CBC的块大小),启用填充会让加密后的数据额外增加16字节的填充内容,这与你预期的命令行结果不符,也会导致解密时的校验失败。

3. 密钥与命令行实际使用的不一致

你命令行中输入的-K参数是15字节的十六进制串0102030405060708090a0b0c0d0e0f,OpenSSL会自动在末尾补0凑够16字节,实际使用的密钥是0102030405060708090A0B0C0D0E0F00;但代码中的密钥是000102030405060708090A0B0C0D0E0F,两者完全不匹配。


修复后的代码

#include <iostream>
#include <vector>
#include <openssl/evp.h>

using namespace std;
typedef vector<uint8_t> Vect;

Vect _cipherMessage(const Vect& ai_in, const Vect& ai_key, const Vect& ai_iv, int ai_encode_decode)
{
    cout << ((ai_encode_decode==1)?"ENCODE":"DECODE") << endl;
    Vect w_ret;
    uint8_t outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
    int outlen;
    int total_outlen = 0;
    
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, ai_key.data(), ai_iv.data(), ai_encode_decode);
    // 禁用填充,匹配命令行-nopad参数
    EVP_CIPHER_CTX_set_padding(ctx, 0);
    
    if (!EVP_CipherUpdate(ctx, outbuf, &outlen, ai_in.data(), ai_in.size()))
    {
        cout << "EVP_CipherUpdate failed" << endl;
        EVP_CIPHER_CTX_free(ctx);
        return w_ret;
    }
    total_outlen = outlen;
    // 保存Update阶段的数据
    for (int i=0 ; i<outlen ; i++)
    {
        w_ret.push_back(outbuf[i]);
    }
    
    if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen))
    {
        cout << "EVP_CipherFinal_ex failed" << endl;
        EVP_CIPHER_CTX_free(ctx);
        return w_ret;
    }
    total_outlen += outlen;
    // 保存Final阶段的数据
    for (int i=0 ; i<outlen ; i++)
    {
        w_ret.push_back(outbuf[i]);
    }
    
    EVP_CIPHER_CTX_free(ctx);
    return w_ret;
}

int main()
{
    Vect w_inputFrame { 0x53, 0x69, 0x78, 0x74, 0x65, 0x65, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x6f, 0x6e, 0x67 }; // "SixteenBytesLong" in hex
    // 修正密钥,匹配命令行实际使用的密钥
    Vect w_key { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00 };
    Vect w_iv { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00 };

    Vect w_encryptedFrame = _cipherMessage(w_inputFrame, w_key, w_iv, 1);
    Vect w_decryptedFrame = _cipherMessage(w_encryptedFrame, w_key, w_iv, 0);
    cout << "Encryption / Decryption : " << ((w_inputFrame == w_decryptedFrame)?"SUCCESS":"FAILURE") << endl;

    return 0;
}

关键修复点说明

  • 新增total_outlen变量跟踪输出数据总长度,分别保存EVP_CipherUpdate和EVP_CipherFinal_ex的输出结果;
  • 调用EVP_CIPHER_CTX_set_padding(ctx, 0)禁用填充,与命令行行为一致;
  • 修正密钥数组,匹配OpenSSL命令行自动补0后的实际密钥值;
  • 调整IV数组,与命令行使用的IV一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 10:26:04