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

如何解决OpenSSL的'EVP_DecryptFinal_ex:wrong final block length'错误?

解决OpenSSL AES解密时"wrong final block length"错误的方案

咱们先拆解你遇到的这个错误——EVP_DecryptFinal_ex:wrong final block length通常意味着解密时的密文长度不符合AES块加密的对齐要求,或者密钥/IV不匹配导致解密过程中块校验失败。结合你的代码,我找到了几个关键问题:

1. 加密和解密的Salt完全不匹配

你加密时用的salt是"12345678",但解密时写成了"12345"——这会导致EVP_BytesToKey生成的密钥(key)和初始化向量(iv)完全不一样,解密自然会失败!这是最核心的问题。

修复方法:把解密代码里的salt改成和加密一致的:

unsigned char *salt = (unsigned char *)"12345678"; // 和加密端保持相同

2. 加密后写入文件的密文长度错误

你当前加密后直接把整个ciphertext向量写入文件,但实际上加密后的有效密文长度是c_len + f_len(EVP_EncryptUpdate返回的实际加密长度加上EVP_EncryptFinal_ex返回的填充块长度),而你初始化的ciphertext长度是size + AES_BLOCK_SIZE,里面包含了未使用的空字节,这些多余的字节会导致解密时密文长度不符合AES的块对齐要求。

修复方法:写入文件时只写入有效密文部分:

out_file.write((char*)ciphertext.data(), c_len + f_len); // 只写实际加密后的有效长度

3. 冗余的初始化函数调用

你提到的两次调用EVP_EncryptInit_ex/EVP_DecryptInit_ex其实是旧版本OpenSSL的遗留写法,在OpenSSL 1.1.1a里,只需要调用一次初始化函数即可,第二次空参数的调用可以删掉,不会影响功能。

4. 解密时的明文长度优化

解密时,明文的实际长度是p_len + f_len,你返回的plaintext向量包含了多余的空间,建议可以截断到有效长度,避免后续处理出现问题:

plaintext.resize(p_len + f_len);
return plaintext;

修复后的完整核心代码示例

加密部分调整后:

// 打开并读取待加密文件
std::ifstream in_file(file_name, std::ios::binary);
in_file.seekg(0, in_file.end);
long size = in_file.tellg();
in_file.seekg(0, in_file.beg);
std::vector<unsigned char> binarydata(size);
in_file.read((char*)binarydata.data(), size);
in_file.close();

// 加密操作
EVP_CIPHER_CTX *en = EVP_CIPHER_CTX_new();
unsigned char *salt = (unsigned char *)"12345678";
unsigned char *key_data = (unsigned char *)"super_secret_key_with_32_charact";
int k_len = strlen((const char*)key_data);
int nrounds = 5;
unsigned char key[32], iv[32];
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, k_len, nrounds, key, iv);
EVP_EncryptInit_ex(en, EVP_aes_256_cbc(), NULL, key, iv);

int c_len = 0, f_len = 0;
std::vector<unsigned char> ciphertext(size + AES_BLOCK_SIZE);
EVP_EncryptUpdate(en, ciphertext.data(), &c_len, binarydata.data(), size);
EVP_EncryptFinal_ex(en, ciphertext.data() + c_len, &f_len);
EVP_CIPHER_CTX_free(en);

// 将密文写入新文件
std::ofstream out_file(output_file, std::ios::binary);
out_file.write((char*)ciphertext.data(), c_len + f_len); // 写入有效长度
out_file.close();

解密部分调整后:

// 打开并读取加密文件
std::ifstream in_file(file_name, std::ios::binary);
in_file.seekg(0, in_file.end);
int size = in_file.tellg();
in_file.seekg(0, in_file.beg);
std::vector<unsigned char> ciphertext(size);
in_file.read((char*)ciphertext.data(), size);
in_file.close();

// 解密操作
EVP_CIPHER_CTX *de = EVP_CIPHER_CTX_new();
unsigned char *salt = (unsigned char *)"12345678"; // 和加密端一致
unsigned char *key_data = (unsigned char *)"super_secret_key_with_32_charact";
int k_len = strlen((const char*)key_data);
int nrounds = 5;
unsigned char key[32], iv[32];
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, k_len, nrounds, key, iv);
EVP_DecryptInit_ex(de, EVP_aes_256_cbc(), NULL, key, iv);

int p_len = 0, f_len = 0;
std::vector<unsigned char> plaintext(size);
EVP_DecryptUpdate(de, plaintext.data(), &p_len, ciphertext.data(), size);
EVP_DecryptFinal_ex(de, plaintext.data() + p_len, &f_len);
EVP_CIPHER_CTX_free(de);

plaintext.resize(p_len + f_len); // 截断到实际明文长度
return plaintext;

额外提示

  • AES-256需要32字节的密钥,你的key_data刚好是32字符,注意要确保它的长度确实是32,避免因字符串末尾的\0导致长度计算错误。
  • 建议在代码中添加错误检查,比如判断EVP_EncryptInit_ex、EVP_EncryptUpdate等函数的返回值,方便后续排查其他问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:58:53