Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

Crypt Library Demo - The Basics of Microsoft CryptoAPI Library

4.83/5 (18 votes)
20 Jan 2024GPL32 min read 31.2K   769  
The article discusses the concept of cryptography and its application in ensuring data security.
This code provides a set of functions for cryptographic operations in C++, including hashing, encryption, and decryption, using the Microsoft CryptoAPI.

Image 1

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();
C++
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)
    • Initial release
  • 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.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)