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; }
关键优化说明
- 修复变量初始化:将明文长度赋值移到正确位置,确保加密时传入合法的长度参数。
- 修正文件流判断:加密分支使用
ofs判断输出文件状态,错误信息准确对应操作。 - 解密内存正确分配:为解密后的明文分配独立堆内存,避免写入只读区域。
- 移除手动Padding处理:依赖BCrypt内置的PKCS7 padding处理逻辑,避免手动截断错误。
- 修复密钥语法错误:将非法的
0xoF改为0x0F,确保密钥正确初始化。 - 统一函数名:修正函数名大小写不一致问题,保证调用匹配。
- 完善参数逻辑:main函数增加加密/解密模式参数,支持双向操作,使用更灵活。
- 优化内存释放:区分加密和解密时的内存来源,避免错误释放只读内存。
内容的提问来源于stack exchange,提问作者user23533541
相关产品推荐
相关产品推荐

