【问题标题】:CryptDecrypt() Failing to decrypt some blocks C++CryptDecrypt() 无法解密某些块 C++
【发布时间】:2014-05-29 06:18:52
【问题描述】:

我目前正在使用 Windows API 在 C++ 中开发一个简单的加密/解密系统。

我相信我已经成功地让CryptEncrypt() 工作 (AES_128) 来加密文件。 但是当我使用CryptDecrypt() 解密文件时,前 16 个字节被损坏,然后在 4000 个字节之后(这是我从ReadFile() 提取并加密的块的大小)是另一块损坏的字节,所以在。如果我尝试解密总长度小于 4000 字节的文件,则解密效果很好。

我很困惑为什么会这样。完全没有错误。

这是我的代码的 sn-p(我有一个紧挨着的 CryptEncrypt()CryptDecrypt(),以节省我导出密钥并加快测试速度):

DWORD bytesRead;
DWORD bytesWritten;
DWORD pointer = 0;
unsigned int blockSize = 4000;
void *fileBuffer = new unsigned char[4106];
bool EOF = false;
do
{
    SetFilePointer(hFileOrginal,pointer,0,0);
    ReadFile(hFileOrginal,fileBuffer,blockSize,&bytesRead,NULL);
    if(bytesRead<blockSize)
    {
        EOF=true;
    }
    CryptEncrypt(aesKey,NULL,EOF,0,(BYTE *)fileBuffer,&bytesRead,(blockSize+16));
    CryptDecrypt(aesKey,NULL,EOF,0,(BYTE *)fileBuffer,&bytesRead);

    WriteFile(hTempFile,fileBuffer,bytesRead,&bytesWritten,NULL);
    pointer +=bytesRead;
}
while(!EOF);
delete[] fileBuffer;

我非常感谢任何有关问题所在的建议。

编辑:在一个 4704 字节的文件上,我使用断点得到了以下内容。

第一个 ReadFile bytesread 4000 第一个 CryptEncrypt bytesRead 4000 第一个 CryptDecrypt bytesRead 4000 第二个 ReadFile 字节读取 704 第二个 CryptEncrypt 字节读取 720 第二个 CryptDecrupt 字节读取 704

一切似乎都很好,但我仍然遇到问题。

我正在使用增强型加密 api(带有 verifycontext),并使用 CRYPT_EXPORTABLE 属性生成单个 AES 密钥

【问题讨论】:

  • 尝试添加一些测试以确保在调用 CryptEncrypt 和 CryptDecrypt 对之前和之后 bytesRead 相同。您也不需要您的 SetFilePointer 和 pointer 代码,因为 ReadFile 无论如何都会按顺序读取。
  • 一切似乎都很正常。我将结果编辑到问题中。

标签: c++ winapi encryption cryptoapi


【解决方案1】:

您根本没有进行任何错误处理。您调用的所有 API 函数都有返回值和错误代码,您都没有检查它们。

您也没有正确管理bytesReadCryptEncrypt() 修改您传递给它的变量,然后影响您对CreateDecrypt() 的调用,这也修改它,然后影响对SetFilePointer() 的后续调用,您不应该在循环中开始调用。您没有验证您是否拥有预期的字节数,或者 bytesRead 最终返回到 ReadFile() 返回的原始值,因此您最终可能会跳过源文件中的字节。

试试类似的方法:

bool ReadFromFile(HANDLE hFile, void *Buffer, DWORD BufSize, DWORD *BytesRead)
{
    if (BytesRead)
        *BytesRead = 0;

    LPBYTE pBuffer = (LPBYTE) Buffer;
    DWORD dwRead;

    while (BufSize > 0)
    {
        if (!ReadFile(hFile, pBuffer, BufSize, &dwRead, NULL))
            return false;

        if (dwRead == 0)
            break;

        pBuffer += dwRead;
        BufSize -= dwRead;

        if (BytesRead)
            *BytesRead += dwRead;
    }

    return true;
}

bool WriteToFile(HANDLE hFile, void *Buffer, DWORD BufSize)
{
    LPBYTE pBuffer = (LPBYTE) Buffer;
    DWORD dwWritten;

    while (BufSize > 0)
    {
        if (!WriteFile(hFile, pBuffer, BufSize, &dwWritten, NULL))
            return false;

        pBuffer += dwWritten;
        BufSize -= dwWritten;
    }

    return true;
}

DWORD bytesRead;
const UINT blockSize = 4000;
LPBYTE fileBuffer = new BYTE[blockSize+16];
bool EOF;

if (SetFilePointer(hFileOrginal, 0, NULL, FILE_BEGIN) != 0)
{
    errorCode = GetLastError();
    ...
}
else
{
    do
    {
        if (!ReadFromFile(hFileOrginal, fileBuffer, blockSize, &bytesRead))
        {
            errorCode = GetLastError();
            ...
            break;
        }

        EOF = (bytesRead < blockSize);

        bytesEncrypted = bytesRead;
        if (!CryptEncrypt(aesKey, NULL, EOF, 0, fileBuffer, &bytesEncrypted, blockSize+16))
        {
            errorCode = GetLastError();
            ...
            break;
        }

        bytesDecrypted = bytesEncrypted;
        if (!CryptDecrypt(aesKey, NULL, EOF, 0, fileBuffer, &bytesDecrypted))
        {
            errorCode = GetLastError();
            ...
            break;
        }

        if (!WriteToFile(hTempFile, fileBuffer, bytesDecrypted))
        {
            errorCode = GetLastError();
            ...
            break;
        }

        if (bytesDecrypted != bytesRead)
        {
            ...
            break;
        }
    }
    while (!EOF);
}
delete[] fileBuffer;

【讨论】:

  • 我查看了您的代码并实现了它。它立即运行良好,但我遇到了同样的问题。不过,您的代码比我的更好看,更易于维护,所以我会保留它。
  • 你能显示初始化aesKey的代码吗?您是否尝试过使用单独的密钥句柄进行加密/解密而不是共享单个句柄?
  • 完美...一如既往。
猜你喜欢
  • 1970-01-01
  • 2019-08-19
  • 2018-12-02
  • 1970-01-01
  • 2017-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
相关资源
最近更新 更多