AES-CBC(256bit):C++与PHP加密输出不一致问题求助
问题分析与解决方案
核心问题是C++与PHP的AES-CBC加密输出不一致,根源大概率是填充方式不匹配:PHP的openssl_encrypt默认使用PKCS#7填充,而你当前使用的WjCryptLib可能未实现该填充逻辑,或默认使用了零填充/无填充。以下是具体解决步骤:
1. 验证填充逻辑
先确认WjCryptLib的AesCbcEncryptWithKey是否自动处理PKCS#7填充:
- 查看该函数的实现代码,如果没有填充逻辑,需手动实现PKCS#7填充后再加密。
- PKCS#7填充规则:将输入数据填充至AES块大小(固定16字节)的整数倍,填充字节的值等于需要填充的字节数。例如输入"SecreteKey"(10字节),需填充6个
0x06字节。
手动实现PKCS#7填充(内联函数)
inline void pkcs7_pad(std::vector<uint8_t>& data, size_t block_size = 16) { size_t pad_len = block_size - (data.size() % block_size); for (size_t i = 0; i < pad_len; ++i) { data.push_back(static_cast<uint8_t>(pad_len)); } } inline void pkcs7_unpad(std::vector<uint8_t>& data, size_t block_size = 16) { if (data.empty()) return; uint8_t pad_len = data.back(); if (pad_len > 0 && pad_len <= block_size) { data.resize(data.size() - pad_len); } }
2. 修改C++加密代码
将输入数据先填充,再调用加密函数,同时修正加密结果的输出方式(避免终端乱码干扰对比):
#include <vector> #include <iostream> #include <iomanip> // 插入WjCryptLib的AES函数声明或实现 // 插入上面的pkcs7_pad/pkcs7_unpad内联函数 int main() { std::string InputText = "SecreteKey"; std::string IV = "1234567890123456"; std::string Key = "12345678901234567890123456789012"; // 转换为字节向量并执行PKCS#7填充 std::vector<uint8_t> input_bytes(InputText.begin(), InputText.end()); pkcs7_pad(input_bytes); // 准备加密缓冲区 std::vector<uint8_t> cipher_text(input_bytes.size(), 0); // 调用加密函数(确保密钥长度为32字节,对应AES-256) AesCbcEncryptWithKey(reinterpret_cast<uint8_t*>(Key.data()), Key.size(), reinterpret_cast<uint8_t*>(IV.data()), input_bytes.data(), cipher_text.data(), cipher_text.size()); // 以十六进制输出加密结果(方便与PHP的bin2hex结果对比) std::cout << "Encrypted Hex: "; for (uint8_t b : cipher_text) { std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(b); } std::cout << std::dec << "\n"; // 解密测试 std::vector<uint8_t> decrypted_text(cipher_text.size(), 0); AesCbcDecryptWithKey(reinterpret_cast<uint8_t*>(Key.data()), Key.size(), reinterpret_cast<uint8_t*>(IV.data()), cipher_text.data(), decrypted_text.data(), decrypted_text.size()); // 去除PKCS#7填充 pkcs7_unpad(decrypted_text); std::cout << "Decrypted Text: " << std::string(decrypted_text.begin(), decrypted_text.end()) << "\n"; return 0; }
3. 对比PHP与C++的结果
在PHP代码中添加十六进制输出,方便与C++结果对比:
function NEncrypt($String, $EncKey, $IV) { return openssl_encrypt($String, 'aes-256-cbc', $EncKey, OPENSSL_RAW_DATA, $IV); } $EncryptedString = NEncrypt("SecreteKey", "12345678901234567890123456789012", "1234567890123456"); echo bin2hex($EncryptedString); // 输出十六进制字符串,与C++的Encrypted Hex对比
4. 更换内联库(如果WjCryptLib无法适配)
如果WjCryptLib的填充逻辑无法修改,推荐使用tiny-AES-c:这是一个单文件、纯内联的AES实现,支持CBC模式和PKCS#7填充,完全符合"所有函数必须内联,不能使用打包库"的要求。
使用tiny-AES-c的核心代码示例
将tiny-AES-c的aes.h和aes.c内容直接复制到你的C++文件中,然后调用:
// 加密流程 std::vector<uint8_t> input_bytes(InputText.begin(), InputText.end()); pkcs7_pad(input_bytes); AES_ctx ctx; AES_init_ctx_iv(&ctx, reinterpret_cast<const uint8_t*>(Key.data()), reinterpret_cast<const uint8_t*>(IV.data())); AES_CBC_encrypt_buffer(&ctx, input_bytes.data(), input_bytes.size()); // input_bytes现在就是与PHP一致的加密结果 // 解密流程 AES_init_ctx_iv(&ctx, reinterpret_cast<const uint8_t*>(Key.data()), reinterpret_cast<const uint8_t*>(IV.data())); AES_CBC_decrypt_buffer(&ctx, input_bytes.data(), input_bytes.size()); pkcs7_unpad(input_bytes);
内容的提问来源于stack exchange,提问作者YoAvrageBiTz
相关产品推荐
相关产品推荐

