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);
}