Search code examples
c++cryptographyaescrypto++

AES IV into file with FileSource and FileSink


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 ?


Solution

  • 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));