I have just startet working with crypto++ and i have a question about the piplenes and how to use them to encrypt a file.
I want to use AES to encrypt a file.
1.)Would it be enough to just do:
EAX<AES>::Encryption encryptor;
encryptor.SetKeyWithIV(derived.data(), 16, ivb, ivb.size());
FileSource f("source", new AuthenticatedEncryptionFilter(encryptor,new FileSink("deststination")));
2.) If i have a huge input file, will this approach automaticly encrypt the files in blocks?
3.) Would this automaticly create the output file if it is not there?
EDIT:
Ok, i got it to wok with my approch.
The 2.) Question remains and i have a new one:
Can I tell it to skip the first 24 bytes of the file?
EAX<AES>::Encryption encryptor; encryptor.SetKeyWithIV(derived.data(), 16, ivb, ivb.size()); FileSource f("source", new AuthenticatedEncryptionFilter(encryptor,new FileSink("deststination")));
Close. The AuthenticatedEncryptionFilter
will be coerced to the bool pumpAll
parameter of FileSink
. So you need:
FileSource f("source", true, new AuthenticatedEncryptionFilter(encryptor,new FileSink("deststination")));
Also see FileSource on the Crypto++ wiki. And the FileSource Class Reference from the manual might be of interest, too.
If i have a huge input file, will this approach automatically encrypt the files in blocks?
Yes. Internally, Crypto++ will "block" or "chunk" the processing in 4096-bytes, IIRC. A recent discussion about it occurred on the mailing list at ios locking up during encryption.
A program that allows you to do the blocking is provided in the post. You can use it to throttle the processing, a place to update a progress bar or yield the processor, if needed. Its reproduced below.
Would this automatically create the output file if it is not there?
Yes. The FileSource
is just a std::ifstream
wrapper, while a FileSink
is just a std::ofstream
wrapper.
Again, here are the wiki pages:
Can I tell it to skip the first 24 bytes of the file?
Yes. In this case, use bool pumpAll
and set it to false
. Then do something like:
FileSource fs("source", false, new AuthenticatedEncryptionFilter(...));
fs.Skip(24);
size_t remaining = <size of file>;
size_t BLOCK_SIZE = 512;
while(remaining && !fs.SourceExhausted())
{
const unsigned int req = STDMIN(remaining, BLOCK_SIZE);
fs.Pump(req);
fs.Flush(false);
remaining -= req;
}
Or, you can:
FileSource fs("source", false, new AuthenticatedEncryptionFilter(...));
fs.Skip(24);
fs.PumpAll();
Also see FileSource Class Reference in the manual. Skip
is part of BufferedTransformation
; and PumpAll
is part of Source
.
There are also wiki pages covering EAX mode and the authenticated {en|de}cryption filters. See:
There's even a page on using a Java-like Init/Update/Final at:
The program below uses CFB_Mode<AES>
, but its easy enough to swap in another cipher and mode. It also demonstrates how to place objects on the stack and use them in a pipeline rather than creating them on the heap with new
.
int main(int argc, char* argv[])
{
static const unsigned int BIG_SIZE = 2U * 1024U * 1024U;
static const unsigned int BLOCK_SIZE = 4096U;
try
{
SecByteBlock key(32);
OS_GenerateRandomBlock(false, key.data(), key.size());
// cout << "Key: ";
// ArraySource as(key.data(), key.size(), true, new HexEncoder(new FileSink(cout)));
// cout << endl;
CFB_Mode<AES>::Encryption enc;
enc.SetKeyWithIV(key.data(), key.size(), key.data());
MeterFilter meter;
StreamTransformationFilter stf(enc);
FileSource source("/dev/zero", false);
FileSink sink("zero.enc");
source.Attach(new Redirector(stf));
stf.Attach(new Redirector(meter));
meter.Attach(new Redirector(sink));
unsigned int remaining = BIG_SIZE;
while(remaining && !source.SourceExhausted())
{
if(remaining % (1024) == 0)
{
cout << "Processed: " << meter.GetTotalBytes() << endl;
}
const unsigned int req = STDMIN(remaining, BLOCK_SIZE);
source.Pump(req);
source.Flush(false);
remaining -= req;
}
}
catch(const Exception& ex)
{
cerr << ex.what() << endl;
}
return 0;
}