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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 06:32:12