Enveloped Message Example 1

The following example code demonstrates the process of encoding, decoding, and decrypting an enveloped message that has a data inner-content data type.

//=============================================================
// EXAMPLE CODE FOR CREATING AN ENVELOPED 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"
                        "Enveloped 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 the messge

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

fReturn = CryptAcquireContext(
               &hCryptProv,       // Address for handle to be returned
               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.

//-------------------------------------------------------------
// Open the system certificate store.
//-------------------------------------------------------------
HCERTSTORE        hStoreHandle = NULL;

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
    AfxMessageBox( "Error Getting Store Handle");
    return;
}

// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.

//-------------------------------------------------------------
// Get a pointer to the recipient certificate.
//-------------------------------------------------------------
PCCERT_CONTEXT    pRecipCert = NULL;

// For the implementation of GetRecipientCert(), see the function
// at the end of this example code.
pRecipCert = GetRecipientCert(hStoreHandle, "James Allard");
if(!pRecipCert)
{
    AfxMessageBox( "Error Getting Recipient Cert");
    return;
}

// Create an array of CERT_INFOs. In this example, a single
// recipient.
PCERT_INFO        RecipCertArray[1];
RecipCertArray[0] = pRecipCert->pCertInfo;

//-------------------------------------------------------------
// Initialize the symmetric encryption Algorithm Identifier
// structure.
//-------------------------------------------------------------
DWORD                        ContentEncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER   ContentEncryptAlgorithm;
ContentEncryptAlgSize = sizeof(ContentEncryptAlgorithm);
memset(&ContentEncryptAlgorithm, 0, 
                             ContentEncryptAlgSize); // Init. to zero.

// Set the necessary fields. This particular OID doesn't
// need any parameters. Some OIDs, however will need the
// parameters member to be initialized.
ContentEncryptAlgorithm.pszObjId = szOID_RSA_RC4;    

//-------------------------------------------------------------
// Initialize the CMSG_ENVELOPED_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_ENVELOPED_ENCODE_INFO    EnvelopedEncodeInfo;

memset(&EnvelopedEncodeInfo, 0, 
                        sizeof(CMSG_ENVELOPED_ENCODE_INFO));
EnvelopedEncodeInfo.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
EnvelopedEncodeInfo.hCryptProv = hCryptProv;
EnvelopedEncodeInfo.ContentEncryptionAlgorithm = 
                                        ContentEncryptAlgorithm;
EnvelopedEncodeInfo.pvEncryptionAuxInfo = NULL;
EnvelopedEncodeInfo.cRecipients = 1;
EnvelopedEncodeInfo.rgpRecipients = RecipCertArray;

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

cbEncodedBlob = CryptMsgCalculateEncodedLength(
                    MY_ENCODING_TYPE,         // Msg encoding type
                    0,                        // Flags
                    CMSG_ENVELOPED,           // Msg type
                    &EnvelopedEncodeInfo,     // 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_ENVELOPED,          // Msg type
                &EnvelopedEncodeInfo,    // 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, enveloped content.

BOOL fForceFlag = 0;
BOOL fAllCertsClosed = 1;
// If CERT_CLOSE_STORE_FORCE_FLAG is used with CertCloseStore,
// all open certificate contexts are closed and freed, and
// the store is closed. In some cases, such as multi-
// threaded programs, this may not be desirable. If 
// CERT_CLOSE_STORE_CHECK_FLAG is used instead, the store will
// close but will warn you if all of the opened or duplicated
// certificate contexts have not been closed. Use
// CertFreeCertificateContext to close them when appropriate (as
// demonstrated in the "else" section of the following code).
if(fForceFlag)
{
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
}
else
{
    CertFreeCertificateContext(pRecipCert);
    fAllCertsClosed = CertCloseStore(hStoreHandle,
                                CERT_CLOSE_STORE_CHECK_FLAG);
    if(!fAllCertsClosed)
        AfxMessageBox("Certs are still open");
    CryptMsgClose(hMsg);
}

//=============================================================
// EXAMPLE CODE FOR DECODING AN ENVELOPED 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_ENVELOPED)
{
    AfxMessageBox("Wrong message type");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the size of inner content type BYTE string. If there is
// prior knowledge of inner data type, the next two function
// calls and the tests for the inner content type can be
// eliminated, and the decoding for that type of inner content
// can be implemented directly.
//-------------------------------------------------------------
DWORD   cbInnerContentObjId = sizeof(DWORD);

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

//-------------------------------------------------------------
// Allocate memory for the string.
//-------------------------------------------------------------
PBYTE   pbInnerContentObjId = NULL;

pbInnerContentObjId = (PBYTE) malloc(cbInnerContentObjId);
if(NULL == pbInnerContentObjId)
{
    AfxMessageBox("Decode inner content malloc failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the inner content type.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
           hMsg,                          // Handle to the message
           CMSG_INNER_CONTENT_TYPE_PARAM, // Parameter type
           0,                             // Index
           pbInnerContentObjId,           // Address for returned info
           &cbInnerContentObjId);         // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_INNER_CONTENT_TYPE_PARAM #2 failed");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}

//-------------------------------------------------------------
// Process according to the inner content type.
//-------------------------------------------------------------
LPSTR    pszInnerContentObjId = (LPSTR) pbInnerContentObjId;

// Test for the "data" data type.
if(!strcmp(pszInnerContentObjId, szOID_RSA_data))
{
    //-----------------------------------------------------------
    // Initialize the CMSG_CONTROL_DECRYPT_PARA structure.
    //-----------------------------------------------------------
    CMSG_CTRL_DECRYPT_PARA DecryptPara;

    memset(&DecryptPara, 0, sizeof(CMSG_CTRL_DECRYPT_PARA));
    DecryptPara.cbSize = sizeof(CMSG_CTRL_DECRYPT_PARA);
    DecryptPara.hCryptProv = hCryptProv; // Using handle opened in 
                                         //   "encode" code sect.
    DecryptPara.dwKeySpec = AT_KEYEXCHANGE;
    DecryptPara.dwRecipientIndex = 0; 

    //-----------------------------------------------------------
    // Decrypt the enveloped message.
    //-----------------------------------------------------------
    fResult = CryptMsgControl(
                 hMsg,                 // Message handle
                 0,                    // Flags
                 CMSG_CTRL_DECRYPT,    // Control type
                 &DecryptPara);        // Address of the parameters
    if(!fResult)
    {
    AfxMessageBox("Decode decryption failed");
    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);

    free(pbDecoded);
}
// Test for the "signed" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_signedData))
{
    // Decode the "signed" data type here.
    AfxMessageBox("Signed data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}
// Test for the "enveloped" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_envelopedData))
{
    // Decode the "enveloped" data type here.
    AfxMessageBox("Enveloped data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}
// Test for the "hashed" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_digestedData))
{
    // Decode the "hashed" data type here.
    AfxMessageBox("Hashed data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}

//-------------------------------------------------------------
// Clean up.
//-------------------------------------------------------------
free(pbEncodedBlob);
free(pbInnerContentObjId);
CryptMsgClose(hMsg);

}


//************************************************************
// GetRecipientCert() - A function to return the first
// certificate in the store that contains the subject name 
// string passed in pszRecipName.
//************************************************************
PCCERT_CONTEXT GetRecipientCert(HCERTSTORE hCertStore,
                                            LPSTR pszRecipName)
{
    PCCERT_CONTEXT    pPrevCertContext = NULL;
    PCCERT_CONTEXT    pCertContext = NULL;
    BOOL              fTestFlag;

    
    // This example code will find the first occurrence of a 
    // certificate containing a subject name passed in to
    // pszRecipName. That certificate must contain an exchange public 
    // key (not a signature public key).  If you suspect that more 
    // than one certificate exists for the desired individual, then 
    // additional checking must be done to determine that the returned 
    // certificate contains an exchange public key.

    while(TRUE)
    {
        pCertContext = CertFindCertificateInStore(
                        hCertStore,
                        X509_ASN_ENCODING,
                        0,
                        CERT_FIND_SUBJECT_STR_A,
                        pszRecipName,
                        pPrevCertContext);
        if(!pCertContext)
        {
            fTestFlag = FALSE;    // No match found
            break;
        }
        else
        {
            fTestFlag = TRUE;        // Match found.
            break;
        } 
        pPrevCertContext = pCertContext;    
    }
    CertFreeCertificateContext(pPrevCertContext);

    if(!fTestFlag)
    {
        AfxMessageBox("Recipient Cert Not Found");
        return NULL;
    }else
        return (pCertContext);
}