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

AES 256加密后代码挂起原因及优化方案咨询

问题原因分析与代码修复

程序挂起/异常的核心原因

  • 未初始化变量引发非法内存访问:加密分支中cbData = inputString.length();被错误注释到上一行,导致cbPlainText = cbData使用未初始化的cbData,BCryptEncrypt处理未知长度的数据,引发内存越界或无限等待。
  • 文件流判断逻辑错误:加密分支中错误使用解密分支的ifs变量判断输出文件是否打开成功,导致文件打开失败时无法进入Cleanup流程,引发资源泄漏或挂起。
  • 解密分支内存分配错误:解密时直接将文件名的只读内存(inputString.c_str())赋值给pbPlainText,试图写入只读区域触发内存访问冲突,导致崩溃或挂起。
  • 手动Padding处理错误:BCryptDecrypt启用BCRYPT_BLOCK_PADDING时会自动移除PKCS7 padding,手动截断会导致数据损坏,引发后续异常。
  • 密钥语法错误:0xoF是非法十六进制值(应为0x0F),导致密钥初始化失败,加密解密流程异常。
  • 函数名大小写不匹配:定义的ENcryptDecryptString与main中调用的EncryptDecryptString大小写不一致,引发未定义行为。

修复后的完整代码

#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#include <iostream>
#include <fstream>
#include <string>

#pragma comment(lib, "bcrypt.lib")

#define NT_SUCCESS(Status)          (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)
#define KEY_SIZE 32
#define IV_SIZE 16

void EncryptDecryptString(const std::string& input, const std::string& outputFile, bool encrypt){
    const unsigned char ENCRYPTION_KEY[KEY_SIZE] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
    };
    
    const unsigned char IV[IV_SIZE] = {
        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
        0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F
    };
    
    BCRYPT_ALG_HANDLE hAesAlg = NULL;
    BCRYPT_KEY_HANDLE hKey = NULL;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    DWORD cbCipherText = 0, cbPlainText = 0, cbData = 0, cbKeyObject = 0, cbBlockLen = 0;
    PBYTE pbCipherText = NULL, pbPlainText = NULL, pbKeyObject = NULL, pbIV = NULL;
    
    // 打开AES算法句柄
    if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0))){
        wprintf(L"BCryptOpenAlgorithmProvider failed: 0x%x\n", status);
        goto Cleanup;
    }
    
    // 获取密钥对象缓冲区大小
    if (!NT_SUCCESS(status = BCryptGetProperty(hAesAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbData, 0))){
        wprintf(L"BCryptGetProperty(BCRYPT_OBJECT_LENGTH) failed: 0x%x\n", status);
        goto Cleanup;
    }
    
    // 分配密钥对象内存
    pbKeyObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbKeyObject);
    if (pbKeyObject == NULL){
        wprintf(L"HeapAlloc for pbKeyObject failed\n");
        goto Cleanup;
    }
    
    // 获取AES块长度(IV大小)
    if (!NT_SUCCESS(status = BCryptGetProperty(hAesAlg, BCRYPT_BLOCK_LENGTH, (PBYTE)&cbBlockLen, sizeof(DWORD), &cbData, 0))){
        wprintf(L"BCryptGetProperty(BCRYPT_BLOCK_LENGTH) failed: 0x%x\n", status);
        goto Cleanup;
    }
    
    // 分配IV内存并复制初始向量
    pbIV = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlockLen);
    if (pbIV == NULL){
        wprintf(L"HeapAlloc for pbIV failed\n");
        goto Cleanup;
    }
    memcpy(pbIV, IV, IV_SIZE);
    
    // 设置CBC链模式
    if (!NT_SUCCESS(status = BCryptSetProperty(hAesAlg, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0))){
        wprintf(L"BCryptSetProperty(BCRYPT_CHAINING_MODE) failed: 0x%x\n", status);
        goto Cleanup;
    }
    
    // 生成对称密钥
    if (!NT_SUCCESS(status = BCryptGenerateSymmetricKey(hAesAlg, &hKey, pbKeyObject, cbKeyObject, (PBYTE)ENCRYPTION_KEY, KEY_SIZE, 0))){
        wprintf(L"BCryptGenerateSymmetricKey failed: 0x%x\n", status);
        goto Cleanup;
    }
    
    if (encrypt){
        // 加密流程:input为明文字符串
        cbPlainText = static_cast<DWORD>(input.length());
        pbPlainText = const_cast<PBYTE>(reinterpret_cast<const unsigned char*>(input.c_str()));
        
        // 获取加密后数据所需大小
        if (!NT_SUCCESS(status = BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV, cbBlockLen, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING))){
            wprintf(L"BCryptEncrypt(get size) failed: 0x%x\n", status);
            goto Cleanup;
        }
        
        // 分配密文内存
        pbCipherText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbCipherText);
        if (pbCipherText == NULL){
            wprintf(L"HeapAlloc for pbCipherText failed\n");
            goto Cleanup;
        }
        
        // 执行加密操作
        if (!NT_SUCCESS(status = BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV, cbBlockLen, pbCipherText, cbCipherText, &cbData, BCRYPT_BLOCK_PADDING))){
            wprintf(L"BCryptEncrypt(encrypt) failed: 0x%x\n", status);
            goto Cleanup;
        }
        
        // 将密文写入输出文件
        std::ofstream ofs(outputFile, std::ios::binary);
        if (!ofs){
            std::cerr << "Failed to open output file: " << outputFile << std::endl;
            goto Cleanup;
        }
        ofs.write(reinterpret_cast<char*>(pbCipherText), cbCipherText);
    } else {
        // 解密流程:input为密文文件名
        std::ifstream ifs(input, std::ios::binary);
        if(!ifs){
            std::cerr << "Failed to open input file: " << input << std::endl;
            goto Cleanup;
        }
        
        // 获取密文文件大小
        ifs.seekg(0, std::ios::end);
        std::streampos fileSize = ifs.tellg();
        ifs.seekg(0, std::ios::beg);
        cbCipherText = static_cast<DWORD>(fileSize);
        
        // 分配密文内存并读取文件内容
        pbCipherText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbCipherText);
        if (pbCipherText == NULL){
            wprintf(L"HeapAlloc for pbCipherText failed\n");
            goto Cleanup;
        }
        ifs.read(reinterpret_cast<char*>(pbCipherText), fileSize);
        
        // 获取解密后数据所需大小
        if (!NT_SUCCESS(status = BCryptDecrypt(hKey, pbCipherText, cbCipherText, NULL, pbIV, cbBlockLen, NULL, 0, &cbPlainText, BCRYPT_BLOCK_PADDING))){
            wprintf(L"BCryptDecrypt(get size) failed: 0x%x\n", status);
            goto Cleanup;
        }
        
        // 分配明文内存
        pbPlainText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbPlainText);
        if (pbPlainText == NULL){
            wprintf(L"HeapAlloc for pbPlainText failed\n");
            goto Cleanup;
        }
        
        // 执行解密操作(自动移除PKCS7 padding)
        if (!NT_SUCCESS(status = BCryptDecrypt(hKey, pbCipherText, cbCipherText, NULL, pbIV, cbBlockLen, pbPlainText, cbPlainText, &cbData, BCRYPT_BLOCK_PADDING))){
            wprintf(L"BCryptDecrypt(decrypt) failed: 0x%x\n", status);
            goto Cleanup;
        }
        
        // 将明文写入输出文件
        std::ofstream ofs(outputFile, std::ios::binary);
        if (!ofs){
            std::cerr << "Failed to open output file: " << outputFile << std::endl;
            goto Cleanup;
        }
        ofs.write(reinterpret_cast<char*>(pbPlainText), cbData);
    }

Cleanup:
    if (pbCipherText) HeapFree(GetProcessHeap(), 0, pbCipherText);
    // 加密时pbPlainText指向字符串只读内存,无需释放;解密时为堆内存,需要释放
    if (!encrypt && pbPlainText) HeapFree(GetProcessHeap(), 0, pbPlainText);
    if (pbKeyObject) HeapFree(GetProcessHeap(), 0, pbKeyObject);
    if (pbIV) HeapFree(GetProcessHeap(), 0, pbIV);
    if (hKey) BCryptDestroyKey(hKey);
    if (hAesAlg) BCryptCloseAlgorithmProvider(hAesAlg, 0);
}

int main(int argc, char* argv[])
{
    if (argc != 4){
        std::cerr << "Usage: " << argv[0] << " <input> <output_file> <encrypt/decrypt>" << std::endl;
        std::cerr << "Example: " << argv[0] << " \"hello world\" encrypted.bin encrypt" << std::endl;
        std::cerr << "Example: " << argv[0] << " encrypted.bin decrypted.txt decrypt" << std::endl;
        return 1;
    }
    
    std::string input = argv[1];
    std::string outputFile = argv[2];
    bool encrypt = (std::string(argv[3]) == "encrypt");
    
    EncryptDecryptString(input, outputFile, encrypt);
    
    std::cerr << (encrypt ? "Encryption" : "Decryption") << " completed successfully." << std::endl;
    
    return 0;
}

关键优化说明

  1. 修复变量初始化:将明文长度赋值移到正确位置,确保加密时传入合法的长度参数。
  2. 修正文件流判断:加密分支使用ofs判断输出文件状态,错误信息准确对应操作。
  3. 解密内存正确分配:为解密后的明文分配独立堆内存,避免写入只读区域。
  4. 移除手动Padding处理:依赖BCrypt内置的PKCS7 padding处理逻辑,避免手动截断错误。
  5. 修复密钥语法错误:将非法的0xoF改为0x0F,确保密钥正确初始化。
  6. 统一函数名:修正函数名大小写不一致问题,保证调用匹配。
  7. 完善参数逻辑:main函数增加加密/解密模式参数,支持双向操作,使用更灵活。
  8. 优化内存释放:区分加密和解密时的内存来源,避免错误释放只读内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:04:50