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

使用OpenSSL和C++实现AES-CBC加密时输出结果不一致的问题

问题分析与修复方案

核心问题1:十六进制字符串转字节数组错误

你的密钥和IV是十六进制字符串,但代码直接用std::copy把字符串的ASCII字符复制到字节数组里,这会导致实际使用的密钥/IV完全不是你预期的值。比如keyString里的字符"A"会被存为ASCII值0x41,而非十六进制对应的0xAC,这是加密结果乱变的主要原因。

修复方法:实现十六进制转字节函数

替换直接复制的代码,用专门的转换函数把十六进制字符串转成字节:

#include <cctype>

// 十六进制字符串转字节数组
bool hexStrToBytes(const std::string& hexStr, uint8_t* outBytes, size_t outLen) {
    if (hexStr.length() != outLen * 2) return false;
    for (size_t i = 0; i < outLen; ++i) {
        char high = toupper(hexStr[i*2]);
        char low = toupper(hexStr[i*2+1]);
        uint8_t highByte = (high >= 'A') ? (high - 'A' + 10) : (high - '0');
        uint8_t lowByte = (low >= 'A') ? (low - 'A' + 10) : (low - '0');
        outBytes[i] = (highByte << 4) | lowByte;
    }
    return true;
}

然后替换原代码中复制密钥和IV的部分:

// 替换原来的std::copy调用
std::uint8_t iv[AES_BLOCK_SIZE];
std::uint8_t key[AES_KEYLENGTH/8]; // 256位密钥对应32字节
if (!hexStrToBytes(keyString, key, AES_KEYLENGTH/8) || !hexStrToBytes(ivString, iv, AES_BLOCK_SIZE)) {
    // 处理转换错误,比如密钥/IV长度不匹配
    return;
}

核心问题2:未按标准填充明文

CBC模式要求输入长度必须是AES块大小(16字节)的整数倍。你虽然扩展了输出长度,但只是用vector默认的0填充,不符合PKCS#7标准填充规范——而且如果明文长度刚好是块大小的倍数,也需要额外填充一个完整块,否则解密时无法区分真实数据和填充数据。

修复方法:添加PKCS#7填充

在加密前对明文做填充:

// PKCS#7填充
size_t paddingLen = AES_BLOCK_SIZE - (inputLen % AES_BLOCK_SIZE);
std::vector<uint8_t> paddedData(data.begin(), data.end());
paddedData.resize(inputLen + paddingLen, paddingLen); // 填充paddingLen个值为paddingLen的字节
size_t encLen = paddedData.size();

后续加密时用paddedData作为输入。

其他问题:二进制数据输出错误

你用printf("%s", encOut.data())打印加密结果是错的——加密后是二进制数据,可能包含空字节\0导致printf提前截断,而且二进制数据不可打印,应该用十六进制格式输出:

// 打印十六进制加密结果
printf("encrypted data: ");
for (uint8_t b : encOut) {
    printf("%02X", b);
}
printf("\n");

修复后的完整代码片段

#define AES_KEYLENGTH 256
#include <cctype>

bool hexStrToBytes(const std::string& hexStr, uint8_t* outBytes, size_t outLen) {
    if (hexStr.length() != outLen * 2) return false;
    for (size_t i = 0; i < outLen; ++i) {
        char high = toupper(hexStr[i*2]);
        char low = toupper(hexStr[i*2+1]);
        uint8_t highByte = (high >= 'A') ? (high - 'A' + 10) : (high - '0');
        uint8_t lowByte = (low >= 'A') ? (low - 'A' + 10) : (low - '0');
        outBytes[i] = (highByte << 4) | lowByte;
    }
    return true;
}

void NetworkHandler::SendEncryptedPacket(std::vector<std::uint8_t>& data)
{
    std::string keyString = "AC3CF1B84D7C946640447DE9670E18BE8A45F49A286FC4D8404DD729491064E4";
    std::string ivString = "5D4FB5A040DE76B316794BAC89FC3A48";

    printf("noncrypted data: %s\n", data.data());
    size_t inputLen = data.size();

    // PKCS#7填充
    size_t paddingLen = AES_BLOCK_SIZE - (inputLen % AES_BLOCK_SIZE);
    std::vector<uint8_t> paddedData(data.begin(), data.end());
    paddedData.resize(inputLen + paddingLen, paddingLen);
    size_t encLen = paddedData.size();
    std::vector<std::uint8_t> encOut(encLen);

    // 初始化密钥和IV
    std::uint8_t iv[AES_BLOCK_SIZE];
    std::uint8_t key[AES_KEYLENGTH/8];
    if (!hexStrToBytes(keyString, key, AES_KEYLENGTH/8) || !hexStrToBytes(ivString, iv, AES_BLOCK_SIZE)) {
        printf("Invalid key or IV\n");
        return;
    }

    AES_KEY encKey;
    // 检查密钥是否有效(返回0为成功)
    if (AES_set_encrypt_key(key, AES_KEYLENGTH, &encKey) != 0) {
        printf("Failed to set encrypt key\n");
        return;
    }
    // AES_cbc_encrypt会修改传入的iv,要保留原始IV需先复制
    uint8_t ivCopy[AES_BLOCK_SIZE];
    memcpy(ivCopy, iv, AES_BLOCK_SIZE);
    AES_cbc_encrypt(paddedData.data(), encOut.data(), encLen, &encKey, ivCopy, AES_ENCRYPT);

    // 打印十六进制加密结果
    printf("encrypted data: ");
    for (uint8_t b : encOut) {
        printf("%02X", b);
    }
    printf("\n");

    SendPacket(encOut);
}

调试检查点

如果还要排查问题,可以重点看:

  • 转换后的密钥/IV字节值是否和十六进制字符串对应(比如调试器看key数组前几个字节是不是0xAC, 0x3C, 0xF1)
  • 填充后的明文长度是否是16的整数倍,填充字节是否正确
  • AES_set_encrypt_key的返回值(非0说明密钥无效)
  • 加密前后IV数组的变化(CBC会更新IV,需保留原始IV的话必须复制)

内容的提问来源于stack exchange,提问作者FoxMaccloud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 23:50:34