使用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
相关产品推荐
相关产品推荐

