Qt OpenSSL C++与PHP AES-256-CBC加密结果不一致求助
解决C++与PHP AES-256-CBC加密结果不一致的问题
你的问题根源完全在于填充方式不匹配:PHP的openssl_encrypt默认使用PKCS#7填充(即使指定OPENSSL_RAW_DATA,也会自动应用该标准填充),而你的C++代码用的是零填充(\0填充),这直接导致最后一个加密块的明文内容不同,最终输出仅末尾字节存在差异。
问题细节拆解
- PHP端:
openssl_encrypt在未显式指定OPENSSL_ZERO_PADDING时,会遵循PKCS#7规则填充——填充的每个字节值等于需要填充的长度(比如需要填充3字节,就填充0x03 0x03 0x03)。 - C++端:你手动填充的是
\0(即0x00),和PKCS#7的填充逻辑完全相悖,最后一个块的明文不一致,加密结果自然出现差异。
修复步骤
1. 修改C++加密逻辑为PKCS#7填充
替换原来的零填充代码,改用标准PKCS#7填充:
QByteArray encryptAES(QByteArray passphrase, QByteArray plainText, QByteArray myiv) { unsigned char* Key = (unsigned char*) passphrase.data(); unsigned char* IV = (unsigned char*) myiv.data(); AES_KEY* AesKey = new AES_KEY(); AES_set_encrypt_key(Key, 256, AesKey); // 替换零填充为PKCS#7填充 const int UserDataSize = plainText.size(); int RequiredPadding = AES_BLOCK_SIZE - (UserDataSize % AES_BLOCK_SIZE); for(int i=0; i < RequiredPadding; i++) { // 填充字节的值等于填充长度 plainText.push_back(static_cast<char>(RequiredPadding)); } unsigned char* UserData = (unsigned char*) plainText.data(); const int UserDataSizePadded = plainText.size(); // 改用动态分配缓冲区,避免栈溢出风险 unsigned char* EncryptedData = new unsigned char[UserDataSizePadded](); AES_cbc_encrypt(UserData, EncryptedData, UserDataSizePadded, (const AES_KEY*)AesKey, IV, AES_ENCRYPT); QByteArray encrypted(reinterpret_cast<char*>(EncryptedData), UserDataSizePadded); // 释放动态分配的内存,避免泄漏 delete[] EncryptedData; delete AesKey; return encrypted; }
2. 修复C++解密逻辑,移除PKCS#7填充
解密后需要手动去掉PKCS#7填充,否则明文末尾会残留填充字节:
QByteArray decryptAES(QByteArray passphrase, QByteArray encryptedText, QByteArray myiv) { unsigned char* Key = (unsigned char*) passphrase.data(); unsigned char* IV = (unsigned char*) myiv.data(); AES_KEY* AesDecryptKey = new AES_KEY(); AES_set_decrypt_key(Key, 256, AesDecryptKey); // 动态分配解密缓冲区 unsigned char* DecryptedData = new unsigned char[encryptedText.size()](); AES_cbc_encrypt((unsigned char*) encryptedText.data(), DecryptedData, encryptedText.size(), (const AES_KEY*)AesDecryptKey, IV, AES_DECRYPT); QByteArray decrypted(reinterpret_cast<char*>(DecryptedData), encryptedText.size()); // 释放内存 delete[] DecryptedData; delete AesDecryptKey; // 移除PKCS#7填充 int paddingLen = static_cast<unsigned char>(decrypted.back()); if (paddingLen > 0 && paddingLen <= AES_BLOCK_SIZE) { decrypted.chop(paddingLen); } return decrypted; }
3. 修正PHP代码的小错误
你的PHP代码里有个赋值错误:$RequiredPadding == (16 - ($UserDataSize % 16));用了双等号(比较),应该改为单等号赋值:
$RequiredPadding = (16 - ($UserDataSize % 16));
验证结果
修改完成后,C++的加密结果会和PHP的$enc完全一致,解密也能正确恢复原始明文,不会残留多余的填充字节。如果你想让PHP适配零填充(不推荐,PKCS#7更安全且是行业标准),可以在openssl_encrypt中添加OPENSSL_ZERO_PADDING参数,但需手动处理填充逻辑。
内容的提问来源于stack exchange,提问作者Pyromanci
相关产品推荐
相关产品推荐

