Tuesday, June 14, 2011

How to use CryptoAPI the easy way

Introduction
The Cryptography API ,also called CryptoAPI, makes it really easy to cipher and decipher files. Unfortunately, the examples found on the internet or in MSDN are often quite complex or not working properly. This program will try to show the use of CryptoAPI on the simplest example, namely on a small plain text saved in ASCII format. The cipher used is of symmetrical bloc type, called triple DES 112, with maximum 128bits key length.

The cipher is symmetrical as it needs the same key for encryption and decryption, and is a bloc cipher based on 64 bit blocs of information. It means that only multiples of 8 bytes data can be encoded, but in reality, we do not really care as CryptoAPI will make the padding automatically for us when the data is less than 8 bytes long.

Normally, in industrial code, an Initialization Vector is randomly generated at runtime, and is added at the beginning of the plain text to make cryptanalysis harder. Indeed a weakness of the cipher used in this program is that the same plain text always results in the same encrypted text. But for the purpose of this example, we will not introduce any Initialization Vector.
For the purpose of simplicity, we also ignore the use of passwords or salts to hash keys.
Originally, the code was compiled on x64 but should work well on x86 without the slightest modification. It still has to be confirmed.


Using the code
Two modules are included in the project, namely CryptoAPI to cipher plain text, and DecryptoAPI to decipher it. Both modules do not include any GUI, they simply ask the user through common dialogs to specify an input and an output file.
Once the plain text is encoded, we do not simply put it in the output file; first, it will be converted to hex values as they are easy to handle. For example, imagine the exchange of information between two people. The encrypted text could also be afterwards encoded in Base64, but it is out of scope here.
To compile with VS:

nmake /f "CryptoAPI.mak"


The code
After having requested from the user to select an input and an output file, we read the input and make our first call to CryptoAPI in order to talk with the Crypto Service Provider. Before obtaining the handle to the CSP, we first deallocate it! It might seem weird to start this way, but it proves actually useful when the program crashes and doed not deallocate memory correctly! This way at least we make sure we do a proper start by getting a handle to the CSP on the first try.

CryptAcquireContext(&hCryptProv, "CryptoAPI", NULL, PROV_DH_SCHANNEL, CRYPT_DELETEKEYSET);
if(hCryptProv)CryptReleaseContext(hCryptProv, 0);
Once this is done, we again call the same function, but this time with the option CRYPT_NEWKEYSET.
if(!CryptAcquireContext(&hCryptProv, "CryptoAPI", NULL, PROV_DH_SCHANNEL, CRYPT_NEWKEYSET))

Then we import the key from the BLOB array (refer to the source) and we make our first call to the CryptEncrypt function. By passing the fifth parameter as NULL, we are able to get the buffer size for encryption. Remember, we must supply to the CSP a multiple of the bloc length for the encryption to work properly! So we retrieve the correct length of our buffer and that's it!

Read more: Codeproject