2

I have the need to crypt big files (multi GB) with crypto++. I managed to find an example on the documentation that helped me create the 2 followings functions :

bool AESEncryptFile(const std::string& clearfile, const std::string& encfile, const std::string& key) {
    
    try {
        byte iv[CryptoPP::AES::BLOCKSIZE] = {};
        CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryptor;
        encryptor.SetKeyWithIV((unsigned char*)key.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH, iv);

        CryptoPP::StreamTransformationFilter filter(encryptor);

        CryptoPP::FileSource source(clearfile.c_str(), false);
        CryptoPP::FileSink sink(encfile.c_str());

        source.Attach(new CryptoPP::Redirector(filter));
        filter.Attach(new CryptoPP::Redirector(sink));

        const CryptoPP::word64 BLOCK_SIZE = 4096;
        CryptoPP::word64 processed = 0;

        while (!EndOfFile(source) && !source.SourceExhausted()) {
            source.Pump(BLOCK_SIZE);
            filter.Flush(false);
            processed += BLOCK_SIZE;
        }

        filter.MessageEnd();
        return true;
    } catch (const CryptoPP::Exception& ex) {
        return false;
    }
    
}

bool AESDecryptFile(const std::string& encfile, const std::string& clearfile, const std::string& key) {
    
    try {
        byte iv[CryptoPP::AES::BLOCKSIZE] = {};
        CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryptor;
        decryptor.SetKeyWithIV((unsigned char*)key.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH, iv);

        CryptoPP::StreamTransformationFilter filter(decryptor);

        CryptoPP::FileSource source(encfile.c_str(), false);
        CryptoPP::FileSink sink(clearfile.c_str());

        source.Attach(new CryptoPP::Redirector(filter));
        filter.Attach(new CryptoPP::Redirector(sink));

        const CryptoPP::word64 BLOCK_SIZE = 4096;
        CryptoPP::word64 processed = 0;

        while (!EndOfFile(source) && !source.SourceExhausted()) {
            source.Pump(BLOCK_SIZE);
            filter.Flush(false);
            processed += BLOCK_SIZE;
        }
.
        filter.MessageEnd();
        return true;
    } catch (const CryptoPP::Exception& ex) {
        return false;
    }
}

This is working great. On 8 GB files i'm using very little memory. But as you can see the IV is (empty for now) hardcoded and i would like to :

  • While encrypting , put it a the end of the file.
  • While decrypting : get the IV from the file to init the decryptor.

Is there a way to do that with crypto++ or should i handle it manually after/before the enc/decryption process ?

Sam Mason
  • 15,216
  • 1
  • 41
  • 60
grunk
  • 14,718
  • 15
  • 67
  • 108
  • minor point, but why do you want to put the IV at the "end of the file" rather than at the beginning? you will necessarily know it before you start encrypting and will need it before decrypting. therefore putting it at the end will mean that you need to do at least one more `seek` on the file (probably two) to extract it before decrypting. – Sam Mason Sep 04 '20 at 09:52
  • I didn't really think about it. It just seems easier to add data at the end of a file rather than at the begining. But whatever works is ok for me :) – grunk Sep 04 '20 at 09:57
  • Putting these details at the beginning of the file is common. e.g. https://github.com/fernet/spec/blob/master/Spec.md#token-format describes a simple/short/readable format that shows how things can be structured. I don't know `CryptoPP`, so can't help directly but this flexibility might help other people. I'd also think about using some authentication (like fernet) to make sure the data hasn't been corrupted/tampered with. – Sam Mason Sep 04 '20 at 11:12
  • I think you can write `filter.MessageEnd(0);` meaning that the message ending is not propagated. Then you can write the IV to the sink, and of course close it afterwards. – Maarten Bodewes Sep 05 '20 at 23:08

1 Answers1

0

Thanks to all the differents comments here is what i managed to do. As suggested by @Sam Mason i put the iv at the beginning of the file :

So before starting to encrypt i 'm putting the iv at the beginning of the file:

CryptoPP::ArraySource(iv, sizeof(iv), true,
    new CryptoPP::Redirector(sink)
);
// Encrypt

And then when decrypting i'm getting the IV back like this :

unsigned char iv[CryptoPP::AES::BLOCKSIZE];
CryptoPP::ArraySink ivSink(iv, sizeof(iv));
source.Attach(new CryptoPP::Redirector(ivSink));
source.Pump(CryptoPP::AES::BLOCKSIZE);
// Decrypt

Note for future reader : Don't use an empty IV like show in my OP , instead generate one randomly , for example :

CryptoPP::AutoSeededRandomPool prng;
unsigned char iv[CryptoPP::AES::BLOCKSIZE];
prng.GenerateBlock(iv, sizeof(iv));
grunk
  • 14,718
  • 15
  • 67
  • 108