Question

I'm currently working on a simple encryption/decryption system in C++ using the Windows API.

I believe I've been successful at getting CryptEncrypt() to work (AES_128) for encrypting a file. But when I Use CryptDecrypt() to decrypt the file, the first 16 bytes are corrupted and then after 4000 bytes (which is the size of the chunks I'm pulling from ReadFile() and encrypting) is another chunk of corrupted bytes and so on. If I try to decrypt a file with a total length less than 4000 bytes, the decryption works perfectly.

I'm very confused about why this is happening. There are no errors at all.

Here is a snippet of my code (I have CryptEncrypt() and CryptDecrypt() right after each other to save me exporting the key and to make the testing faster):

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;

I would really appreciate any suggestions about whats going wrong.

EDIT: On a 4704 bytes file I got the following using breakpoints.

First ReadFile bytesread 4000 First CryptEncrypt bytesRead 4000 First CryptDecrypt bytesRead 4000 Second ReadFile bytesread 704 Second CryptEncrypt bytesread 720 Second CryptDecrupt bytesread 704

Everything seems good with that yet I still get a problem.

I'm using the enhanced crypto api (With verifycontext) with a generated a single AES key with the CRYPT_EXPORTABLE property

Was it helpful?

Solution

You are not doing any error handling at all. All of the API functions you are calling have return values and error codes, none of which you are checking.

You are also not managing bytesRead correctly. CryptEncrypt() modifies the variable you pass to it, which then affects your call to CreateDecrypt(), which also modifies it, and that then affects subsequent calls to SetFilePointer(), which you should not be calling in your loop to begin with. You are not validating that you have as many bytes as you are expecting, or that bytesRead ends up back at the original value that ReadFile() returned, so you may end up skipping bytes in the source file.

Try something more like this instead:

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top