Alexey Markov
Alexey Markov

Reputation: 1566

CryptDecrypt decrypts only first bytes

I am using Windows Crypto API and can't decrypt file. After CryptDecrypt I got some first bytes of my file is decrypted, but other bytes are rubbish.

For example:

01234567012345670123456701234567012345670123456701234567012345670123456701234
56701234567012345670123456701234567012345670123456701234567012345670123456701
23456701234567012345670123456701234567012345670123456701234567012345670123456
70123456701еzc^HЏ-v"ЙЂQЋ;Ђ©ЕЮЃЛќА ы§Чюн-D„=оШХU†>™B‰Кy)Л¬6A)жO0”~sjё;<Лxj:("Ц
TвeхфOУKCв]H°фі"XШ8S{±~Ф\+a]gmъШie,Zџ§0ыќQq1ђ$sѓI~Чроы_2f

This is MCVE. I read content from file input.txt, ecnrypt it, write to file encrypted.txt. Then I read encrypted.txt and decrypt it with the same key and save to decrypted.txt. The only first bytes of decrypted.txt is correct.

#include "stdafx.h"
#include <fstream>
#include <Windows.h>
#include <wincrypt.h>

using namespace std;

HCRYPTPROV hProvider;
HCRYPTKEY hKey;


char* readFile(const char* filename, DWORD* bufferSize);
void encrypt();
void decrypt();

int main()
{
    //Create  context
    if (!CryptAcquireContextA(&hProvider, "container", NULL, PROV_RSA_FULL, 0))
    {
        if (!CryptAcquireContextA(&hProvider, "container", NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
            return 1;
    }

    //Create key
    CryptGenKey(
        hProvider,
        CALG_RC4,
        CRYPT_EXPORTABLE,
        &hKey);

    encrypt();
    decrypt();
}

//Read all file content
char* readFile(const char* filename, DWORD* bufferSize)
{
    //Чтение исходного файла
    ifstream is(filename);

    is.seekg(0, std::ios::end);
    *bufferSize = is.tellg();
    is.seekg(0, std::ios::beg);

    char* buffer = new char[*bufferSize];
    is.read(buffer, *bufferSize);
    is.close();

    return buffer;
}

void encrypt()
{
    //Read file
    DWORD dataSize;
    char* data = readFile("input.txt", &dataSize);

    //Encrypt
    CryptEncrypt(
        hKey,
        NULL,
        true,
        NULL,
        (unsigned char*)data,
        &dataSize,
        dataSize
    );

    //Write file
    ofstream os("encrypted.txt");
    os.write(data, dataSize);
    os.close();

    delete[] data;
 }

void decrypt()
{
    //Read file
    DWORD dataSize;
    char* data = readFile("encrypted.txt", &dataSize);

    //Encrypt
    CryptDecrypt(
        hKey,
        NULL,
        true,
        NULL,
        (unsigned char*)data,
        &dataSize
    );

    //Write file
    ofstream os("decrypted.txt");
    os.write(data, dataSize);
    os.close();

   delete[] data;
}

Upvotes: 0

Views: 672

Answers (1)

bardalas
bardalas

Reputation: 81

I'm guessing that you did the same as I did - adding data to an encrypted file and then try to decrypt it... Well, it seems that you can not decrypt data using CryptDecrypt that was not encrypted all at once.

If you want to add data to an existing encrypted file you'll need to first read it's content to the memory and decrypt it (oldData), then add the newData, encrypt all together oldData+newData and then write to file (overwrite). It works for me with this code:

    void CMFCApplication2Dlg::log2File(CString newData) {

        //Open or Create new log file
        if (!(file.Open(_T(FILE_NAME), CFile::modeNoTruncate | CFile::modeCreate | CFile::modeReadWrite)))
        {
            AfxMessageBox(_T("Couldn't open file."));
            return;
        }
        file.Close();

        CString oldData;

        //read binary data from file --> decrypt it and return decrypted oldData.
        readFile(oldData);      

        //Add at the end of file new data to be encrypted.
        oldData += newData;
        newData = oldData;  

        CByteArray arBytes;

        //Encypt new data
        //Derive a key from a password.
        crypto.DeriveKey(CRYPTO_PASS);

        //put encypted newData to arBytes.
        crypto.Encrypt(newData, arBytes);   

        //Delete file (we will write a new one ==> overwite)
        CFile::Remove(_T(FILE_NAME));       

        //Create new log file
        if (file.Open(_T(FILE_NAME), CFile::modeNoTruncate | CFile::modeCreate |CFile::modeReadWrite))
        {
            //Write the encrypted data (byte array) to a "new" file 
            //(we deleted the original one and creating a new one with the same name (overwrite)
            file.Write(arBytes.GetData(), static_cast<UINT>(arBytes.GetCount()));
            file.Close();
        }
        else {
            AfxMessageBox(_T("Couldn't write newData to file."));
        }


        //For Debug only ==> popup the file content
        CString str1;
        readFile(str1);
        AfxMessageBox((str1));

    }
    void CMFCApplication2Dlg::readFile(CString &str) {

        //Open the file in read mode
        if (  (file.Open(_T(FILE_NAME), CFile::modeRead) == TRUE) && 
            (file.GetLength() == 0) )
        {
            //There is no file ==> first time
            //Nothing to read, return empty string
            file.Close();
            str = "";
            return;
        }


        CByteArray arBytes;
        CString m_strData;

        //Size the array to accomodate the file bytes.
        arBytes.SetSize(static_cast<INT_PTR>(file.GetLength()));        

        //  Copy the data and close the file.
        file.Read(arBytes.GetData(), static_cast<UINT>(file.GetLength()));
        file.Close();

        //  Try and deserialize the data.
        //Derive a key from a password.
        crypto.DeriveKey(CRYPTO_PASS);
        if (crypto.Decrypt(arBytes, m_strData) == false)
            AfxMessageBox(_T("Coudln't decrypt data- check password."));
        else
        {
            //We have data !!
            str = m_strData;
        }
    }

Upvotes: 1

Related Questions