CryptoAPI RSA: CryptDecrypt只在第一次解密,其他调用返回NTE_BAD_DATA

CryptoAPI RSA: CryptDecrypt decrypts only at the first time, other calls return NTE_BAD_DATA

本文关键字:调用 其他 返回 NTE BAD DATA 解密 RSA CryptDecrypt 第一次 CryptoAPI      更新时间:2023-10-16

我已经编写了加密/解密自定义长度的内存缓冲区的程序。加密结束得很好;但是我的解密代码只在任何缓冲区位置解密一次数据,这对应于块条目。其他块的解密以NTE_BAD_DATA结束。

你有什么建议为什么会发生这种情况?

这是我的加密代码:

void CWinRSA::FinishEncrypt(const char* pcbRawData, const size_t nDataSize, char** ppcbEcrData, size_t& rnEcrSize) const
{
    if (m_hProvider == NULL)
    {
        throw ("Cannot encrypt data with wrong provider!!");
    }
    if (m_hKey == NULL)
    {
        throw ("Cannot encrypt data with a wrong key!!");
    }
    size_t nBlockLength = GetBlockLength();
    size_t nPaddingSize = nBlockLength - 11;
    size_t nRemain = nDataSize % nBlockLength;
    size_t nBlockProcess = (nDataSize / nPaddingSize + (nRemain != 0 ? 1 : 0));
    size_t nResultSize = nBlockProcess * nBlockLength;
    (*ppcbEcrData) = new char[nResultSize];
    DWORD dwBufferLength = nBlockLength;
    DWORD dwDataLength;
    for (int iBlock = 0; iBlock < nBlockProcess - 1; iBlock++)
    {
        memcpy((*ppcbEcrData) + (iBlock * nBlockLength),
            pcbRawData + (iBlock * nPaddingSize), nPaddingSize);
        dwDataLength = nPaddingSize;
        if (!CryptEncrypt(m_hKey, NULL, FALSE, 0,
            (BYTE*)((*ppcbEcrData) + (iBlock * nBlockLength)),
            &dwDataLength, dwBufferLength))
        {
            throw ("Cannot encrypt data!!");
        }
    }
    memcpy((*ppcbEcrData) + ((nBlockProcess - 1) * nBlockLength),
        pcbRawData + ((nBlockProcess - 1) * nPaddingSize), (nRemain ? nRemain : nPaddingSize));
    dwDataLength = (nRemain ? nRemain : nPaddingSize);
    if (!CryptEncrypt(m_hKey, NULL, TRUE, 0,
        (BYTE*)((*ppcbEcrData) + ((nBlockProcess - 1) * nBlockLength)),
        &dwDataLength, dwBufferLength))
    {
        throw ("Cannot encrypt data!!");
    }
    rnEcrSize = nResultSize;
}

解密:

void CWinRSA::FinishDecrypt(const char* pcbRawData, const size_t nDataSize, char** ppcbDecData, size_t& rnDecSize) const
{
    if (m_hProvider == NULL)
    {
        throw ("Cannot decrypt data with wrong provider!!");
    }
    if (m_hKey == NULL)
    {
        throw ("Cannot decrypt data with a wrong key!!");
    }
    size_t nBlockLength = GetBlockLength();
    if ((nDataSize % nBlockLength) != 0)
    {
        throw ("Cannot decrypt data!! Probably data is corrupted!!");
    }
    size_t nPaddingSize = nBlockLength - 11;
    size_t nBlockProcess = nDataSize / nBlockLength;
    size_t nResultSize = nBlockProcess * nPaddingSize;
    (*ppcbDecData) = new char[nResultSize];
    DWORD dwDataLength;
    char* pcbComputeResult = new char[nBlockLength];
    for (int iBlock = 0; iBlock < nBlockProcess - 1; iBlock++)
    {
        memcpy(pcbComputeResult, pcbRawData + (iBlock * nBlockLength), nBlockLength);
        if (!CryptDecrypt(m_hKey, NULL, FALSE, 0, (BYTE*)pcbComputeResult, &dwDataLength))
        {
            throw ("Cannot decrypt data!!");
        }
        memcpy((*ppcbDecData) + (iBlock * nPaddingSize), pcbComputeResult, nPaddingSize);
    }
    memcpy(pcbComputeResult, pcbRawData + ((nBlockProcess - 1) * nBlockLength), nBlockLength);
    if (!CryptDecrypt(m_hKey, NULL, TRUE, 0, (BYTE*)pcbComputeResult, &dwDataLength))
    {
        DWORD dwError = GetLastError();
        throw ("Cannot decrypt data!!");
    }
    memcpy((*ppcbDecData) + ((nBlockProcess - 1) * nPaddingSize), pcbComputeResult, nPaddingSize);
    rnDecSize = ((nBlockProcess - 1) * nPaddingSize) + dwDataLength;
    delete[] pcbComputeResult;
    pcbComputeResult = NULL;
}

RSA不应该这样使用。它真的不是一个分组密码(或者流密码)。我的理解是,除了一条"短"消息外,它真的没有任何密码学用途,因此,在从密钥解密一次后,库失败并不令我感到惊讶。

如果你需要保护任意大小的数据,使用RSA交换对称密钥为流或块密码(如AES)

我找到了答案。在所有解密调用之前,我必须初始化dwDataLength,以字节为单位的块长度。

dwDataLength = nBlockLength;
if (!CryptDecrypt(m_hKey, NULL, TRUE, 0, (BYTE*)pcbComputeResult, &dwDataLength))
{
     DWORD dwError = GetLastError();
     throw ("Cannot decrypt data!!");
}

完整的解密方法

void CWinRSA::FinishDecrypt(const char* pcbRawData, const size_t nDataSize, char** ppcbDecData, size_t& rnDecSize) const
{
    if (m_hProvider == NULL)
    {
        throw ("Cannot decrypt data with wrong provider!!");
    }
    if (m_hKey == NULL)
    {
        throw ("Cannot decrypt data with a wrong key!!");
    }
    size_t nBlockLength = GetBlockLength();
    if ((nDataSize % nBlockLength) != 0)
    {
        throw ("Cannot decrypt data!! Probably data is corrupted!!");
    }
    size_t nPaddingSize = nBlockLength - 11;
    size_t nBlockProcess = nDataSize / nBlockLength;
    size_t nResultSize = nBlockProcess * nPaddingSize;
    (*ppcbDecData) = new char[nResultSize];
    DWORD dwDataLength;
    char* pcbComputeResult = new char[nBlockLength];
    for (int iBlock = 0; iBlock < nBlockProcess - 1; iBlock++)
    {
        memcpy(pcbComputeResult, pcbRawData + (iBlock * nBlockLength), nBlockLength);
        dwDataLength = nBlockLength;
        if (!CryptDecrypt(m_hKey, NULL, FALSE, 0, (BYTE*)pcbComputeResult, &dwDataLength))
        {
            throw ("Cannot decrypt data!!");
        }
        memcpy((*ppcbDecData) + (iBlock * nPaddingSize), pcbComputeResult, nPaddingSize);
    }
    memcpy(pcbComputeResult, pcbRawData + ((nBlockProcess - 1) * nBlockLength), nBlockLength);
    dwDataLength = nBlockLength;
    if (!CryptDecrypt(m_hKey, NULL, TRUE, 0, (BYTE*)pcbComputeResult, &dwDataLength))
    {
        throw ("Cannot decrypt data!!");
    }
    memcpy((*ppcbDecData) + ((nBlockProcess - 1) * nPaddingSize), pcbComputeResult, nPaddingSize);
    rnDecSize = ((nBlockProcess - 1) * nPaddingSize) + dwDataLength;
    delete[] pcbComputeResult;
    pcbComputeResult = NULL;
}