This code provides a set of functions for cryptographic operations in C++, including hashing, encryption, and decryption, using the Microsoft CryptoAPI.
Introduction
In simple terms, cryptography is the application of selected processes for encoding data so that the information can be stored and transmitted securely. The Microsoft CryptoAPI
allows developers to build cryptographic security into their applications by providing a flexible set of functions to encrypt or digitally sign data. You can use cryptography to achieve many security requirements, including:
- Ensuring secrecy by coding sensitive files so that an interloper cannot understand them;
- Guaranteeing secure communications even though the transmission media is not secure;
- Verifying the origin of messages and data using digital signatures.
The fundamental cryptographic operations supported by the CryptoAPI
are encryption, decryption, and signing. Encryption is somewhat like controlled fragmentation: the data is there, but it’s scattered according to the encryption rules. Decryption is simply the inverse of encryption, where the encryption rules are reversed to reassemble the data. Digital signing is analogous to physically hand-signing a document, but with one significant improvement: it is very, very difficult to forge a digital signature. Here, you can find more about this subject.
Using the Code
The main implementation is done in CryptographyExt.h and CryptographyExt.cpp files, as follows:
BOOL GetChecksumBuffer(ALG_ID nAlgorithm, LPBYTE lpszOutputBuffer, DWORD& dwOutputLength, LPBYTE lpszInputBuffer, DWORD dwInputLength);
computes hash code for the given binary buffer, using the specified algorithm; BOOL GetChecksumString(ALG_ID nAlgorithm, CString& strResult, CString strBuffer);
computes hash code for the given CString
, using the specified algorithm; BOOL GetChecksumFile(ALG_ID nAlgorithm, CString& strResult, CString strPathName);
computes hash code for the given file, using the specified algorithm; BOOL EncryptBuffer(ALG_ID nAlgorithm, LPBYTE lpszOutputBuffer, DWORD& dwOutputLength, LPBYTE lpszInputBuffer, DWORD dwInputLength, LPBYTE lpszSecretKey, DWORD dwSecretKey);
encrypt the given binary buffer, using the specified algorithm; BOOL EncryptFile(ALG_ID nAlgorithm, CString strOutputName, CString strInputName, LPBYTE lpszSecretKey, DWORD dwSecretKey);
encrypt the given file, using the specified algorithm; BOOL DecryptBuffer(ALG_ID nAlgorithm, LPBYTE lpszOutputBuffer, DWORD& dwOutputLength, LPBYTE lpszInputBuffer, DWORD dwInputLength, LPBYTE lpszSecretKey, DWORD dwSecretKey);
decrypt the given binary buffer, using the specified algorithm; BOOL DecryptFile(ALG_ID nAlgorithm, CString strOutputName, CString strInputName, LPBYTE lpszSecretKey, DWORD dwSecretKey);
decrypt the given file, using the specified algorithm; - Helper function for secret key:
CString GetComputerID();
BOOL GetChecksumBuffer(ALG_ID nAlgorithm, LPBYTE lpszOutputBuffer,
DWORD& dwOutputLength, LPBYTE lpszInputBuffer, DWORD dwInputLength)
{
BOOL retVal = FALSE;
ASSERT(lpszOutputBuffer != NULL);
ASSERT(dwOutputLength != 0);
ASSERT(lpszInputBuffer != NULL);
ASSERT(dwInputLength != 0);
HCRYPTPROV hCryptProv = NULL;
HCRYPTHASH hCryptHash = NULL;
if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
if (CryptCreateHash(hCryptProv, nAlgorithm, NULL, 0, &hCryptHash))
{
if (CryptHashData(hCryptHash, lpszInputBuffer, dwInputLength, 0))
{
if (CryptGetHashParam(hCryptHash, HP_HASHVAL,
lpszOutputBuffer, &dwOutputLength, 0))
{
retVal = TRUE;
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptGetHashParam"),
GetLastError());
}
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptHashData"), GetLastError());
}
VERIFY(CryptDestroyHash(hCryptHash));
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptCreateHash"), GetLastError());
}
VERIFY(CryptReleaseContext(hCryptProv, 0));
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptAcquireContext"), GetLastError());
}
return retVal;
}
BOOL EncryptBuffer(ALG_ID nAlgorithm, LPBYTE lpszOutputBuffer, DWORD& dwOutputLength,
LPBYTE lpszInputBuffer, DWORD dwInputLength, LPBYTE lpszSecretKey, DWORD dwSecretKey)
{
BOOL retVal = FALSE;
DWORD dwHowManyBytes = dwInputLength;
ASSERT(lpszOutputBuffer != NULL);
ASSERT(dwOutputLength != 0);
ASSERT(lpszInputBuffer != NULL);
ASSERT(dwInputLength != 0);
ASSERT(lpszSecretKey != NULL);
ASSERT(dwSecretKey != 0);
HCRYPTPROV hCryptProv = NULL;
HCRYPTHASH hCryptHash = NULL;
HCRYPTKEY hCryptKey = NULL;
::CopyMemory(lpszOutputBuffer, lpszInputBuffer, dwHowManyBytes);
if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
if (CryptCreateHash(hCryptProv, CALG_MD5, NULL, 0, &hCryptHash))
{
if (CryptHashData(hCryptHash, lpszSecretKey, dwSecretKey, 0))
{
if (CryptDeriveKey(hCryptProv, nAlgorithm,
hCryptHash, CRYPT_EXPORTABLE, &hCryptKey))
{
if (CryptEncrypt(hCryptKey, NULL, TRUE, 0,
lpszOutputBuffer, &dwHowManyBytes, dwOutputLength))
{
dwOutputLength = dwHowManyBytes;
retVal = TRUE;
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptEncrypt"),
GetLastError());
}
VERIFY(CryptDestroyKey(hCryptKey));
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptDeriveKey"),
GetLastError());
}
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptHashData"), GetLastError());
}
VERIFY(CryptDestroyHash(hCryptHash));
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptCreateHash"), GetLastError());
}
VERIFY(CryptReleaseContext(hCryptProv, 0));
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptAcquireContext"), GetLastError());
}
return retVal;
}
BOOL DecryptBuffer(ALG_ID nAlgorithm, LPBYTE lpszOutputBuffer, DWORD& dwOutputLength,
LPBYTE lpszInputBuffer, DWORD dwInputLength, LPBYTE lpszSecretKey, DWORD dwSecretKey)
{
BOOL retVal = FALSE;
DWORD dwHowManyBytes = dwInputLength;
ASSERT(lpszOutputBuffer != NULL);
ASSERT(dwOutputLength != 0);
ASSERT(lpszInputBuffer != NULL);
ASSERT(dwInputLength != 0);
ASSERT(lpszSecretKey != NULL);
ASSERT(dwSecretKey != 0);
HCRYPTPROV hCryptProv = NULL;
HCRYPTHASH hCryptHash = NULL;
HCRYPTKEY hCryptKey = NULL;
::CopyMemory(lpszOutputBuffer, lpszInputBuffer, dwHowManyBytes);
if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
if (CryptCreateHash(hCryptProv, CALG_MD5, NULL, 0, &hCryptHash))
{
if (CryptHashData(hCryptHash, lpszSecretKey, dwSecretKey, 0))
{
if (CryptDeriveKey(hCryptProv, nAlgorithm,
hCryptHash, CRYPT_EXPORTABLE, &hCryptKey))
{
if (CryptDecrypt(hCryptKey, NULL, TRUE, 0,
lpszOutputBuffer, &dwHowManyBytes))
{
dwOutputLength = dwHowManyBytes;
retVal = TRUE;
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptDecrypt"),
GetLastError());
}
VERIFY(CryptDestroyKey(hCryptKey));
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptDeriveKey"),
GetLastError());
}
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptHashData"), GetLastError());
}
VERIFY(CryptDestroyHash(hCryptHash));
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptCreateHash"), GetLastError());
}
VERIFY(CryptReleaseContext(hCryptProv, 0));
}
else
{
TraceLastError(CRYPT_LIBRARY_NAME, _T("CryptAcquireContext"), GetLastError());
}
return retVal;
}
History
- Version 1.00 (July 27th, 2014)
- Same version (March 31st, 2023)
- Moved source code to GitHub
- Version 1.01 (June 25th, 2023)
- Updated About dialog with GPLv3 notice
- Replaced old
CHyperlinkStatic
class with PJ Naughter's CHLinkCtrl
library
- Version 1.02 (October 19th, 2023):
- Updated the About dialog (email & website)
- Added social media links: Twitter, LinkedIn, Facebook, and Instagram
- Added shortcuts to GitHub repository's Issues, Discussions, and Wiki
- Same version (January 20th, 2024) - Added ReleaseNotes.html and SoftwareContextRegister.html to GitHub repo.