Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / Win32

Crypt Library Demo - The Basics of Microsoft CryptoAPI Library

Rate me:
Please Sign up or sign in to vote.
4.81/5 (17 votes)
20 Jan 2024GPL32 min read 29.3K   769   52   10
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)


Written By
Software Developer NXP Semiconductors
Romania Romania
My professional background includes knowledge of analyst programmer for Microsoft Visual C++, Microsoft Visual C#, Microsoft Visual Basic, Sun Java, assembly for Intel 80x86 microprocessors, assembly for PIC microcontrollers (produced by Microchip Inc.), relational databases (MySQL, Oracle, SQL Server), concurrent version systems, bug tracking systems, web design (HTML5, CSS3, XML, PHP/MySQL, JavaScript).

Comments and Discussions

 
QuestionThe article mentioned about GitHub repo Pin
Shao Voon Wong22-Jan-24 15:43
mvaShao Voon Wong22-Jan-24 15:43 
AnswerRe: The article mentioned about GitHub repo Pin
Ștefan-Mihai MOGA22-Jan-24 17:00
professionalȘtefan-Mihai MOGA22-Jan-24 17:00 
GeneralMy vote of 5 Pin
Shao Voon Wong20-Jan-24 13:15
mvaShao Voon Wong20-Jan-24 13:15 
GeneralRe: My vote of 5 Pin
Ștefan-Mihai MOGA20-Jan-24 15:58
professionalȘtefan-Mihai MOGA20-Jan-24 15:58 
QuestionLimit(s)! Pin
Apprieu (Apprieu)24-Oct-23 22:47
Apprieu (Apprieu)24-Oct-23 22:47 
AnswerRe: Limit(s)! Pin
Ștefan-Mihai MOGA25-Oct-23 9:25
professionalȘtefan-Mihai MOGA25-Oct-23 9:25 
GeneralRe: Limit(s)! Pin
Apprieu (Apprieu)3-Nov-23 22:29
Apprieu (Apprieu)3-Nov-23 22:29 
GeneralRe: Limit(s)! Pin
Ștefan-Mihai MOGA3-Nov-23 22:47
professionalȘtefan-Mihai MOGA3-Nov-23 22:47 
GeneralRe: Limit(s)! Pin
Apprieu (Apprieu)6-Nov-23 22:22
Apprieu (Apprieu)6-Nov-23 22:22 
Questionany .NET version of this article? Pin
Southmountain8-Jul-23 9:51
Southmountain8-Jul-23 9:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.