c++ 在加密函数期间返回函数或子例程时,会发生堆损坏

chhkpiq4  于 2023-04-01  发布在  其他
关注(0)|答案(1)|浏览(125)

我尝试使用RSA public_key加密AES密钥,并在控制台上打印加密的字节。我使用Windows Cryptographic API加密密钥,并使用Microsoft记录的方法获取加密字节所需的缓冲区大小,如下面提供的代码:
我面临的问题是,每次当我的程序执行和lockKey函数被调用时,在每次返回时,它都会给予堆损坏的错误,即使lockKey函数中的所有代码都已成功执行。我已经调试了代码,但无法找到原因,因为每次函数返回时都会抛出异常(结束括号)。
完整代码如下:

#include <windows.h>
#include <wincrypt.h>
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <fstream>

#pragma comment(lib, "crypt32.lib")
using namespace std;

void lockKey(std::string, HCRYPTKEY, HCRYPTPROV);
void handleError(const char*);
std::string byteToHex(BYTE*, DWORD);

void handleError(const char* message)
{
    cerr << message << " error code: " << GetLastError() << endl;
    exit(1);
}

std::string byteToHex(BYTE* inputBytes, DWORD inputSize)
{
    std::string outputString;
    DWORD hexSize = 0;
    if (!CryptBinaryToStringA(inputBytes, inputSize, CRYPT_STRING_HEX, NULL, &hexSize))
    {
        // handle error
        handleError("Failed to get size of encrypted bytes key");
        return NULL;
    }

    outputString.resize(hexSize, '\0');
    if (!CryptBinaryToStringA(inputBytes, inputSize, CRYPT_STRING_HEX, &outputString[0], &hexSize))
    {
        // handle error
        handleError("Failed to convert encrypted bytes key to hexSize");
        return NULL;
    }
    //outputString.resize(hexSize - 1); // remove null terminator
    return outputString;
}

void lockKey(std::string publickey, HCRYPTKEY hKey, HCRYPTPROV hCryptProv)
{
    //Import RSA public key
    std::vector<BYTE> publicKeyBytes;
    DWORD publicKeySize = 0;
    if (!CryptStringToBinaryA(publickey.c_str(), publickey.length(), CRYPT_STRING_BASE64, NULL, &publicKeySize, NULL, NULL)) {
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error getting binary size");
    }
    publicKeyBytes.resize(publicKeySize);
    if (!CryptStringToBinaryA(publickey.c_str(), publickey.length(), CRYPT_STRING_BASE64, publicKeyBytes.data(), &publicKeySize, NULL, NULL)) {
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error converting to binary");
    }

    HCRYPTKEY phKey = NULL;
    if (!CryptImportKey(hCryptProv, publicKeyBytes.data(), publicKeyBytes.size(), 0, 0, &phKey)) {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error importing key");
    }

    //Export AES key for encryption
    //Determine the size of the buffer needed for the exported key
    DWORD dwBufSizeAES = 0;
    if (!CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB, NULL, NULL, &dwBufSizeAES))
    {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error determining key buffer size");
    }

    // Allocate a buffer for the exported key
    //BYTE* pbAesKey = new BYTE[dwBufSizeAES];
    //memset(pbAesKey, 0, dwBufSizeAES);
    std::vector<BYTE> pbAesKey(dwBufSizeAES, 0);

    // Export the key to the buffer
    if (!CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB, NULL, pbAesKey.data(), &dwBufSizeAES))
    {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error exporting key");
    }

    //Encrypt AES key with RSA public key
    //Determine the size of the buffer needed for the encrypted key
    DWORD dwBufSize = 0;
    if (!CryptEncrypt(phKey, NULL, TRUE, 0, NULL, &dwBufSize, 0))
    {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error determining encrypted buffer size");
    }

    //PBYTE pbEncryptedKey = (PBYTE)malloc(dwBufSize);
    std::vector<BYTE> pbEncryptedKey(dwBufSize, 0);

    // Encrypt the AES key with RSA-OAEP padding
    DWORD cbAesKey = 0;
    if (!CryptEncrypt(phKey, NULL, TRUE, 0, pbAesKey.data(), &cbAesKey, dwBufSize))
    {
        CryptDestroyKey(phKey);
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Error encrypting AES key");
    }

    memcpy(pbEncryptedKey.data(), pbAesKey.data(), dwBufSize);   

    // Now pbEncryptedKey contains the encrypted AES key
    std::string hexEncryptedKey = byteToHex(pbEncryptedKey.data(), dwBufSize);
    cout << "Encrypted AES Key Bytes: \n" << hexEncryptedKey << endl;
    CryptDestroyKey(phKey);

} //error always on this line of code.

int main()
{
    DWORD blockSize;
    HCRYPTKEY hKey;
    HCRYPTPROV hCryptProv;

    // Import the RSA public key as in the previous example.
    std::string publickey = "valid public key"; //removed

    // Generate aes key
    hCryptProv;
    if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
        CryptReleaseContext(hCryptProv, 0);
        handleError("Failed to acquire cryptographic context");
    }
    hKey;
    if (!CryptGenKey(hCryptProv, CALG_AES_256, CRYPT_EXPORTABLE, &hKey)) {
        CryptReleaseContext(hCryptProv, 0);
        handleError("Failed to generate key");
    }
    // Get the block size for the algorithm
    blockSize;
    DWORD dwDataLen = sizeof(DWORD);
    if (!CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE*)&blockSize, &dwDataLen, 0)) {
        CryptDestroyKey(hKey);
        CryptReleaseContext(hCryptProv, 0);
        handleError("Failed to get block size");
    }
        
    lockKey(publickey, hKey, hCryptProv);
    
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
    return 0;

}

错误的屏幕截图如下:

如果继续,则给予堆损坏错误:

我一开始使用的是内存管理函数,比如memset、malloc、free、delete等,但是由于堆错误,我把缓冲区转移到了vector上,我知道这更好地避免了内存损坏。然而,我的错误仍然没有解决。我已经调试了程序,并检查了每个变量的可用值和缓冲区。一切都在它应该。我错过了一些东西。任何帮助都将不胜感激。

gab6jxml

gab6jxml1#

我已经向ChatGPT-4提出了同样的问题,并得到了准确的答案。看起来问题是我处理加密密钥缓冲区的方式。当我调用CryptEncrypt时,pbAesKey缓冲区被加密数据覆盖。然而,我已经分配了pbEncryptedKey单独存储加密密钥。而不是将加密数据从pbAesKey复制到pbEncryptedKey,我应该直接将数据加密到pbEncryptedKey中。
所以替换代码

if (!CryptEncrypt(phKey, NULL, TRUE, 0, pbAesKey.data(), &cbAesKey, dwBufSize)){
    CryptDestroyKey(phKey);
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
    handleError("Error encrypting AES key");
}
memcpy(pbEncryptedKey.data(), pbAesKey.data(), dwBufSize);

memcpy(pbEncryptedKey.data(), pbAesKey.data(), dwBufSizeAES);
if (!CryptEncrypt(phKey, NULL, TRUE, 0, pbEncryptedKey.data(), &dwBufSizeAES, dwBufSize)){
    CryptDestroyKey(phKey);
    CryptDestroyKey(hKey);
    CryptReleaseContext(hCryptProv, 0);
    handleError("Error encrypting AES key");
}

已解决问题。
这样,我首先将AES密钥复制到pbEncryptedKey中,然后使用pbEncryptedKey作为加密数据的缓冲区,之后,我可以安全地使用pbEncryptedKey.data()将加密密钥转换为十六进制字符串,而不会出现任何堆损坏问题。

相关问题