Click here to Skip to main content
Click here to Skip to main content
Go to top

Writing a C++ Program with the CAPICOM Component to Encrypt and Decrypt Files

, 1 May 2009
Rate this:
Please Sign up or sign in to vote.
How to use the CAPICOM component in C++ to encrypt and decrypt files.

Introduction

The purpose of this article to try to help the beginner to learn how to encrypt and decrypt files using a symmetric key algorithm (e.g., RC2, RC4, DES, Triple-DES, and AES) by building an application with Visual C++ that uses the CAPICOM component. The Platform SDK redistributable ships a COM component called CAPICOM. CAPI stands for Crypto API. When we download this component, Capicom.dll, we must install it on our machine. Because it installs by default in the Program Files directory, we must traverse the CAPICOM folder on the command line until we find the Capicom.dll in the directory listing. At that point, we use the 'regsvr32 Capicom.dll' command to get a "succeeded" box. To build this application, simply use Visual C++ Express 2005 or 2008, or use Visual Studio. Remember to choose the Win32 Console application icon when starting the process and to choose "empty project" in the application settings box. Copy and paste this code, build the solution, and deploy the executable.

The source code file uses four headers that predefine methods that deal with strings, and files that deal with strings. The <fstream> template is for file I/O. And because we are not using the Crypto API but the CAPICOM component, we must initialize the COM library, and at some point, uninitialize it. Import Capicom.dll. I used quotation marks after the import statement in my source code file after I copied and pasted the DLL into the same directory as the source. It can help to avoid file path errors when building the solution. Here is the source code, which will be explained:

#include <windows.h>
#include <fstream>
#include <string>
#include <iostream>
#import "capicom.dll"
using namespace std;
using namespace CAPICOM;

const char szErrParms[] = "Enter Capi [E|D] [file name] [secret key]";
const char szErrNoFile[] = "File not found";
const char szErrWrite[] = "Error writing to output file";

void Encrypt(char *pszFile, char *pszKey);
void Decrypt(char *pszFile, char *pszKey);
int main(int argc, char **argv)
{
    char c;
    CoInitialize(0);
    if ( argc != 4 )
        cout << szErrParms << endl;
    else
    {
        c = argv[1][0];
        if ( (c == 'E') || (c == 'e') )
            Encrypt(argv[2], argv[3]);
        else if ( (c == 'D') || (c == 'd') )
            Decrypt(argv[2], argv[3]);
        else
            cout << szErrParms << std::endl;
    }
    CoUninitialize();
    return 0;
}
void Encrypt(char *pszFile, char *pszSecret)
{
    int               size;
    char              *buf;
    _bstr_t           cipherText;
    string            name;
    ifstream          in(pszFile, ios::in | ios::binary | ios::ate);
    ofstream          out;
    IAlgorithmPtr     algo;
    IEncryptedDataPtr encryptor;

    if ( !in.is_open() )
        cout << szErrNoFile << std::endl;
    else
    {
        size = in.tellg();
        buf = new char[size + 1];
        buf[size] = 0;

        in.seekg(0, ios::beg);
        in.read(buf, size);
        in.close();
  
        encryptor.CreateInstance("CAPICOM.EncryptedData");
        encryptor->PutContent(_bstr_t(buf) );

        algo = encryptor->GetAlgorithm();
        algo->PutName(CAPICOM_ENCRYPTION_ALGORITHM_AES);
        algo->PutKeyLength(CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM);

        encryptor->SetSecret(_bstr_t(pszSecret), CAPICOM_SECRET_PASSWORD);

        cipherText = encryptor->Encrypt(CAPICOM_ENCODE_BASE64);

        name = pszFile;
        name.append(".encrypted");
        out.open(name.c_str(), ios::out | ios::binary);

        if ( !out.is_open() )
            cout << szErrWrite << endl;
        else
        {
            out << cipherText;
            out.close();
        }
    }
}

void Decrypt(char *pszFile, char *pszSecret)
{
    int               size;
    char              *buf;
    _bstr_t           plainText;
    string            name;
    ifstream          in(pszFile, ios::in | ios::binary | ios::ate);
    ofstream          out;
    IEncryptedDataPtr encryptor;

    if ( !in.is_open() )
        cout << szErrNoFile << std::endl;

    else
    {
        size = in.tellg();

        buf = new char[size + 1];
        buf[size] = 0;

        in.seekg(0, ios::beg);
        in.read(buf, size);
        in.close();

        encryptor.CreateInstance("CAPICOM.EncryptedData");

        encryptor->SetSecret(_bstr_t(pszSecret), CAPICOM_SECRET_PASSWORD);

        encryptor->Decrypt(_bstr_t(buf));
        plainText = encryptor->GetContent();

        name = pszFile;
        name.append(".decrypted");
        out.open(name.c_str(), ios::out | ios::binary);

        if ( !out.is_open() )
            cout << szErrWrite << endl;
        else
        {
            out << plainText;
            out.close();
        }
    }
}

The line in the source code (ifstream in(pszFile, ios::in | ios::binary | ios::ate); means that we open the file in binary mode. Problems would result if we were to use any mapping of carriage returns and line feeds, because the data is in binary and we don't know what it means. So once a file is in binary data, it cannot be mapped by CR-LF to anything else. For the beginner, CR-LF means hit the ENTER key to have the cursor drop down one line and move to the far left. We see that in this operation, a COM object wraps an encrypted data block. But we must first check and see if the file will open. If it won't, we have to output an error message to the console. We also need to know the size of the file: the option ios::ate makes the open operation point the file pointer to the end of the file. When we are at the end of the file, we can determine the file size:

now that (else
{
    size = in.tellg();

    buf = new char[size + 1];
    buf[size] = 0;

If I'm at the end of the file, and I know the file size, then I can allocate a buffer. Notice these parts of the code: in.seekg(0, ios::beg); -- in.read(buf, size); in other words, go to the beginning of the file and read it into a buffer. When the file is read into the buffer, we can create an instance of the object to encrypt it:

encryptor.CreateInstance("CAPICOM.EncryptedData");

Because this is a COM API, we will take our buffer and wrap it up into a bstr_t. Note the line of code:

encryptor->PutContent(_bstr_t(buf) ); 

This line asks the encrypted data object for a pointer to the algorithm:

algo = encryptor->GetAlgorithm();

Now that we have a pointer to the encryption algorithm, we tell the algorithm that we are going to use the symmetrical AES algorithm and that we will use the maximum key length. After that, we tell the encryptor what password we will use to encrypt the data with. Subsequent to the choice of cipher block, key length, and password, we then wrap what we got off the command line into a bstr_t object:

encryptor->SetSecret(_bstr_t(pszSecret), CAPICOM_SECRET_PASSWORD);

It is good practice to encode the encrypted data with base64 encoding. Now examine an example of the use of the CAPI.exe on the command line:

1.JPG

Here is a partial view of the encrypted text:

MIILzAYJKwYBBAGCN1gDoIILvTCCC7kGCisGAQQBgjdYAwGgggupMIILpQIDAgAB
AgJmEAICAQAEEAAAAAAAAAAAAAAAAAAAAAAEEOp4prYlThFUgqN6JmefuyQEggtw
mace/peBQ6aiRk3mTiwQRO85rEazI7GVyd/kojaNKfgfjJixLPgzusTuQqs9xJmiu
so6apAeFDvSMhu5XRAM44DjM/dfRohEBhoqjmRuio7Wh/tJzMoF6Ks/kVTBPrJ7R
2g0S3C3OHbN3fBxWi73QQL6P4H34AqIinfAXj1PSTKONSWYNF7IOtYU3xPazcc6+
8DBztOgisWKlMFw8e6KMPRRKuRZy2VzFGBhpihUDVlhqpoelUcd4m56pZsCmTkrc
f5MBxRe25nPhGEyxWOaM6l0+51GKeFUDPjnwUiY7aAkF/nSxvyTJK2I9A9ANYZtN
UY+CGA6DlvIuvC72n+1x7fSd3D8Nle9dq1QE72n2EaE9uvUFxcP/+GZZYX54EWP6
 hK8AICMPHC5emTNnuGV8vvOazpLKpPnaO1p3YRT7f4H5BDtAlIjNMu43QXZMThj9
+BOc2FHmaTr8XIAIlrH9A1Kmeqej1LbYoHSFMrFOSxJ3JuOZQZJju6X0jxYPtwLt
CQQSQiHKZQXzEoy7fUU4OZc5rlOoIRw3BIxulAMBZfVmQlvx5mWYFgcdN6DVZ8PG
Gnk+E2zBVyB4vOWxLuu2sPb2DYVr5Xmcd4rVkB0c3EggnZQ3DLc1DSl7736IspM2
OxzdGfaJ5IB2B4HNw1rV5vsUFI26z9JB5nc88mIyuibHio9IWn7ee8xgRme77kN5
UgLgNUcsf8Sgh2Q1RJcjioXaQrzQso54GxpkpF0tjl6rx1fHRGagLdPFEuXfs9T
    and so on 

Here is a partial view of the file, MyFile.txt.encrypted.decrypted:

Excel Services are an invaluable service defined in the Microsoft Business Intelligence Strategy. Management can formulate a plan that involves delivering key information in real time to the right audience. This would obviously involve updating some data and refreshing calculated data. Email is a convenient form of electronic communication, but could prevent synchronous and timely information reception. Excel Services involve aggregating and displaying business-scope information about the business pipeline. When the numbers are displayed in a timely and synchronous manner to all involved in a venture, then those who make decisions can tell what parts of any business plan either is failing or succeeding. It is entirely possible to upload an Excel workbook to a Microsoft SharePoint services document library to make it available to others. Excel is probably the strongest business product on the market because it gives users the flexibility to create a data repository quickly to implement data processing, charting, graphing, and analysis without having to build a full-blown database application. Excel services enables one to consolidate Excel workbooks into document libraries. If you are a SharePoint server user, then you would know that by integrating your workbooks into your information management by consolidating them into a document library, you can publish the spreadsheets, charts, and graphs on your SharePoint sites.

Build Capi.exe and try on the text above to see if you get the same encrypted text.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

logicchild
Other Pref. Trust
United States United States
I started electronics training at age 33. I began studying microprocessor technology in an RF communications oriented program. I am 43 years old now. I have studied C code, opcode (mainly x86 and AT+T) for around 3 years in order to learn how to recognize viral code and the use of procedural languages. I am currently learning C# and the other virtual runtime system languages. I guess I started with the egg rather than the chicken. My past work would indicate that my primary strength is in applied mathematics.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web01 | 2.8.140922.1 | Last Updated 1 May 2009
Article Copyright 2009 by logicchild
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid