简体   繁体   English

使用 Crypto++ 加密大数据的有效方法

[英]Effecient way for encrypt large data using Crypto++

I am looking for a solution to encrypt/decrypt a big file (some GBs) using Crypto++.我正在寻找一种使用 Crypto++ 加密/解密大文件(一些 GB)的解决方案。 Several days ago, I was thinking about using StringSource in this question , read the whole file into a char array, then encrypt/decrypt it using CTR mode.几天前,我正在考虑在这个问题中使用 StringSource ,将整个文件读入一个字符数组,然后使用 CTR 模式对其进行加密/解密。

Encrypt a string to a string将字符串加密为字符串

string  encryptString(string plain, byte key[], int sizeKey, byte iv[], int sizeIV){
    string cipher;
    try{
        CTR_Mode< AES >::Encryption e;
        e.SetKeyWithIV(key, sizeKey, iv, sizeIV);

        StringSource s(plain, true,
            new StreamTransformationFilter(e,
            new StringSink(cipher)
            )
            );

#if 0
        StreamTransformationFilter filter(e);
        filter.Put((const byte*)plain.data(), plain.size());
        filter.MessageEnd();

        const size_t ret = filter.MaxRetrievable();
        cipher.resize(ret);
        filter.Get((byte*)cipher.data(), cipher.size());
#endif
        return cipher;
    }
    catch (const CryptoPP::Exception& e)
    {
        cerr << e.what() << endl;
        return NULL;
    }
}

Decrypt a string to a string将字符串解密为字符串

string  decryptString(string cipher, byte key[], int sizeKey, byte iv[], int sizeIV){
    string reco;
    try{
        CTR_Mode< AES >::Decryption d;
        d.SetKeyWithIV(key, sizeKey, iv, sizeIV);

        StringSource s(cipher, true,
            new StreamTransformationFilter(d,
            new StringSink(reco)
            )
            );

#if 0
        StreamTransformationFilter filter(e);
        filter.Put((const byte*)plain.data(), plain.size());
        filter.MessageEnd();

        const size_t ret = filter.MaxRetrievable();
        cipher.resize(ret);
        filter.Get((byte*)cipher.data(), cipher.size());
#endif
        return reco;
    }
    catch (const CryptoPP::Exception& e)
    {
        cerr << e.what() << endl;
        return reco;
    }
}

Wrap the encrypt string above将加密字符串包裹在上面

char* encrypt(char * plainText, byte key[], int sizeKey, byte iv[], int sizeIV, long len){
    string ss(plainText, len);
    long lengSS = ss.length();

    string cipher = encryptString(ss, key, sizeKey, iv, sizeIV);
    len = cipher.size();
    char * writable = new  char[len];
    std::copy(cipher.begin(), cipher.end(), writable);
    writable[len] = '\0';
    return writable;
}

Wrap the decrypt string above将上面的解密字符串包裹起来

char* decrypt(char * cipher, byte key[], int sizeKey, byte iv[], int sizeIV, long len){
    string ss(cipher, len);
    long lengSS = ss.length();
    string recovered = decryptString(ss, key, sizeKey, iv, sizeIV);
    //FileUtil::writeStringToFile("d2.txt", recovered);
    char * writable = new char[recovered.size() ];
    std::copy(recovered.begin(), recovered.end(), writable);
    writable[recovered.size() ] = '\0';
    return writable;
}

The main主要的

int main(int argc, char* argv[])
{
    AutoSeededRandomPool prng;

    byte key[AES::DEFAULT_KEYLENGTH] = { '1', '2', '3', '4', '5', '6', '7', '8', '1', '2', '3', '4', '5', '6', '7', '8' };
    byte iv[AES::BLOCKSIZE] = { '8', '7', '6', '5', '4', '3', '2', '1', '8', '7', '6', '5', '4', '3', '2', '1' };
    //prng.GenerateBlock(iv, sizeof(iv));
    char* pdata = "CTR encrypt mode 1234567890";
    char * sourceFileName = "1MB.txt";
    char * targetFileName = "1MB.aes.crpp.txt";

    /*
    Looking for parameters.
    param 0: e to encrypt. d to decrypt
    param 1: sourceFileName
    param 2: targetFileName
    */
    if (argc > 1){

        char * action = argv[1];
        sourceFileName = argv[2];
        targetFileName = argv[3];
        long size = 0;

        char * pdata = FileUtil::readAllByte(sourceFileName, size);

        string ext = getExtension(sourceFileName);

        char * result1 = NULL;
        if (strcmp(action, "e") == 0){
            result1 = encrypt(pdata, key, sizeof(key), iv, sizeof(iv), size);
        }
        else if (strcmp(action, "d") == 0){
            result1 = decrypt(pdata, key, sizeof(key), iv, sizeof(iv), size);
        }
        FileUtil::writeFile(targetFileName, result1, size);
        //FileUtil::writeStringToFile(targetFileName, recovered1);
    }
    else{
        cout << "Missing/Invalid params" << endl;

    }
    return 0;

}

Now this solution can encrypt/decrypt file have size up to several hundreds MB.现在这个解决方案可以加密/解密大小高达数百 MB 的文件。 But when I using it with 1GB text file, its got error:但是当我将它与 1GB 文本文件一起使用时,出现错误:

Unhandled exception at 0x74DFA6F2 in AES-CRPP.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x00AFE480.

at the line:在线:

char*encrypt(...){
string ss(data, len)
...
}

I have 8GB of RAM and its look like reading 1GB of char and convert it into string cause the error.我有 8GB 的​​ RAM,它看起来像是读取 1GB 的字符并将其转换为字符串导致错误。 In another question , jww gave me a hint at the bottom, but I cannot make it work.在另一个问题中,jww 在底部给了我一个提示,但我无法让它工作。 Is there a solution for large byte (char) array encrypt using Crypto++是否有使用 Crypto++ 加密大字节(char)数组的解决方案

About using FileSource Document here: enter link description here Code example:关于在此处使用 FileSource 文档:在此处输入链接描述代码示例:

EAX< Blowfish >::Encryption e1;
        e1.SetKeyWithIV(key, key.size(), iv, sizeof(iv));

        CryptoPP::FileSource fs1(ofilename.c_str(), true,
            new AuthenticatedEncryptionFilter(e1,
            new FileSink(efilename.c_str())
            ));



        EAX< Blowfish >::Decryption d2;
        d2.SetKeyWithIV(key, key.size(), iv, sizeof(iv));

        CryptoPP::FileSource fs2(efilename.c_str(), true,
            new AuthenticatedDecryptionFilter(d2,
            new FileSink(rfilename.c_str()),
            AuthenticatedDecryptionFilter::THROW_EXCEPTION
            ));

It doesn't allow me to export the output cipher to a temporatory char * variable, instead of saving directly to a file.它不允许我将输出密码导出到临时 char * 变量,而不是直接保存到文件中。 Of course I can wait for the file to file encryption to completed, then read the output file into the memory again, but its seem so bad.当然我可以等待文件到文件加密完成,然后再次将输出文件读入内存,但它看起来很糟糕。

As you told you want to encrypt big file while consuming less memory in the RAM.正如您所说,您想加密大文件,同时在 RAM 中消耗更少的内存。 So you can use pipeline used in the crypto++ .所以你可以使用在crypto++使用的管道。 Please refer to this link https://www.cryptopp.com/wiki/Pumping_Data请参考此链接https://www.cryptopp.com/wiki/Pumping_Data

Now here you will only see how to limit the size of your process.现在,您将只看到如何限制流程的大小。 So if you want to do the encryption of big file.所以如果你想做大文件的加密。 It is always preferable to encrypt big file in block by block.最好是逐块加密大文件。 So you can use cipher block techniques of crypto++ .所以你可以使用crypto++密码块技术。

You can use StreamTransformationFilter as it automatically encrypt the file in blocks.您可以使用StreamTransformationFilter因为它会自动以块为单位加密文件。

I have reproduce the code to do the same.我已经复制了代码来做同样的事情。 The following code will encrypt the big size file using pipeline process.以下代码将使用管道过程加密大文件。 It won't take more than 10MB of RAM in your computer.它不会占用您计算机中超过 10MB 的 RAM。

bool Widget::optimize_enc(const char *filename){
    try
        {
            string pwd="qwertyuiopasdfgh";
            const char* enc="out.aes";

            byte iv[ CryptoPP::CIPHER::BLOCKSIZE ];
            memset( iv, 0x01, CryptoPP::CIPHER::BLOCKSIZE );

            CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption Encryptor((byte*)&pwd[0], pwd.size(), iv);

            StreamTransformationFilter f1(Encryptor, new FileSink(enc));
            ChannelSwitch cs;
            cs.AddDefaultRoute(f1);

            FileSource(filename, true /*pumpAll*/, new Redirector(cs));

        }
        catch(const Exception& ex)
        {
            std::cerr << ex.what() << std::endl;
            return false;
        }
    return true;
}

Remember the length of the passphrase should be of 16 bytes.请记住, passphrase的长度应为16个字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM