В настоящее время я работаю над простой системой шифрования / дешифрования в C ++ с использованием Windows API.
Я считаю, что мне удалось получить CryptEncrypt()
работать (AES_128) для шифрования файла.
Но когда я использую CryptDecrypt()
чтобы расшифровать файл, первые 16 байтов повреждаются, а затем после 4000 байтов (это размер фрагментов, которые я извлекаю из ReadFile()
и шифрование) это еще один кусок поврежденных байтов и так далее. Если я пытаюсь расшифровать файл с общей длиной менее 4000 байт, расшифровка работает отлично.
Я очень смущен тем, почему это происходит. Там нет ошибок вообще.
Вот фрагмент моего кода (у меня есть 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 bytesread 704
Второй CryptEncrypt bytesread 720
Second CryptDecrupt bytesread 704
Все, кажется, хорошо с этим, но у меня все еще есть проблема.
Я использую расширенный crypto api (с verifycontext) с сгенерированным одиночным ключом AES со свойством CRYPT_EXPORTABLE
Вы вообще не обрабатываете ошибки. Все функции API, которые вы вызываете, имеют возвращаемые значения и коды ошибок, ни одну из которых вы не проверяете.
Вы тоже не управляете bytesRead
правильно. CryptEncrypt()
изменяет переменную, которую вы передаете ей, что затем влияет на ваш вызов 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;
Других решений пока нет …