Much of the code in the Decrypt demo is identical to the code in the Encrypt demo. The #define and #include statements are the same as for Encrypt; however, we need only a single buffer size for decrypting. The size of the buffer needs to be a multiple of the encryption block size. Since both RC2 and RC4 encryption (the two block encryption algorithms supplied by the Microsoft base CSP), use 40-bit and 64-bit block sizes, respectively, the Decrypt demo uses a buffer size that is an even multiple of both. This way, you can change the encryption type in both programs without needing to worry about changing the buffer size.
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
// note: the IN_BUFFER_SIZE used here is purposely an even multiple of the
// various possible encryption block sizes, namely 1, 8, and 64 bytes.
const BUFFER_SIZE = 64 * 100; // needs to be multiple of block size.
NOTE
The Decrypt demo is included on the CD that accompanies this book, in the Chapter 20 folder. As noted earlier, the software that does the actual work is not in this demo’s code; it is installed as part of the crypto API.
The variables are also almost identical to those in the Encrypt demo, except that the buffer being allocated is a different size.
int __cdecl main(int argc, char * argv[])
{
HANDLE hInFile, hOutFile;
BYTE pbBuffer[BUFFER_SIZE];
BOOL finished;
HCRYPTPROV hProvider = 0;
HCRYPTKEY hKey = 0;
DWORD dwByteCount, dwBytesWritten;
if (argc != 3)
{
printf(“Usage: DECRYPT infile outfile\n”);
exit(0);
}
As in the Encrypt demo, we first need to get a handle to the default CSP.
// Get handle for the default provider (use RSA encryption).
CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, 0);
// Open infile and create outfile.
hInFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
hOutFile = CreateFile(argv[2], GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
We now read in, in the same order as they were written, the key blob size and then the key blob itself.
// Read in key blob size, then key blob itself from input file.
ReadFile(hInFile,&dwByteCount,sizeof(dwByteCount),
&dwBytesWritten,NULL);
ReadFile(hInFile, pbBuffer, dwByteCount, &dwBytesWritten, NULL);
Now, we convert the key blob back into a key (internally to the CSP), with the call to CryptImportKey.
// Import Key blob into “CSP”
CryptImportKey(hProvider, pbBuffer, dwByteCount, 0, 0, &hKey);
Next, we read encrypted data in, decrypt it using CryptDecrypt, and write the decrypted data to our output file. Like the CryptEncrypt function, CryptDecrypt takes a “finished” Boolean flag to tell it when we’re sending it the last buffer to decrypt.
// Read data in, encrypt it, and write encrypted data to output file.
do
{
ReadFile(hInFile, pbBuffer, IN_BUFFER_SIZE, &dwByteCount,NULL);
finished = (dwByteCount < IN_BUFFER_SIZE);
CryptDecrypt(hKey, 0, finished, 0, pbBuffer, &dwByteCount);
WriteFile(hOutFile, pbBuffer,dwByteCount,&dwBytesWritten,NULL);
} while (!finished);
We’re finished, so we now delete our key, release the CSP handle, and close the input and output files.
// Clean up: release handles, close files.
CryptDestroyKey(hKey);
CryptReleaseContext(hProvider, 0);
CloseHandle(hInFile);
CloseHandle(hOutFile);
return(0);
}