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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:08:33