Hashed Message Example Code

The following example code demonstrates the process of encoding, decoding, and verifying the hash of a hashed message.

//=============================================================
// EXAMPLE CODE FOR CREATING A HASHED MESSAGE.
//=============================================================

// Use this constant definition (or one similar to it) to define
// a single encoding type that can be used in all parameters and
// data members that require one or the other or both.
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING)

//-------------------------------------------------------------
// Get a pointer to the message content- this code creates  
// the message content and gets a pointer to it. In reality, 
// the content will usually exist somewhere and a pointer to it
// will get passed to the application. 
//-------------------------------------------------------------
char szContent[] = "A Razzle-Dazzle \n"
                        "Hashed Message";    // The message
char* pszContent = szContent;                // A string pointer
BYTE* pbContent = (BYTE*) pszContent;        // A byte pointer
DWORD cbContent = sizeof(szContent);         // Size of message

AfxMessageBox(pszContent);    // Display original message.

//-------------------------------------------------------------
// Get a handle to a cryptographic provider. 
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
               &hCryptProv,      // Address for the handle 
               NULL,             // Use the current user's logon name
               NULL,             // Use the default provider
               PROV_RSA_FULL,    // Specifies the provider type
               0);               // Zero allows access to private keys
if(!fReturn)
{
    AfxMessageBox("CryptAcquireContext failed");
    return;
}

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

//-------------------------------------------------------------
// Initialize the Algorithm Identifier structure.
//-------------------------------------------------------------
DWORD                        HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER    HashAlgorithm;
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize);   // Init. to zero.
HashAlgorithm.pszObjId = szOID_RSA_MD5;   // Then set the 
                                          //   necessary field.

//-------------------------------------------------------------
// Initialize the CMSG_HASHED_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_HASHED_ENCODE_INFO    HashedEncodeInfo;

memset(&HashedEncodeInfo, 0, sizeof(CMSG_HASHED_ENCODE_INFO));
HashedEncodeInfo.cbSize = sizeof(CMSG_HASHED_ENCODE_INFO);
HashedEncodeInfo.hCryptProv = hCryptProv;
HashedEncodeInfo.HashAlgorithm = HashAlgorithm;
HashedEncodeInfo.pvHashAuxInfo = NULL;

//-------------------------------------------------------------
// Get the size of the encoded message blob.
//-------------------------------------------------------------
DWORD        cbEncodedBlob;
BYTE        *pbEncodedBlob = NULL;

cbEncodedBlob = CryptMsgCalculateEncodedLength(
                     MY_ENCODING_TYPE,     // Msg encoding type
                     0,                    // Flags
                     CMSG_HASHED,          // Msg type
                     &HashedEncodeInfo,    // Ptr. to struct.
                     NULL,                 // Inner content ObjID
                     cbContent);           // size of content
if(0 == cbEncodedBlob)
{
    AfxMessageBox("Getting cbEncodedBlob length failed");
    return;
}

//-------------------------------------------------------------
// Allocate memory for the encoded blob.
//-------------------------------------------------------------
pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
    AfxMessageBox("Malloc failed");
    return;
}

//-------------------------------------------------------------
// Open a message to encode.
//-------------------------------------------------------------
HCRYPTMSG    hMsg = NULL;

hMsg = CryptMsgOpenToEncode(
            MY_ENCODING_TYPE,        // Encoding type
            0,                       // Flags
            CMSG_HASHED,             // Msg type
            &HashedEncodeInfo,       // Pointer to structure
            NULL,                    // Inner content ObjID
            NULL);                   // Stream Info (not used)
if(NULL == hMsg)
{
    AfxMessageBox("OpenToEncode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the data.
//-------------------------------------------------------------
BOOL fResult;

fResult = CryptMsgUpdate(
                    hMsg,          // Handle to the message
                    pbContent,     // Pointer to the content
                    cbContent,     // Size of the content
                    TRUE);         // Last call
if(!fResult)
{
    AfxMessageBox("MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the resultant message.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
               hMsg,                     // Handle to the message
               CMSG_CONTENT_PARAM,       // Parameter type
               0,                        // Index
               pbEncodedBlob,            // Pointer to the blob
               &cbEncodedBlob);          // Size of the blob
if(!fResult)
{
    AfxMessageBox("MsgGetParam failed");
    free(pbEncodedBlob);
    return;
}else
    AfxMessageBox("Message encoded sucessfully");

// If the call was successful, pbEncodedBlob now points to the
// encoded, signed content.

CryptMsgClose(hMsg);

//=============================================================
// EXAMPLE CODE FOR DECODING A HASHED MESSAGE
//=============================================================

//-------------------------------------------------------------
// Open a message for decoding.
//-------------------------------------------------------------

hMsg = CryptMsgOpenToDecode(
            MY_ENCODING_TYPE,         // Encoding type
            0,                        // Flags
            0,                        // Message type (get from msg.)
            hCryptProv,               // Cryptographic provider
            NULL,                     // Recipient info
            NULL);                    // Stream info
if(NULL == hMsg)
{
    AfxMessageBox("OpenToDecode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the encoded blob, using the data
// that was encoded in the previous section of code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
                    hMsg,             // Handle to the message
                    pbEncodedBlob,    // Pointer to the encoded blob
                    cbEncodedBlob,    // Size of the encoded blob
                    TRUE);            // Last call
if(!fResult)
{
    AfxMessageBox("Decode MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the message type.
//-------------------------------------------------------------
DWORD cbData = sizeof(DWORD);
DWORD dwMsgType = 0;

fResult = CryptMsgGetParam(
                    hMsg,               // Handle to the message
                    CMSG_TYPE_PARAM,    // Parameter type
                    0,                  // Index
                    &dwMsgType,         // Address for returned info
                    &cbData);           // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_TYPE_PARAM failed");
    free(pbEncodedBlob);
    return;
}

// Some applications may need to use a "switch" statement here
// and process the message differently, depending on the
// message type.
if(dwMsgType != CMSG_HASHED)
{
    AfxMessageBox("Wrong message type");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the size of the content.
//-------------------------------------------------------------
DWORD    cbDecoded = 0;

fResult = CryptMsgGetParam(
               hMsg,                   // Handle to the message
               CMSG_CONTENT_PARAM,     // Parameter type
               0,                      // Index
               NULL,                   // Address for returned info
               &cbDecoded);            // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_CONTENT_PARAM failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Allocate Memory.
//-------------------------------------------------------------
BYTE    *pbDecoded = NULL;

pbDecoded = (BYTE *) malloc(cbDecoded);
if(NULL == pbDecoded)
{
    AfxMessageBox("Decode memory allocation failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get a pointer to the content.
//-------------------------------------------------------------
LPSTR    pDecodedString;

fResult = CryptMsgGetParam(
               hMsg,                    // Handle to the message
               CMSG_CONTENT_PARAM,      // Parameter type
               0,                       // Index
               pbDecoded,               // Address for returned info
               &cbDecoded);             // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_CONTENT_PARAM #2 failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    return;
}else
    AfxMessageBox("Message decoded successfully");

pDecodedString = (LPSTR) pbDecoded;

AfxMessageBox(pDecodedString);

//-------------------------------------------------------------
// VERIFY THE HASH.
//-------------------------------------------------------------

fResult = CryptMsgControl(
              hMsg,                        // Handle to the message
              0,                           // Flags
              CMSG_CTRL_VERIFY_HASH,       // Control type
              NULL);                       // Pointer not used
if(!fResult)
{
    AfxMessageBox("Verify Hash failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    return;
}
else
    AfxMessageBox("Verify Hash Succeeded");

// If the call succeeded, the hash was verified and the data
// has not been tampered with.

//-------------------------------------------------------------
// Clean up
//-------------------------------------------------------------
free(pbEncodedBlob);
free(pbDecoded);
CryptMsgClose(hMsg);    
}