How to generate key pairs, encrypt and decrypt data with CryptoAPI
Hi, welcome back,
Today I'm posting a sample I did some time ago which shows how to generate key pairs, encrypt and decrypt data with C++ and CryptoAPI. The comments in the code should be self-explanatory.
<SAMPLE>
// INCLUDES
#include "stdio.h"
#include "conio.h"
#include "windows.h"
#include "wincrypt.h"
#include "tchar.h"
// FUNCTIONS
int Keys(_TCHAR* strPublicKeyFile, _TCHAR* strPrivateKeyFile);
int Encrypt(_TCHAR* strPublicKeyFile, _TCHAR* strPlainFile, _TCHAR* strEncryptedFile);
int Decrypt(_TCHAR* strPrivateKeyFile, _TCHAR* strEncryptedFile, _TCHAR* strPlainFile);
// Main
int _tmain(int argc, _TCHAR* argv[])
{
int iResult = 0;
if ((argc == 4) && (_tcscmp(argv[1], _T("k")) == 0))
{
// Generate a new key pair
iResult = Keys(argv[2], argv[3]);
}
else if ((argc == 5) && (_tcscmp(argv[1], _T("e")) == 0))
{
// Encrypt
iResult = Encrypt(argv[2], argv[3], argv[4]);
}
else if ((argc == 5) && (_tcscmp(argv[1], _T("d"))== 0))
{
// Decrypt
iResult = Decrypt(argv[2], argv[3], argv[4]);
}
else
{
// Show usage
_tprintf(_T("Usage:\n"));
_tprintf(_T(" - New key pair: EncryptDecrypt k public_key_file private_key_file\n"));
_tprintf(_T(" - Encrypt: EncryptDecrypt e public_key_file plain_file encrypted_file\n"));
_tprintf(_T(" - Decrypt: EncryptDecrypt d private_key_file encrypted_file plain_file\n"));
iResult = 1;
}
_tprintf(_T("\n<< Press any key to continue >>\n"));
_getch();
return iResult;
}
// End of Main
// Keys
int Keys(_TCHAR* strPublicKeyFile, _TCHAR* strPrivateKeyFile)
{
// Variables
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
DWORD dwPublicKeyLen = 0;
DWORD dwPrivateKeyLen = 0;
BYTE* pbPublicKey = NULL;
BYTE* pbPrivateKey = NULL;
HANDLE hPublicKeyFile = NULL;
HANDLE hPrivateKeyFile = NULL;
DWORD lpNumberOfBytesWritten = 0;
__try
{
// Acquire access to key container
_tprintf(_T("CryptAcquireContext...\n"));
if (!CryptAcquireContext(&hCryptProv, _T("AlejaCMa.EncryptDecrypt"), NULL, PROV_RSA_FULL, 0))
{
// Error
_tprintf(_T("CryptAcquireContext error 0x%x\n"), GetLastError());
// Try to create a new key container
if (!CryptAcquireContext(&hCryptProv, _T("AlejaCMa.EncryptDecrypt"), NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
// Error
_tprintf(_T("CryptAcquireContext error 0x%x\n"), GetLastError());
return 1;
}
}
// Generate new key pair
_tprintf(_T("CryptGenKey...\n"));
if (!CryptGenKey(hCryptProv, AT_KEYEXCHANGE, CRYPT_ARCHIVABLE, &hKey))
{
// Error
_tprintf(_T("CryptGenKey error 0x%x\n"), GetLastError());
return 1;
}
// Get public key size
_tprintf(_T("CryptExportKey...\n"));
if (!CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, NULL, &dwPublicKeyLen))
{
// Error
_tprintf(_T("CryptExportKey error 0x%x\n"), GetLastError());
return 1;
}
// Create a buffer for the public key
_tprintf(_T("malloc...\n"));
if (!(pbPublicKey = (BYTE *)malloc(dwPublicKeyLen)))
{
// Error
_tprintf(_T("malloc error 0x%x\n"), GetLastError());
return 1;
}
// Get public key
_tprintf(_T("CryptExportKey...\n"));
if (!CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, pbPublicKey, &dwPublicKeyLen))
{
// Error
_tprintf(_T("CryptExportKey error 0x%x\n"), GetLastError());
return 1;
}
// Get private key size
_tprintf(_T("CryptExportKey...\n"));
if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwPrivateKeyLen))
{
// Error
_tprintf(_T("CryptExportKey error 0x%x\n"), GetLastError());
return 1;
}
// Create a buffer for the private key
_tprintf(_T("malloc...\n"));
if (!(pbPrivateKey = (BYTE *)malloc(dwPrivateKeyLen)))
{
// Error
_tprintf(_T("malloc error 0x%x\n"), GetLastError());
return 1;
}
// Get private key
_tprintf(_T("CryptExportKey...\n"));
if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pbPrivateKey, &dwPrivateKeyLen))
{
// Error
_tprintf(_T("CryptExportKey error 0x%x\n"), GetLastError());
return 1;
}
// Create a file to save the public key
_tprintf(_T("CreateFile...\n"));
if ((hPublicKeyFile = CreateFile(
strPublicKeyFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
)) == INVALID_HANDLE_VALUE)
{
// Error
_tprintf(_T("CreateFile error 0x%x\n"), GetLastError());
return 1;
}
// Write the public key to the file
_tprintf(_T("WriteFile...\n"));
if (!WriteFile(
hPublicKeyFile,
(LPCVOID)pbPublicKey,
dwPublicKeyLen,
&lpNumberOfBytesWritten,
NULL
))
{
// Error
_tprintf(_T("WriteFile error 0x%x\n"), GetLastError());
return 1;
}
// Create a file to save the private key
_tprintf(_T("CreateFile...\n"));
if ((hPrivateKeyFile = CreateFile(
strPrivateKeyFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
)) == INVALID_HANDLE_VALUE)
{
// Error
_tprintf(_T("CreateFile error 0x%x\n"), GetLastError());
return 1;
}
// Write the private key to the file
_tprintf(_T("WriteFile...\n"));
if (!WriteFile(
hPrivateKeyFile,
(LPCVOID)pbPrivateKey,
dwPrivateKeyLen,
&lpNumberOfBytesWritten,
NULL
))
{
// Error
_tprintf(_T("WriteFile error 0x%x\n"), GetLastError());
return 1;
}
return 0;
}
__finally
{
// Clean up
if (!pbPublicKey) {
_tprintf(_T("free...\n"));
free(pbPublicKey);
}
if (!pbPrivateKey) {
_tprintf(_T("free...\n"));
free(pbPrivateKey);
}
if (hPublicKeyFile) {
_tprintf(_T("CloseHandle...\n"));
CloseHandle(hPublicKeyFile);
}
if (hPrivateKeyFile) {
_tprintf(_T("CloseHandle...\n"));
CloseHandle(hPrivateKeyFile);
}
if (hKey) {
_tprintf(_T("CryptDestroyKey...\n"));
CryptDestroyKey(hKey);
}
if (hCryptProv) {
_tprintf(_T("CryptReleaseContext...\n"));
CryptReleaseContext(hCryptProv, 0);
}
}
}
// End of Keys
// Encrypt
int Encrypt(_TCHAR* strPublicKeyFile, _TCHAR* strPlainFile, _TCHAR* strEncryptedFile)
{
// Variables
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
DWORD dwPublicKeyLen = 0;
DWORD dwDataLen = 0;
DWORD dwEncryptedLen = 0;
BYTE* pbPublicKey = NULL;
BYTE* pbData = NULL;
HANDLE hPublicKeyFile = NULL;
HANDLE hEncryptedFile = NULL;
HANDLE hPlainFile = NULL;
DWORD lpNumberOfBytesWritten = 0;
__try
{
// Acquire access to key container
_tprintf(_T("CryptAcquireContext...\n"));
if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
// Error
_tprintf(_T("CryptAcquireContext error 0x%x\n"), GetLastError());
return 1;
}
// Open public key file
_tprintf(_T("CreateFile...\n"));
if ((hPublicKeyFile = CreateFile(
strPublicKeyFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
)) == INVALID_HANDLE_VALUE)
{
// Error
_tprintf(_T("CreateFile error 0x%x\n"), GetLastError());
return 1;
}
// Get file size
_tprintf(_T("GetFileSize...\n"));
if ((dwPublicKeyLen = GetFileSize(hPublicKeyFile, NULL)) == INVALID_FILE_SIZE)
{
// Error
_tprintf(_T("GetFileSize error 0x%x\n"), GetLastError());
return 1;
}
// Create a buffer for the public key
_tprintf(_T("malloc...\n"));
if (!(pbPublicKey = (BYTE *)malloc(dwPublicKeyLen)))
{
// Error
_tprintf(_T("malloc error 0x%x\n"), GetLastError());
return 1;
}
// Read public key
_tprintf(_T("ReadFile...\n"));
if (!ReadFile(hPublicKeyFile, pbPublicKey, dwPublicKeyLen, &dwPublicKeyLen, NULL))
{
// Error
_tprintf(_T("ReadFile error 0x%x\n"), GetLastError());
return 1;
}
// Import public key
_tprintf(_T("CryptImportKey...\n"));
if (!CryptImportKey(hCryptProv, pbPublicKey, dwPublicKeyLen, 0, 0, &hKey))
{
// Error
_tprintf(_T("CryptImportKey error 0x%x\n"), GetLastError());
return 1;
}
// Open plain text file
_tprintf(_T("CreateFile...\n"));
if ((hPlainFile = CreateFile(
strPlainFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
)) == INVALID_HANDLE_VALUE)
{
// Error
_tprintf(_T("CreateFile error 0x%x\n"), GetLastError());
return 1;
}
// Get file size
_tprintf(_T("GetFileSize...\n"));
if ((dwDataLen = GetFileSize(hPlainFile, NULL)) == INVALID_FILE_SIZE)
{
// Error
_tprintf(_T("GetFileSize error 0x%x\n"), GetLastError());
return 1;
}
// Create a buffer for the plain text
_tprintf(_T("malloc...\n"));
if (!(pbData = (BYTE *)malloc(dwDataLen)))
{
// Error
_tprintf(_T("malloc error 0x%x\n"), GetLastError());
return 1;
}
// Read plain text
_tprintf(_T("ReadFile...\n"));
if (!ReadFile(hPlainFile, pbData, dwDataLen, &dwDataLen, NULL))
{
// Error
_tprintf(_T("ReadFile error 0x%x\n"), GetLastError());
return 1;
}
// Get lenght for encrypted data
if (!CryptEncrypt(hKey, NULL, TRUE, 0, NULL, &dwEncryptedLen, 0))
{
// Error
_tprintf(_T("CryptEncrypt error 0x%x\n"), GetLastError());
return 1;
}
// Create a buffer for encrypted data
_tprintf(_T("malloc...\n"));
if (!(pbData = (BYTE *)realloc(pbData, dwEncryptedLen)))
{
// Error
_tprintf(_T("malloc error 0x%x\n"), GetLastError());
return 1;
}
// Encrypt data
if (!CryptEncrypt(hKey, NULL, TRUE, 0, pbData, &dwDataLen, dwEncryptedLen))
{
// Error
_tprintf(_T("CryptEncrypt error 0x%x\n"), GetLastError());
return 1;
}
// Create a file to save the encrypted data
_tprintf(_T("CreateFile...\n"));
if ((hEncryptedFile = CreateFile(
strEncryptedFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
)) == INVALID_HANDLE_VALUE)
{
// Error
_tprintf(_T("CreateFile error 0x%x\n"), GetLastError());
return 1;
}
// Write the public key to the file
_tprintf(_T("WriteFile...\n"));
if (!WriteFile(
hEncryptedFile,
(LPCVOID)pbData,
dwDataLen,
&lpNumberOfBytesWritten,
NULL
))
{
// Error
_tprintf(_T("WriteFile error 0x%x\n"), GetLastError());
return 1;
}
return 0;
}
__finally
{
// Clean up
if (!pbPublicKey) {
_tprintf(_T("free...\n"));
free(pbPublicKey);
}
if (!pbData) {
_tprintf(_T("free...\n"));
free(pbData);
}
if (hPublicKeyFile) {
_tprintf(_T("CloseHandle...\n"));
CloseHandle(hPublicKeyFile);
}
if (hPlainFile) {
_tprintf(_T("CloseHandle...\n"));
CloseHandle(hPlainFile);
}
if (hEncryptedFile) {
_tprintf(_T("CloseHandle...\n"));
CloseHandle(hEncryptedFile);
}
if (hKey) {
_tprintf(_T("CryptDestroyKey...\n"));
CryptDestroyKey(hKey);
}
if (hCryptProv) {
_tprintf(_T("CryptReleaseContext...\n"));
CryptReleaseContext(hCryptProv, 0);
}
}
}
// End of Encrypt
// Decrypt
int Decrypt(_TCHAR* strPrivateKeyFile, _TCHAR* strEncryptedFile, _TCHAR* strPlainFile)
{
// Variables
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
DWORD dwPrivateKeyLen = 0;
DWORD dwDataLen = 0;
BYTE* pbPrivateKey = NULL;
BYTE* pbData = NULL;
HANDLE hPrivateKeyFile = NULL;
HANDLE hEncryptedFile = NULL;
HANDLE hPlainFile = NULL;
DWORD lpNumberOfBytesWritten = 0;
__try
{
// Acquire access to key container
_tprintf(_T("CryptAcquireContext...\n"));
if (!CryptAcquireContext(&hCryptProv, _T("AlejaCMa.EncryptDecrypt"), NULL, PROV_RSA_FULL, 0))
{
// Error
_tprintf(_T("CryptAcquireContext error 0x%x\n"), GetLastError());
// Try to create a new key container
if (!CryptAcquireContext(&hCryptProv, _T("AlejaCMa.EncryptDecrypt"), NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
// Error
_tprintf(_T("CryptAcquireContext error 0x%x\n"), GetLastError());
return 1;
}
}
// Open private key file
_tprintf(_T("CreateFile...\n"));
if ((hPrivateKeyFile = CreateFile(
strPrivateKeyFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
)) == INVALID_HANDLE_VALUE)
{
// Error
_tprintf(_T("CreateFile error 0x%x\n"), GetLastError());
return 1;
}
// Get file size
_tprintf(_T("GetFileSize...\n"));
if ((dwPrivateKeyLen = GetFileSize(hPrivateKeyFile, NULL)) == INVALID_FILE_SIZE)
{
// Error
_tprintf(_T("GetFileSize error 0x%x\n"), GetLastError());
return 1;
}
// Create a buffer for the private key
_tprintf(_T("malloc...\n"));
if (!(pbPrivateKey = (BYTE *)malloc(dwPrivateKeyLen)))
{
// Error
_tprintf(_T("malloc error 0x%x\n"), GetLastError());
return 1;
}
// Read private key
_tprintf(_T("ReadFile...\n"));
if (!ReadFile(hPrivateKeyFile, pbPrivateKey, dwPrivateKeyLen, &dwPrivateKeyLen, NULL))
{
// Error
_tprintf(_T("ReadFile error 0x%x\n"), GetLastError());
return 1;
}
// Import private key
_tprintf(_T("CryptImportKey...\n"));
if (!CryptImportKey(hCryptProv, pbPrivateKey, dwPrivateKeyLen, 0, 0, &hKey))
{
// Error
_tprintf(_T("CryptImportKey error 0x%x\n"), GetLastError());
return 1;
}
// Open encrypted file
_tprintf(_T("CreateFile...\n"));
if ((hEncryptedFile = CreateFile(
strEncryptedFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
)) == INVALID_HANDLE_VALUE)
{
// Error
_tprintf(_T("CreateFile error 0x%x\n"), GetLastError());
return 1;
}
// Get file size
_tprintf(_T("GetFileSize...\n"));
if ((dwDataLen = GetFileSize(hEncryptedFile, NULL)) == INVALID_FILE_SIZE)
{
// Error
_tprintf(_T("GetFileSize error 0x%x\n"), GetLastError());
return 1;
}
// Create a buffer for the encrypted data
_tprintf(_T("malloc...\n"));
if (!(pbData = (BYTE *)malloc(dwDataLen)))
{
// Error
_tprintf(_T("malloc error 0x%x\n"), GetLastError());
return 1;
}
// Read encrypted data
_tprintf(_T("ReadFile...\n"));
if (!ReadFile(hEncryptedFile, pbData, dwDataLen, &dwDataLen, NULL))
{
// Error
_tprintf(_T("ReadFile error 0x%x\n"), GetLastError());
return 1;
}
// Get lenght for plain text
if (!CryptDecrypt(hKey, NULL, TRUE, 0, pbData, &dwDataLen))
{
// Error
_tprintf(_T("CryptDecrypt error 0x%x\n"), GetLastError());
return 1;
}
// Create a file to save the plain text
_tprintf(_T("CreateFile...\n"));
if ((hPlainFile = CreateFile(
strPlainFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
)) == INVALID_HANDLE_VALUE)
{
// Error
_tprintf(_T("CreateFile error 0x%x\n"), GetLastError());
return 1;
}
// Write the plain text the file
_tprintf(_T("WriteFile...\n"));
if (!WriteFile(
hPlainFile,
(LPCVOID)pbData,
dwDataLen,
&lpNumberOfBytesWritten,
NULL
))
{
// Error
_tprintf(_T("WriteFile error 0x%x\n"), GetLastError());
return 1;
}
return 0;
}
__finally
{
// Clean up
if (!pbPrivateKey) {
_tprintf(_T("free...\n"));
free(pbPrivateKey);
}
if (!pbData) {
_tprintf(_T("free...\n"));
free(pbData);
}
if (hPrivateKeyFile) {
_tprintf(_T("CloseHandle...\n"));
CloseHandle(hPrivateKeyFile);
}
if (hEncryptedFile) {
_tprintf(_T("CloseHandle...\n"));
CloseHandle(hEncryptedFile);
}
if (hPlainFile) {
_tprintf(_T("CloseHandle...\n"));
CloseHandle(hPlainFile);
}
if (hKey) {
_tprintf(_T("CryptDestroyKey...\n"));
CryptDestroyKey(hKey);
}
if (hCryptProv) {
_tprintf(_T("CryptReleaseContext...\n"));
CryptReleaseContext(hCryptProv, 0);
}
}
}
// End of Decrypt
</SAMPLE>
Take a look to the following article for more info on these APIs: The Cryptography API, or How to Keep a Secret.
I hope this helps.
Cheers,
Alex (Alejandro Campos Magencio)
Comments
Anonymous
April 22, 2008
I am working in a concern in chennai,india.i am doing POC on 2-factor authentication.I need to have a client part for encrypting a data with certificate and post the same to server where i am decrypting with C#.net.i completed server part.i am working on client part. need your help.if possible please help me.My Mail ID: lraja@rsi.ramco.comAnonymous
April 22, 2008
Hi there,If you want to encrypt data with a certificate using CryptoAPI, you may want to take a look to this other post:How to Encrypt and Decrypt with CryptoAPI and a user Certificate (Windows Mobile)http://blogs.msdn.com/alejacma/archive/2008/04/04/how-to-encrypt-and-decrypt-with-cryptoapi-and-a-user-certificate-windows-mobile.aspxThis article talks about a solution for Windows Mobile, but for standard Windows the idea is the same. Just pay attention to the differences in the APIs as stated in MSDN.I hope this helps. If not, please open a case with MS Technical Support and we will help you.Cheers,AlexAnonymous
May 11, 2011
Very interesting article, but won't your encryption fail, if the file is bigger than bytelength of key -11?I'm sure i read about this limitation in MSDN.Thanks in Advance for your answerAnonymous
August 11, 2015
Very good article...worked like a charm... Thanks Alex..Anonymous
October 22, 2015
I'm not sure what I'm doing wrong. I create a pub and private key. I encrypt with the public key. I can then decrypt using either the public key or the private key.Anonymous
November 07, 2015
Rob, i've the same problem on windows 7 x64. Did you find out what's wrong with this code?