【问题标题】:CryptDecrypt decrypts only first bytesCryptDecrypt 只解密第一个字节
【发布时间】:2016-10-06 19:33:44
【问题描述】:

我正在使用 Windows Crypto API,但无法解密文件。在CryptDecrypt 之后,我的文件的一些第一个字节被解密,但其他字节是垃圾。

例如:

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

这是 MCVE。我从文件input.txt 中读取内容,加密它,写入文件encrypted.txt。然后我阅读encrypted.txt 并用相同的密钥解密并保存到decrypted.txt。 decrypted.txt 唯一的第一个字节是正确的。

#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;
}

【问题讨论】:

  • 如果您将"encrypted.txt" 命名为"encrypted.bin" 并在ofstreamifstream 的构造函数中提供binary 标志,您能试试吗?
  • 您在CryptGenKey()CryptEncrypt()CryptDecrypt() 上缺少任何错误处理。
  • 我查了一下,所有这些函数都返回true

标签: c++ winapi cryptography cryptoapi


【解决方案1】:

我猜你和我做的一样 - 将数据添加到加密文件然后尝试解密它......好吧,你似乎无法使用未一次加密的 CryptDecrypt 解密数据.

如果您想将数据添加到现有的加密文件,您需要先将其内容读取到内存并解密(oldData),然后添加 newData,将 oldData+newData 全部加密,然后写入文件(覆盖)。 它适用于我的代码:

    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;
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-01
    • 2014-05-29
    • 2022-01-15
    • 2021-05-24
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 2010-11-14
    相关资源
    最近更新 更多