C++实现AES-CBC 256加密与SHA-512哈希的异常输出问题及遗留疑问
首先恭喜你已经解决了SHA-512跨语言不一致的问题——大小写差异确实是这类问题的常见坑,统一格式化就能轻松对齐。针对你遗留的AES加密结果混杂明文的疑问,我们来拆解代码里的几个关键问题:
问题根源分析
你看到加密结果里同时出现明文和加密数据,主要是由以下几个代码错误导致的:
输入数据的错误处理
你把明文"Hello World"直接传入fromHex处理,但fromHex是用来把十六进制字符串转成二进制的,明文本身不是十六进制,这会导致解析出乱码数据。更糟的是,fromHex返回std::string(dest)时,二进制数据里可能包含\0字符,std::string的构造函数遇到\0就会截断,导致数据不完整,同时还存在new char[_size]未释放的内存泄漏。加密结果的缓冲区溢出
加密分支里你定义了char res[inputLength];,但AES-CBC加密后的长度是块对齐的,正确长度应该是((inputLength + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE。用inputLength大小的数组存加密结果,会导致缓冲区溢出,破坏栈上的其他数据(比如之前存储的明文变量),这就是你看到明文混杂在加密结果里的核心原因。strlen的误用
加密后的二进制数据大概率包含\0字符,用strlen(res)获取长度会提前截断,导致后续输出时把栈上的其他数据(比如明文)也一并包含进去,进一步加剧了混乱。strcpy的潜在问题
之前用strcpy复制二进制数据(密钥、IV、输入),strcpy遇到\0就停止,会导致二进制数据复制不完整。换成memcpy是正确的选择,因为它会按指定长度完整复制。
修正后的关键代码示例
这里给你调整后的核心代码片段,解决上述问题:
修正AES-CBC 256函数
#include <vector> #include <openssl/aes.h> std::string Encryption::AES::cbc256(const unsigned char* data, size_t len, const unsigned char* key, const unsigned char* iv, bool encrypt) { AES_KEY aes_key; if (encrypt) { if (AES_set_encrypt_key(key, 256, &aes_key) != 0) { // 处理密钥错误 return ""; } } else { if (AES_set_decrypt_key(key, 256, &aes_key) != 0) { // 处理密钥错误 return ""; } } // 计算正确的输出长度:加密时块对齐,解密时输入应已对齐 size_t output_len = encrypt ? ((len + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE : len; std::vector<unsigned char> res(output_len); // 复制IV(因为AES_cbc_encrypt会修改IV) unsigned char iv_copy[AES_BLOCK_SIZE]; memcpy(iv_copy, iv, AES_BLOCK_SIZE); AES_cbc_encrypt(data, res.data(), len, &aes_key, iv_copy, encrypt ? AES_ENCRYPT : AES_DECRYPT); if (encrypt) { // 加密后转十六进制输出 return Encryption::Utils::toHex(res.data(), output_len); } else { // 解密后去掉PKCS#7填充(如果加密时用了填充) if (!res.empty()) { size_t padding_len = res.back(); if (padding_len > 0 && padding_len <= AES_BLOCK_SIZE) { res.resize(res.size() - padding_len); } } return std::string(res.begin(), res.end()); } }
修正fromHex工具函数
#include <string> #include <sstream> #include <stdexcept> std::string Encryption::Utils::fromHex(const std::string& hex_str) { if (hex_str.size() % 2 != 0) { throw std::invalid_argument("Hex string length must be even"); } std::string result; result.reserve(hex_str.size() / 2); for (size_t i = 0; i < hex_str.size(); i += 2) { std::string byte_str = hex_str.substr(i, 2); char byte = static_cast<char>(std::stoul(byte_str, nullptr, 16)); result.push_back(byte); } return result; }
额外提示
- 加密时记得添加PKCS#7填充(AES要求输入长度是块的倍数),修正后的加密函数已经处理了块对齐,解密时也对应去掉了填充。
- 避免用栈数组存储动态长度的数据,改用
std::vector更安全,防止缓冲区溢出。 - 处理二进制数据时,始终用
unsigned char类型,避免符号扩展导致的错误。
内容的提问来源于stack exchange,提问作者Ryan Fitzgerald

