65.9K
CodeProject is changing. Read more.
Home

Crypt Library Demo - The Basics of Microsoft CryptoAPI Library

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (17 votes)

Jul 28, 2014

GPL3

2 min read

viewsIcon

31182

downloadIcon

769

The article discusses the concept of cryptography and its application in ensuring data security.

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)
    • 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.