Introduction
Target Audience
This article is targeted for MFC developers with understanding of the Crypto++ code library.
For the sake of clarity and introducing Crypto++ to those who are not familiar with it, I added the following paragraph.
Crypto++ Intro
From the Crypto++ website: "Crypto++ Library is a free C++ class library of cryptographic schemes".
Written and maintained by Wei Dai, this is a powerful library that contains modern cryptography algorithms.
To understand Crypto++, you should have (at least) basic understanding of cryptography concepts.
The World-Wide-Web offers a lot of information, and so does CodeProject (e.g.: See Jeffery Walton's valuable articles in this field).
For an in-depth reading, I found the book Applied Cryptography to be very enlightening. Beyond being very informative, it is written almost like an espionage/conspiracy novel, which makes reading it a lot more fun.
Back to Crypto++, the website contains valuable information and you may also want to visit the Crypto++ Wiki pages to get started.
I should point out that, to me, the learning curve was kinda slower than, oh, let's say, the time it took Trinity to learn how to fly that Bell 212 helicopter... (Note: I am not the geek you might think I am at this point in the article!)
Anyway, it will take a while to get used to the concepts and design patterns of the library (on a personal note, I really enjoyed reading Crypto++'s source code).
So, if you're going for it - don't get discouraged - once you get the hang of things, everything will fall into place and it'll all become clear.
The Problem
While integrating cryptography abilities into an MFC application I'm working on, I needed to use CFile
(s) with Crypto++'s code instead of its built-in fstream
file handling implementation.
Not being able to find such an implementation, I decided to write one.
The Code
This implementation will enable you to use an MFC CFile
as a Source / Sink element in conjunction with Crypto++'s data transport design pattern. It is pretty straightforward - I used Crypto++'s files.h/.cpp as a baseline, and made the necessary modifications for the code to work with a CFile
.
The code is based on Crypto++ v5.5.2 (but I believe it may work with earlier versions) and was tested on Visual C++ 6.0 and Visual Studio 2005.
Code Integration
The source code won't run on its own. You will have to integrate it into a working Crypto++ environment.
Crypto++ source code may be downloaded from Crypto++'s download section.
You'll probably want to review the Compiling and Integrating Crypto++ into the Microsoft Visual C++ Environment page, which will help you get started with Crypto++ on your version of Microsoft Visual Studio.
You may also have a look at the Crypto++ FAQ and the Crypto++ Wiki for a user reference, some useful examples and more information.
Using the Code
I'll use a simple file-copy operation to demonstrate the code.
void CopyFile( CFile* fin, CFile* fout )
{
MfcCFileSource( fin, true, new MfcCFileSink( fout ) );
}
This code will create an MfcCFileSource
wrapper for the input file, create a MfcCFileSink
wrapper for the output file, and pump all bytes from the input file to the output file.
Preserving the Output File Pointer
In the above example, MfcCFileSink
will be deleted somewhere during MfcCFileSource
's destruction sequence. Effectively, this means that MfcCFileSink
, in its turn, will delete the fout
file pointer (this will be done implicitly by a smart pointer that wraps fout
).
In order to overcome this hurdle, I added a boolean parameter to MfcCFileSink
's constructor:
MfcCFileSink( CFile* out, bool bAutoDelete = true );
The default value of bAutoDelete
will be to auto-delete the out
file pointer, which is the default behavior of having fout
wrapped in a smart pointer. In order to keep out
alive and unharmed, you should pass false
as the second parameter to MfcCFileSink
's constructor.
Here's the revised file-copy example:
void CopyFile( CFile* fin, CFile* fout, bool bAutoDeleteFOut )
{
MfcCFileSource( fin, true, new MfcCFileSink( fout, bAutoDeleteFOut ) );
}
Using this version of CopyFile
, it is possible to pass false
to bAutoDeleteFOut
and thus preserve fout
for consecutive operations (e.g., appending several files one after the other into a single output file).
No Auto-delete Option for a Filename Constructor
While we're on the subject, I'll just add the filename related constructor:
MfcCFileSink(LPCTSTR filename, bool binary=true);
Since the CFile
pointer in this case is maintained internally in this case, I'd like to keep it that way. That is why there is no bAutoDeleteFOut
parameter here. If you really need the CFile*
- open a file in advance and pass it to the appropriate constructor.
A Real-Life Example
Of course, any transformation filter may be applied before MfcCFileSink
in order to manipulate the bytes on their way from the source to the sink.
In order to see the code in action, here's a real-life example of compressing and encrypting an input file:
void EncryptFileDemo( CFile* fin, CFile* fout, const char* sPassPhrase )
{
MfcCFileSource( fin, true,
new Gzip(
new DefaultEncryptorWithMAC( sPassPhrase,
new MfcCFileSink( fout )
)
)
);
}
In the example, we pass the input file bytes through a compression filter and an encryption (with password) filter all the way out to the output file.
Filter
is a Crypto++ data manipulation mechanism.- Explaining filters is beyond the scope of this article.
The client code may look like this:
EncryptFileDemo(
new CFile(File, CFile::modeRead),
new CFile(sOutFile, CFile::modeWrite | CFile::modeCreate),
"Geronimo"
);
That's It
Hope you'll find this helpful.
Comments / suggestions are most welcome.
History
- 3rd March, 2009
- 7th March, 2009
- Added Crypto++ Background and Code Integration info (thanks to Hans Dietrich)
- Fixed a minor compatibility issue with VC7 version and above