c++ - CryptDecrypt 只解密第一个字节

标签 c++ winapi cryptography cryptoapi

我正在使用 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 并使用相同的 key 解密它并保存到 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;
}

最佳答案

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

如果你想将数据添加到现有的加密文件中,你需要先将其内容读取到内存中并对其进行解密(旧数据),然后添加新数据,将所有旧数据+新数据一起加密,然后写入文件(覆盖)。 它适用于我的代码:

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

关于c++ - CryptDecrypt 只解密第一个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39904267/

相关文章:

c++ - 类命名空间?

c# - 忽略鼠标点击并将键盘输入发送到外部应用程序

ssl - 如果没有为 TLSv1.0 启用密码,协商还能进行吗?

c# - 哈希算法 SHA256,我的方法安全吗?如何添加盐值以使其更安全

grails - 是否可以在 GORM 层之外使用 Grails Jasypt 插件进行简单的字符串加密和解密?

c++ - CryptGenRandom 在循环调用时给出相同的值

c++ - 本地类友元函数的名称查找

c++ - 如何从字符串文字初始化 unsigned char 数组?

c++ - 尝试连接到 MessageBeep 系统 API

c++ - "child control"、 "child window"和 "child window control"之间有区别吗?