This example will utilize the cryptography API on my previous post. If you are new to Microsoft cryptography API, you may refer to the following post, C++ Encryption and Decryption using Microsoft CryptoAPI, for more information on how to use the cryptography API. The objective of this example is to encrypt a string from edit control and store it in a text file. The encrypted string in the text file can be decrypted and display on a edit control as well. I will demonstrate this example with a MFC dialog based application. Let’s start with a new MFC dialog based application project – MfcCrypt. We will need to create a new class for this example. I named the new class — CAskybCrypt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//AskybCrypt.h

#pragma once
#include <wincrypt.h>

class CAskybCrypt
{
public:
  CAskybCrypt(void);
  ~CAskybCrypt(void);
  HCRYPTPROV GetCryptContainer(LPCSTR keyContainer);
  HCRYPTHASH CreateHashObj(HCRYPTPROV hCryptProv, const char * szPassword);
  HCRYPTKEY GetDeriveKey(HCRYPTPROV hCryptProv, HCRYPTHASH hHash);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//AskybCrypt.cpp
#include "StdAfx.h"
#include "AskybCrypt.h"

#define ENCRYPT_ALGORITHM CALG_RC4
#define KEYLENGTH  0x00800000

CAskybCrypt::CAskybCrypt(void)
{
}

CAskybCrypt::~CAskybCrypt(void)
{
}

/*
Acquire key container handle
*/

HCRYPTPROV CAskybCrypt::GetCryptContainer(LPCSTR keyContainer)
{
  HCRYPTPROV hCryptProv = NULL;

  if(CryptAcquireContext(
      &hCryptProv,
      keyContainer,
      NULL,
      PROV_RSA_FULL,
      0))
  {
     printf("A cryptographic provider has been acquired.\n");
  }
  else
  {
    if (GetLastError() == NTE_BAD_KEYSET)
    {
       if(CryptAcquireContext(
        &hCryptProv,
        keyContainer,
        NULL,
        PROV_RSA_FULL,
        CRYPT_NEWKEYSET))
      {
        printf("A new key container has been created.\n");
      }
      else
      {
        printf("Could not create a new key container.\n");
      }
    }
    else
    {
      printf("A cryptographic service handle could not be acquired.\n");
    }
  }

  return hCryptProv;
}

HCRYPTHASH CAskybCrypt::CreateHashObj(HCRYPTPROV hCryptProv, const char * szPassword)
{
  HCRYPTHASH hHash = NULL;

  if(CryptCreateHash(
       hCryptProv,
       CALG_MD5,
       0,
       0,
       &hHash))
    {
        printf("A hash object has been created. \n");

    //  hash the password
    if(CryptHashData(
      hHash,
      (BYTE *)szPassword,
      strlen(szPassword),
      0))
     {
      printf("The password has been added to the hash. \n");

     }
     else
     {
       // reset hash object to NULL
      CryptDestroyHash(hHash);
      hHash = NULL;  
     }
    }
    else
    {
         printf("Failed to create hash object.\n");
    }

  return hHash;
}

// Derive a session key from the hash object.
HCRYPTKEY CAskybCrypt::GetDeriveKey(HCRYPTPROV hCryptProv, HCRYPTHASH hHash)
{
  HCRYPTKEY hKey = NULL;

  if(CryptDeriveKey(
       hCryptProv,
       ENCRYPT_ALGORITHM,
       hHash,
       KEYLENGTH,
       &hKey))
   {
     printf("An encryption key is derived from the password hash. \n");
   }
   else
   {
     //MyHandleError("Error during CryptDeriveKey!\n");
   }
  return hKey;
}
We are almost done with this example now. We need to include the new class that we’ve created to our dialog based project.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// MfcCryptDlg.h
#include "AskybCrypt.h"
..
..
class CMfcCryptDlg : public CDialog
{
..
..
protected:
  HICON m_hIcon;
  CAskybCrypt m_askybCrypt;
  HCRYPTPROV hCryptProv;
  HCRYPTHASH hHash;
  LPCSTR keyContainer;
  char szPassword[10];
  HCRYPTKEY hKey;
  DWORD dwCount;

  bool StartCryptAPI();
  void ReleaseCryptAPI();
  void WriteDataToFile(PBYTE buf, DWORD dwCount);
  DWORD ReadDataFromFile(PBYTE buf, DWORD dwBlockLen);
..
..
};
The following functions will initialize & uninitialize the cryptoAPI class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// MfcCryptDlg.cpp
..
#define ENCRYPT_BLOCK_SIZE 16 // We are using 16 block size in this MFC example
..
void CMfcCryptDlg::ReleaseCryptAPI()
{
  // Remove all references
  if(hKey)
    CryptDestroyKey(hKey);
  if(hHash)
     CryptDestroyHash(hHash);
  if(hCryptProv)
     CryptReleaseContext(hCryptProv,0);
}

bool CMfcCryptDlg::StartCryptAPI()
{
  hCryptProv = NULL;
  hHash   = NULL;
  keyContainer    = "MyKeyContainer";
  strcpy(szPassword, "12345");

  // get CSP
  hCryptProv = m_askybCrypt.GetCryptContainer(keyContainer);

  if(!hCryptProv)
  {
    AfxMessageBox("CryptoAPI Failed!");
    return false;
  }

  // get the hash object
  hHash = m_askybCrypt.CreateHashObj(hCryptProv, szPassword);

  if(!hHash)
  {
    AfxMessageBox("CryptoAPI Failed!");
    return false;
  }

  // get the session key
  hKey = m_askybCrypt.GetDeriveKey(hCryptProv, hHash);

  if(!hKey)
  {
    AfxMessageBox("CryptoAPI Failed!");
    return false;
  }

  return true;
}
The following function will trigger when the user click the encrypt & Save button. It will encrypt the string in the edit control and store the encrypted data into a text file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// MfcCryptDlg.cpp
void CMfcCryptDlg::OnBnClickedEncrypt()
{
  CString str = "";
  GetDlgItemText(IDC_EDIT_NAME, str);

  if(str.CompareNoCase("") != 0)
  {
    if(StartCryptAPI())
    {
      // determine input data length
      int len = str.GetLength();
      dwCount = str.GetLength();

      DWORD cbData = (DWORD)len;

      // Determine the block size. If a block cipher is used,
      // it must have room for an extra block.
      DWORD dwBufferLen;
      DWORD dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
      if(ENCRYPT_BLOCK_SIZE > 1)
        dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
      else
        dwBufferLen = dwBlockLen;

      PBYTE pbBuffer;
      if(pbBuffer = (BYTE *)malloc(dwBufferLen))
      {
        memcpy(pbBuffer, str, dwBlockLen);

        if(CryptEncrypt(
           hKey,
           0,
           TRUE,
           0,
           pbBuffer,
           &dwCount,
           dwBufferLen))
        {
          // write to file
          WriteDataToFile(pbBuffer, dwCount);
        }

        free(pbBuffer);
      }
     
      ReleaseCryptAPI();
    }
  }
}

void CMfcCryptDlg::WriteDataToFile(PBYTE buf, DWORD dwCount)
{
  FILE *fp = NULL;
  if(fp = fopen("data.txt","wb"))
  {
    fwrite(buf, 1, dwCount, fp);

    if(fclose(fp))
    {
      //error
    }
  }
}
Finally, the decrypt button will read the text file and decrypt the data.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// MfcCryptDlg.cpp
void CMfcCryptDlg::OnBnClickedDecrypt()
{
  if(StartCryptAPI())
  {

    DWORD dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
    DWORD dwBufferLen = dwBlockLen;

    PBYTE pbBuffer;

    if(pbBuffer = (BYTE *)malloc(dwBufferLen))
    {
      memset(pbBuffer, NULL, dwBufferLen);

      DWORD dwCount = ReadDataFromFile(pbBuffer, dwBlockLen);

      if(CryptDecrypt(
          hKey,
          0,
          TRUE,
          0,
          pbBuffer,
          &dwCount))
      {
        CString s(pbBuffer);
        SetDlgItemText(IDC_EDIT_DECRYPT, s);
      }
    }
  }

  ReleaseCryptAPI();
}

DWORD CMfcCryptDlg::ReadDataFromFile(PBYTE buf, DWORD dwBlockLen)
{
  FILE *fp = NULL;
  DWORD dwCount = 0;

  if(fp = fopen("data.txt","rb"))
  {
    PBYTE pbBuffer;
    if(pbBuffer = (BYTE *)malloc(dwBlockLen))
    {
      memset(pbBuffer, NULL, sizeof(pbBuffer));
      dwCount = fread(pbBuffer, 1, dwBlockLen, fp);

      memcpy(buf, pbBuffer, dwCount);

    }

    if(fclose(fp))
    {
      //error
    }
  }

  return dwCount;
}
Screenshot: Storing encrypted data into text file Download sample source code: MfcCrypt.zip