Introduction

This article shows how to use Microsoft Cryptography to create a simple MFC class that will encrypt and decrypt data.

Microsoft's Cryptography API is very powerful, but a little cumbersome to use. If you need to quickly add security to your software with password-based encryption, then this little class will let you encrypt and decrypt many different kinds of data very quickly.

Using the code

Before I go into how the code works, here is a brief example of how you might use it. First of all, make sure you include Crypto.cpp and Crypto.h in your project. If you are going to be using the Cryptography code in many modules, include it in stdafx.h. Otherwise, just include it in the modules you will be using it in. To do any cryptography, one must first create the object and then derive a key from it. At the moment, the only way to derive a key is from a password.

// Create the Crypto object, this initializes all of
// the underlying handles etc.
CCrypto crypto;
// Ask the user for a password.
if(somePasswordDialog.DoModal() == IDOK)
{
// Set the password for the crypto object.
cryto.DeriveKey(somePasswordDialog.m_strPassword);
// Now the crypto object is ready to use
// ... some code using encryption and decryption ...
}

So, setting the Crypto object up for use is very easy. If you want to know how to make sure the user has specified the correct password, look further down the article. There's a point about it there.

When encrypting data with this object, one always passes over a reference to CByteArray. This is where the encrypted bytes will be stored. This may seem a little bit clunky, but in the end it turns out to be the quickest and easiest way. We cannot store, say, the result of an encrypted string in another string because the encrypted data can contain zeros. The resulting string would be malformed.

Still, why a byte array? The reason is that this class doesn't want to know where you want to store the data. It might be a file; it might be the clipboard; it might be the registry. All it knows is that you are going to want to store the encrypted data somewhere afterwards, so a byte array is the most convenient way to pass it around.

Similarly, you will at some stage load encrypted data from a file, the registry, the clipboard, a socket or anything really. The decrypt function will take that data in the form of a byte array. Overall, this is much better than writing a class that can encrypt directly to a file, a socket or whatever. All this class does is encrypt or decrypt data to and from byte arrays. It leaves storage up to you.

So, how to go about encrypting data then? Here's an example.

// I assume that you have a crypto object here, that has been
// constructed and has a key derived for it!
CCrypto crypto;
// Create a byte array, we will use this later on to store data.
CByteArray arBytes;
// To start off with, lets encrypt a string.
CString str = _T("What the hell am I supposed to write here?");
if(crypto.Encrypt(str, arBytes) == true)
{
// Store the byte array in a file, the registry, whatever.
}
// Now I want to encrypt my applications document object.
CDocument* pDoc = GetDocument();
if(crypto.Encrypt(*pDoc, arBytes) == true)
{
// Store the byte array in a file, the registry, whatever.
}
// Finally, I want to encrypt an array of strings.
CStringArray arStrings;
arStrings.Add(_T("String One"));
arStrings.Add(_T("String Two"));
arStrings.Add(_T("String Three"));
if(crypto.Encrypt(arStrings, arBytes) == true)
{
// Store the byte array in a file, the registry, whatever.
}

It couldn't be easier. If you're really miffed and want to encrypt the data and dump it into a file, it only takes a couple of lines to open a CFile object and call Write on the contents of the byte array. What about decrypting? Have a look at the code below.

Hoody dizzle. Nice and easy. The only work you have to do is fill the arBytes variable with the encrypted data that you have retrieved from a file or whatever. These two code examples show all of the functions in the crypto object.

What can I encrypt?

I could've gone overboard here and provided functions for encrypting ints, doubles, std::strings, CFile objects and so on. However, I have deliberately limited what you can encrypt and decrypt to two types of object that cover everything we need.

CStrings - Such a common object, if you want to encrypt a string of any kind convert it to a CString. I prefer std::string, but this is an MFC class and CStrings compile happily in Unicode environments too.

In MFC if you want something to be able to be serialized to a set of bytes, you make it serializable. Anything that you can serialize to a stream of bytes you can encrypt and decrypt. This is very useful, as you can directly encrypt application document objects, arrays, lists and anything that was designed to be serialized! Everyone knows how to make an MFC class serializable; it's very easy to do. So, if you have a complex data type that you need to encrypt, make it a CObject, using DECLARE_SERIAL and IMPLEMENT_SERIAL. Then write the serialize function and you're done. You can encrypt and decrypt to your heart's content.

What about unsigned char[]?

If you want to encrypt the contents of a buffer of bytes or something, copy the buffer into CByteArray. This is serializable and therefore you can encrypt it. I don't want to have to write a function that takes a pointer to some random area of memory and assumes that the correct length has been passed. If you're working with areas of raw memory, use CByteArray. It'll make your code safer, more readable and more efficient.

Great. Cheers. What about Win32?

I would've loved to write this class so that it can only encrypt an std::string or std::vector<unsigned char>, but hitching a ride on the MFC serialization mechanism just gives me such a large amount of functionality for free. With a couple of pages of code, I can encrypt and decrypt anything I can be bothered to write a serialize function for. It's so quick and easy that I couldn't resist. Sorry, Win32. Sorry, STL.

What does it all mean, Basil? How does it wooooork?

Have a quick gander at the code. It's only two files and only two important functions. OK, here's the gist (actually it's not the gist, it's the whole lot).

Construction - Initialise all of the crypto handles and all that stuff. If this fails, your object is useless. I normally hate putting initialisation of this kind in a constructor, but what the hell. If the initialisation of the Crypto API can't complete, your software is screwed anyway. Reinstall the Platform SDK.

Destruction - Uuuuuh, free everything above.

Encryption - OK, this is more interesting. For a serializable: create a CArchive from a CMemFile that the crypto object owns and uses as a buffer for its operations. Use Serialize to serialize the serializable (whew) to the archive. Call InternalEncrypt to call the API function that encrypts the contents of the memory file to the byte array. For a string: create a CArchive from a CMemFile that the crypto object owns and uses as a buffer for its operations. Use CArchive::operator << to serialize the string. Call InternalEncrypt to call the API function that encrypts the contents of the memory file to the byte array.

Decryption - Very similar to the above. For a serializable: use InternalDecrypt to decrypt the byte array to the memory file. Create a CArchive from the memory file. Call Serialize on the object, passing the archive. All done. Easy. For a string: use InternalDecrypt to decrypt the byte array to the memory file. Create a CArchive from the memory file. Call CArchive::operator << on the string. All done. Easy.

So, it's all very simple stuff. I use a CMemFile as a scratchpad for all encryption and decyption operations because then I can attach an archive to it nice and easily. Also, there may come a day when I want to encrypt 12 Gb of data, in which case I'll use a disk file instead.

What the code won't do

I have made this class as simple as possible and because of that there are some things it won't do, although I am planning to add certain features. This class will not:

Directly serialize STL types or built-in types. Sorry, you've got to make them into a byte array or a serializable object. There's a mechanism for turning objects into arrays of bytes, serialization, so use that.

Directly serialize to file. Sure, you can encrypt or decrypt a file with one call, but if you are encrypting or decrypting data in memory, it's up to you to open a file or save it.

Be polite if construction fails. If the Crypto API throws errors at me, Encrypt and Decrypt will return false. That's as good as the error reporting gets so far.

Handle non-password encryption mechanisms. This is just a case of providing another function along the lines of DeriveKey that takes a key file or whatever, but at the moment I'm only supporting password protection. It's very easy to add more functionality and it won't change how the internals of the code work.

Points of interest

Have a look at InternalEncrypt or InternalDecrypt. In the space of about fifteen lines, MFC has specified buffer lengths using:

int

UINT

DWORD

INT_PTR

DWORD_PTR

ULONGLONG

What a joke! STL had it right when they decided to be consistent and use size_t everywhere. In all my non-MFC code, I use size_t everywhere I specify a length, size, array index, etc. There are lots of static_casts in the code because MFC uses sizes inconsistently.

What's the right password?

If Decrypt is returning false, you're probably using the wrong password. If you want to be able to check, do this:

When the user specifies a password for the first time, encrypt the value of the password using the key generated by the password, i.e. call DeriveKey and then Encrypt. Save the encrypted password in the registry/data file/whatever.

The next time the user specifies a password, try and decrypt their original password. If decrypt works AND the decrypted password matches what the user gave you, then they have specified the correct password.

As far as I know, this is safer than encrypting some constant string with the password and checking that decrypting it gives the same string. This is because if someone finds out the string you are using as a check, then they can write a program that generates passwords, checks to see if the generated password decrypts the check string correctly, and then hack your application if it works. So encrypt the password itself.

Updates and more info

If I update the code, I'll update it on my site at the same time I update it here, so check there for updates. If you have comments or suggestions, feel free to email me.

Free stuff

My site contains free software you might like. If you like it or this code, buy me a beer, as I'm destitute. Really, really horribly poor.

First of all, when it is converted by VS 2010, the Load, Save, and data window are all disabled. How is that ?

If I enter a password, then enter some text in the data window, then click on Save, I invariable get the message : 'Couldn't encrypt data'.

Finally, the project is advertised as How to Encrypt a File, but I don't understand, even if this worked, how one would encrypt a file. Do you suggest that the entire file needs to be loaded into memory as a byte array then encrypted, then saved as a dat file? What am I missing here?

Hi,
when i do encrypt, i meet some problem, can you tell me how to solve this problem, thank you!

First: I write a encrypt funtion using C++, and after encrypt successfully, then I want to save a key to the key store, in C++, I did not find such of function. But under .NET, there is a class named CspParameters, it can save a key to a container, all the code I see is below:

Lot's of things are required to run it properly, C runtime library, C++ runtime library, MFC, crypto API etc etc. However, these are all standard dlls that should be on windows. Here's a few things to try:

1. Release, not Debug - Make sure you're distributing release versions of your code - debug versions require the debug libraries that are not present on most computers. If the computer has VC6 it has VC6's debug versions of the c runtime, the c++ runtime, mfc etc etc, so this is your most likely problem.

2. Deployment - Create a setup/deployment project and use this to install your code. The setup project will automatically detect the softwares dependencies for you - so you can distribute debug or release, the installer will simply package the necessary dlls.

3. Dependency Checker - One of the tools that comes with the win32 sdk, this'll tell you what your code depends on, use this as a last resort to find what libraries your code needs that seem to be missing from standard distributions and let me know, then I can help you further.

I think though this may be a debug libraries issue - check for dependencies on debug code, or if this is possible for you and your project use an installer to handle all of the dependencies for you!

//Hash the password. This will have a different result in UNICODE mode, as it will hash the UNICODE string (this is by design, allowing for UNICODE passwords, but it's important to be aware of this behaviour.

I am new to Cryptography. I found this code very simple.
My application is based on Client Server architecture.
So when I encrypt data in Client to send to Server, the server is producing different Hash no. and Key with same password.
So server is not able to decrypt the msg from Client.
Please suggest any logic so as to encrypt and decrypt in two different applications.