Example #1
0
BOOL EncodeMessage(PCRYPT_DATA_BLOB pEncodedBlob,
                   LPWSTR pwszSignerName)
{
    /*---------------------------------------------------------------
        Declare and initialize variables. This includes getting a 
        pointer to the message content. This sample creates 
        the message content and gets a pointer to it. In most 
        situations, the content will exist somewhere, and a 
        pointer to it will get passed to the application. 
    ---------------------------------------------------------------*/

    HCERTSTORE hSystemStoreHandle;
    CRYPT_SIGN_MESSAGE_PARA SignMessagePara;

    //---------------------------------------------------------------
    //   The message to be signed and encoded.

    BYTE* pbContent = (BYTE*) "The quick brown fox jumped over " \
        "the lazy dog.";

    /*---------------------------------------------------------------
        The length of the message. This must be one more than the 
        value returned by strlen() to include the terminal NULL 
        character.
    ---------------------------------------------------------------*/
    DWORD cbContent = lstrlenA((char *) pbContent) + 1;

    //---------------------------------------------------------------
    //    Arrays to hold the message to be signed and its length.

    const BYTE *rgpbToBeSigned[1] ;
    DWORD rgcbToBeSigned[1];

    //---------------------------------------------------------------
    //    The signer's certificate.

    PCCERT_CONTEXT pSignerCert; 

    //---------------------------------------------------------------
    //    Buffer to hold the name of the subject of a certificate.

	wchar_t pszNameString[MAX_NAME];

    //---------------------------------------------------------------
    //  The following variables are used only in the decoding phase.

    DWORD cbData = sizeof(DWORD);

    //---------------------------------------------------------------
    //  Begin processing. Display the original message.

    rgpbToBeSigned[0] = pbContent;
    rgcbToBeSigned[0] = cbContent;

    printf("The original message = \n%s\n\n",
        rgpbToBeSigned[0]);

    //---------------------------------------------------------------
    // Open a certificate store.

    if(hSystemStoreHandle = CertOpenStore(
        CERT_STORE_PROV_SYSTEM,
        0,
        NULL,
        CERT_SYSTEM_STORE_CURRENT_USER,
        CERTIFICATE_STORE_NAME))
    {
        printf("The certificate store is open. \n");
    }
    else
    {
        MyHandleError( "Error Getting Store Handle");
    }

    /*---------------------------------------------------------------
        Find a certificate in the store. This certificate will be 
        used to sign the message. To sign the message, the 
        certificate must have a private key accessible.
    ---------------------------------------------------------------*/

    if(pSignerCert = CertFindCertificateInStore(
        hSystemStoreHandle,
        MY_ENCODING_TYPE,
        0,
        CERT_FIND_SUBJECT_STR,
        pwszSignerName,
        NULL))
    {
        //-----------------------------------------------------------
        //  Get and print the name of the subject of the certificate.

        if(CertGetNameString(
            pSignerCert,
            CERT_NAME_SIMPLE_DISPLAY_TYPE,
            0,
            NULL,
            pszNameString,
            MAX_NAME) > 1)
        {
            wprintf(L"The message signer is  %s \n",pszNameString);
        }
        else
        {
            MyHandleError("Getting the name of the signer " \
                "failed.\n");
        }
    }
    else
    {
        MyHandleError("Signer certificate not found.");
    }

    /*---------------------------------------------------------------
    Initialize the CRYPT_SIGN_MESSAGE_PARA structure. First, use 
    memset to set all members to zero or NULL. Then set the values of
    all members that must be nonzero.
    ---------------------------------------------------------------*/

    memset(&SignMessagePara, 0, sizeof(CRYPT_SIGN_MESSAGE_PARA));
    SignMessagePara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
    SignMessagePara.HashAlgorithm.pszObjId = szOID_RSA_MD2;
    SignMessagePara.pSigningCert = pSignerCert;
    SignMessagePara.dwMsgEncodingType = MY_ENCODING_TYPE;
    SignMessagePara.cMsgCert = 1;
    SignMessagePara.rgpMsgCert = &pSignerCert;

    /*---------------------------------------------------------------
        In two steps, sign and encode the message. First, get the 
        number of bytes required for the buffer to hold the signed 
        and encoded message.
    ---------------------------------------------------------------*/

    if( CryptSignMessage(
            &SignMessagePara,
            FALSE,
            1,
            rgpbToBeSigned,
            rgcbToBeSigned,
            NULL,
            &pEncodedBlob->cbData))
    {
        printf("The needed length is %d \n", pEncodedBlob->cbData);
    }
    else
    {
        MyHandleError("Getting the length failed.\n");
    }

    //---------------------------------------------------------------
    //   Allocate memory for the required buffer.
    pEncodedBlob->pbData = (BYTE *)malloc(pEncodedBlob->cbData);
    if(!pEncodedBlob->pbData)
    {
        MyHandleError("Memory allocation failed.");
    }

    //---------------------------------------------------------------
    //   Call CryptSignMessage a second time to
    //   copy the signed and encoded message to the buffer.

    if( CryptSignMessage(
        &SignMessagePara,
        FALSE,
        1,
        rgpbToBeSigned,
        rgcbToBeSigned,
        pEncodedBlob->pbData,
        &pEncodedBlob->cbData))
    {
        printf("Signing worked \n");
    }
    else
    {
        MyHandleError("Signing failed.\n");
    }

    //---------------------------------------------------------------
    //  Clean up after signing and encoding.

    if(pSignerCert)
    {
        CertFreeCertificateContext(pSignerCert);
    }
    
    if(hSystemStoreHandle)
    {
        CertCloseStore(hSystemStoreHandle,
            CERT_CLOSE_STORE_FORCE_FLAG);
    }

    return TRUE;
}
/*****************************************************************************
 wmain

*****************************************************************************/
DWORD
__cdecl
wmain(
    int     argc,
    LPWSTR  argv[]
    )
{
    HRESULT                     hr = S_OK;

    BOOL                        fSign = TRUE;        

    LPCWSTR                     pwszInputFile = NULL;
    LPCWSTR                     pwszOutputFile = NULL;

    BYTE                        *pbInput = NULL;
    DWORD                       cbInput = 0;    
    BYTE                        *pbOutput = NULL;
    DWORD                       cbOutput = 0;

    CERT_CHAIN_PARA             ChainPara         = {0};
    CERT_CHAIN_POLICY_PARA      ChainPolicy       = {0};
    CERT_CHAIN_POLICY_STATUS    PolicyStatus      = {0};
    PCCERT_CHAIN_CONTEXT        pChain = NULL;

    PCCERT_CONTEXT              pSignerCert = NULL;
    HCERTSTORE                  hStoreHandle = NULL;

    LPCWSTR                     pwszStoreName = L"MY";  // by default
    LPCWSTR                     pwszCName = L"Test";    // by default

    LPCWSTR                     wszHashAlgName = L"SHA1";

    int                         i;

    //
    // options
    //

    for( i=1; i<argc; i++ )
    {
        if ( lstrcmpW (argv[i], L"/?") == 0 ||
             lstrcmpW (argv[i], L"-?") == 0 ) 
        {
            Usage( L"cms_sign.exe" );
            goto CleanUp;
        }

        if( *argv[i] != L'-' )
            break;

        if ( lstrcmpW (argv[i], L"-s") == 0 )
        {
            if( i+1 >= argc )
            {
                hr = E_INVALIDARG;
                goto CleanUp;
            }

            pwszStoreName = argv[++i];
        }
        else
        if ( lstrcmpW (argv[i], L"-n") == 0 )
        {
            if( i+1 >= argc )
            {
                hr = E_INVALIDARG;
                goto CleanUp;
            }

            pwszCName = argv[++i];
        }
        else
        if ( lstrcmpW (argv[i], L"-a") == 0 )
        {
            if( i+1 >= argc )
            {
                hr = E_INVALIDARG;
                goto CleanUp;
            }

            wszHashAlgName = argv[++i];
        }
    }

    if( 0 == lstrcmpW (argv[i], L"SIGN"))
    {
        if( i+2 >= argc )
        {
            hr = E_INVALIDARG;
            goto CleanUp;
        }

        fSign = TRUE;
        pwszInputFile = argv[++i];
        pwszOutputFile = argv[++i];
    }
    else
    if( 0 == lstrcmpW (argv[i], L"VERIFY"))
    {
        if( i+1 >= argc )
        {
            hr = E_INVALIDARG;
            goto CleanUp;
        }

        fSign = FALSE;
        pwszInputFile = argv[++i];
    }
    else
    {
        hr = E_INVALIDARG;
        goto CleanUp;
    }

    if( i != argc-1 )
    {
        hr = E_INVALIDARG;
        goto CleanUp;
    }

    //-------------------------------------------------------------------
    // Open the certificate store to be searched.

    hStoreHandle = CertOpenStore(
                           CERT_STORE_PROV_SYSTEM,          // the store provider type
                           0,                               // the encoding type is not needed
                           NULL,                            // use the default HCRYPTPROV
                           CERT_SYSTEM_STORE_CURRENT_USER,  // set the store location in a 
                                                            //  registry location
                           pwszStoreName
                           );                               // the store name 

    if( NULL == hStoreHandle )
    {
        hr = HRESULT_FROM_WIN32( GetLastError() );
        goto CleanUp;
    }

    //
    // Load file
    // 

    hr = HrLoadFile(
                                            pwszInputFile,
                                            &pbInput,
                                            &cbInput
                                            );
    if( FAILED(hr) )
    {
        wprintf( L"Unable to read file: %s\n", pwszInputFile );
        goto CleanUp;
    }


    if( fSign )
    {
        //-------------------------------------------------------------------
        // Sign Message

        PCCRYPT_OID_INFO pOidInfo = NULL;
        CRYPT_SIGN_MESSAGE_PARA  SigParams = {0};

        // Create the MessageArray and the MessageSizeArray.
        const BYTE* MessageArray[] = {pbInput};
        DWORD MessageSizeArray[] = {cbInput};

        //
        // Get a certificate that has the specified Subject Name
        //

        pSignerCert = CertFindCertificateInStore(
                               hStoreHandle,
                               X509_ASN_ENCODING ,        // Use X509_ASN_ENCODING
                               0,                         // No dwFlags needed
                               CERT_FIND_SUBJECT_STR,     // Find a certificate with a
                                                          //  subject that matches the 
                                                          //  string in the next parameter
                               pwszCName,                 // The Unicode string to be found
                                                          //  in a certificate's subject
                               NULL);                     // NULL for the first call to the
                                                          //  function; In all subsequent
                                                          //  calls, it is the last pointer
                                                          //  returned by the function
        if( NULL == pSignerCert )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        //
        // Build a chain in order to include certs to the message
        //

        if( !CertGetCertificateChain(
                                    NULL,                  // use the default chain engine
                                    pSignerCert,           // pointer to the end certificate
                                    NULL,                  // use the default time
                                    NULL,                  // search no additional stores
                                    &ChainPara,            // use AND logic and enhanced key usage 
                                                           //  as indicated in the ChainPara 
                                                           //  data structure
                                    CERT_CHAIN_REVOCATION_CHECK_END_CERT,
                                    NULL,                  // currently reserved
                                    &pChain ))             // return a pointer to the chain created
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        //
        // Verify that the chain complies with Base policy
        //

        ChainPolicy.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
        ChainPolicy.dwFlags = 0;

        PolicyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS);

        ChainPolicy.pvExtraPolicyPara = NULL;
        if (!CertVerifyCertificateChainPolicy(
                                        CERT_CHAIN_POLICY_BASE,
                                        pChain,
                                        &ChainPolicy,
                                        &PolicyStatus))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        if( PolicyStatus.dwError != S_OK ) 
        {
            ReportError( L"Base Policy Chain Status Failure:", PolicyStatus.dwError  );
            hr = PolicyStatus.dwError;
        }

        // Initialize the signature structure.
        SigParams.cbSize = sizeof(SigParams);
        SigParams.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
        SigParams.pSigningCert = pSignerCert;
        SigParams.cAuthAttr = 0;
        SigParams.dwInnerContentType = 0;
        SigParams.cMsgCrl = 0;
        SigParams.cUnauthAttr = 0;
        SigParams.dwFlags = 0;
        SigParams.pvHashAuxInfo = NULL;
        SigParams.rgAuthAttr = NULL;

        //
        // Addd max of 8 certs to the message
        //

        PCCERT_CONTEXT   rgpMsgCert[8] = {NULL};
        SigParams.rgpMsgCert = rgpMsgCert;
        for( SigParams.cMsgCert=0; SigParams.cMsgCert<pChain->rgpChain[0]->cElement && SigParams.cMsgCert<8; SigParams.cMsgCert++ )
        {
            rgpMsgCert[SigParams.cMsgCert] = pChain->rgpChain[0]->rgpElement[SigParams.cMsgCert]->pCertContext;
        }

        //
        // Find OID
        //

        pOidInfo = CryptFindOIDInfo(
                                    CRYPT_OID_INFO_NAME_KEY,
                                    (void*)wszHashAlgName,
                                    CRYPT_HASH_ALG_OID_GROUP_ID
                                    );

        if( NULL == pOidInfo )
        {
            hr = CRYPT_E_UNKNOWN_ALGO;
            goto CleanUp;
        }

        SigParams.HashAlgorithm.pszObjId = (LPSTR)pOidInfo->pszOID;


        // First, get the size of the signed BLOB.
        if( !CryptSignMessage(
                                &SigParams,
                                FALSE,
                                1,
                                MessageArray,
                                &cbInput,
                                NULL,
                                &cbOutput ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        // Allocate memory for the signed BLOB.
        pbOutput = (BYTE*)LocalAlloc( LPTR, cbOutput );
        if( NULL == pbOutput )
        {
            hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
            goto CleanUp;
        }

        // Get the signed message BLOB.
        if( !CryptSignMessage(
                                &SigParams,
                                FALSE,
                                1,
                                MessageArray,
                                MessageSizeArray,
                                pbOutput,
                                &cbOutput ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        hr = HrSaveFile(
                                    pwszOutputFile,
                                    pbOutput,
                                    cbOutput
                                    );
        if( FAILED(hr) )
        {
            wprintf( L"Unable to save file: %s\n", pwszOutputFile );
            goto CleanUp;
        }

        wprintf( L"Successfully signed message using CryptSignMessage.\n");
    }
    else
    {
        //-------------------------------------------------------------------
        // Verify signed message

        CRYPT_VERIFY_MESSAGE_PARA   VerifyParams = {0};

        VerifyParams.cbSize = sizeof(VerifyParams);
        VerifyParams.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
        VerifyParams.hCryptProv = 0;
        VerifyParams.pfnGetSignerCertificate = NULL;
        VerifyParams.pvGetArg = NULL;

        // First, call CryptVerifyMessageSignature to get the length 
        // of the buffer needed to hold the decoded message.
        if( !CryptVerifyMessageSignature(
                                        &VerifyParams,
                                        0,
                                        pbInput,
                                        cbInput,
                                        NULL,
                                        &cbOutput,
                                        NULL))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        pbOutput = (BYTE*)LocalAlloc( LPTR, cbOutput );
        if( NULL == pbOutput )
        {
            hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
            goto CleanUp;
        }

        //---------------------------------------------------------------
        // Call CryptVerifyMessageSignature again to verify the signature
        // and, if successful, copy the decoded message into the buffer. 
        if( !CryptVerifyMessageSignature(
                                        &VerifyParams,
                                        0,
                                        pbInput,
                                        cbInput,
                                        pbOutput,
                                        &cbOutput,
                                        &pSignerCert))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        wprintf( L"Successfully verified signed message using CryptVerifyMessageSignature.\n");

        //
        // Build a chain in order to verify certificate trust
        //

        //
        // Instruction :   Create a certificate store from the CMS message and provide as a parameter to 
        //                 CertGetCertificateChain. This will ensure that all additional certificates from
		//                 the CMS message are used in chain building
        //                 Otherwise chain will be build using the local stores only.
        // 

        if( !CertGetCertificateChain(
                                    NULL,                  // use the default chain engine
                                    pSignerCert,           // pointer to the end certificate
                                    NULL,                  // use the default time
                                    NULL,                  // search no additional stores
                                    &ChainPara,            // use AND logic and enhanced key usage 
                                                           //  as indicated in the ChainPara 
                                                           //  data structure
                                    CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
                                    NULL,                  // currently reserved
                                    &pChain ))             // return a pointer to the chain created
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        //
        // Verify that the chain complies with Base policy
        //

        ChainPolicy.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
        ChainPolicy.dwFlags = 0;

        PolicyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS);

        ChainPolicy.pvExtraPolicyPara = NULL;
        if (!CertVerifyCertificateChainPolicy(
                                        CERT_CHAIN_POLICY_BASE,
                                        pChain,
                                        &ChainPolicy,
                                        &PolicyStatus))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        if( PolicyStatus.dwError != S_OK ) 
        {
            ReportError( L"Base Policy Chain Status Failure:", PolicyStatus.dwError  );
            hr = PolicyStatus.dwError;
        }
    }

    hr = S_OK;

    //-------------------------------------------------------------------
    // Clean up memory.

CleanUp:

    if( NULL != pbInput )
    {
        LocalFree(pbInput);
    }

    if( NULL != pbOutput )
    {
        LocalFree(pbOutput);
    }

    if( NULL != pChain )
    {
        CertFreeCertificateChain(pChain);
    }

    if( NULL != pSignerCert )
    {
        CertFreeCertificateContext(pSignerCert);
    }

    if( NULL != hStoreHandle)
    {
        CertCloseStore( hStoreHandle, 0 );
    }

    if( FAILED( hr ))
    {
        ReportError( NULL, hr  );
    }

    return (DWORD)hr;
} // End of main
int _tmain(int argc, _TCHAR* argv[])
{
	//--------------------------------------------------------------------
	// Declare and initialize variables.
	HCERTSTORE       hCertStore = NULL;        
	PCCERT_CONTEXT   pCertContext = NULL;      
	TCHAR * pszStoreName = TEXT("MY");
	HCRYPTKEY hKey = NULL;
	HCRYPTPROV hProv = NULL;
	DWORD dwKeySpec = 0;
	BOOL bCallerFreeProv = FALSE;
	HCRYPTHASH hHash;
	DWORD dwSigLen= 0;
	BYTE * pbSignature = NULL;

	//-------------------------------------------------------------
	// Declare and initialize variables.
	BYTE *pbBuffer= (BYTE *)"The data that is to be hashed and signed.";
	DWORD dwBufferLen = strlen((char *)pbBuffer)+1;

	//--------------------------------------------------------------------
	//   Open a certificate store.
	if ( hCertStore = CertOpenSystemStore(
		NULL,
		pszStoreName))
	{
		fprintf(stderr,"The store has been opened.\n");
	}
	else
	{
		printf("Unable to open store.\n");
		goto err;
	}
	//--------------------------------------------------------------------
	//  Display a list of the certificates in the store and 
	//  allow the user to select a certificate. 
	if(!(pCertContext = CryptUIDlgSelectCertificateFromStore(
		hCertStore,      // Open the store that contains the certificates to
		// display
		NULL,
		NULL,
		NULL,
		CRYPTUI_SELECT_LOCATION_COLUMN,
		0,
		NULL)))
	{
		printf("Select Certificate UI failed.\n" );
		goto err;
	}

#if 1
	//获取CSP句柄
	if (!CryptAcquireCertificatePrivateKey(pCertContext, 0, NULL, &hProv, &dwKeySpec, &bCallerFreeProv))
	{
		printf("CryptAcquireCertificatePrivateKey failed.\n" );
		goto err;
	}

	//获取密钥句柄
	if(!CryptGetUserKey(hProv, dwKeySpec, &hKey))
	{
		printf("CryptGetUserKey failed.\n" );
		goto err;
	}

	
	
	//--------------------------------------------------------------------
	// Acquire a hash object handle.
	if(CryptCreateHash(
		hProv, 
		CALG_MD5, 
		0, 
		0, 
		&hHash)) 
	{
		printf("An empty hash object has been created. \n");
	}
	else
	{
		printf("Error during CryptBeginHash!\n");
		goto err;
	}


	//--------------------------------------------------------------------
	//  This code assumes that the handle of a cryptographic context 
	//  has been acquired and that a hash object has been created 
	//  and its handle (hHash) is available.
	if(CryptHashData(
		hHash, 
		pbBuffer, 
		dwBufferLen, 
		0)) 
	{
		printf("The data buffer has been added to the hash.\n");
	}
	else
	{
		printf("Error during CryptHashData.\n");
		goto err;
	}


	//--------------------------------------------------------------------
	// Determine the size of the signature and allocate memory.
	dwSigLen= 0;
	if(CryptSignHash(
		hHash, 
		dwKeySpec, 
		NULL, 
		0, 
		NULL, 
		&dwSigLen)) 
	{
		printf("Signature length %d found.\n",dwSigLen);
	}
	else
	{
		printf("Error during CryptSignHash\n");
		goto err;
	}
	//--------------------------------------------------------------------
	// Allocate memory for the signature buffer.

	if(pbSignature = (BYTE *)malloc(dwSigLen))
	{
		printf("Memory allocated for the signature.\n");
	}
	else
	{
		printf("Out of memory\n");
		goto err;
	}
	//--------------------------------------------------------------------
	// Sign the hash object.

	if(CryptSignHash(
		hHash, 
		dwKeySpec, 
		NULL, 
		0, 
		pbSignature, 
		&dwSigLen)) 
	{
		printf("pbSignature is the hash signature.\n");
	}
	else
	{
		printf("Error during CryptSignHash.\n");
		goto err;
	}


	{
		DWORD dwBlobLen = 0;
		BYTE * pbKeyBlob = 0;
		HCRYPTKEY hPubKey = 0; 

		if(CryptExportKey(  
			hKey, 
			NULL, 
			PUBLICKEYBLOB,       //导出公钥
			0,   
			NULL,
			&dwBlobLen))         //返回密钥数据长度
		{
			printf("Size of the BLOB for the public key determined. \n");
		}
		else
		{
			printf("Error computing BLOB length.\n");
			goto err;
		}

		if(pbKeyBlob = (BYTE*)malloc(dwBlobLen))
		{
			printf("Memory has been allocated for the BLOB. \n");
		}
		else
		{
			printf("Out of memory. \n");
			goto err;
		}
		if(CryptExportKey(  
			hKey,
			NULL, 
			PUBLICKEYBLOB,   
			0,   
			pbKeyBlob,       //返回密钥数据
			&dwBlobLen)) //导出的密钥数据的长度
		{
			printf("Contents have been written to the BLOB. \n");
		}
		else
		{
			printf("Error exporting key.\n");
			goto err;
		}

		if(CryptImportKey(hProv,pbKeyBlob, dwBlobLen, NULL, 0, &hPubKey))
		{
			printf("CryptImportKey OK. \n");
		}
		else
		{
			printf("Error CryptImportKey.\n");
			goto err;
		}

		if(CryptVerifySignature(hHash, pbSignature, dwSigLen,hPubKey,NULL,0))
		{
			printf("verify OK.\n");
		}
		else
		{
			printf("Error during CryptVerifySignature.\n");
			goto err;
		}

	}

	if(CryptVerifySignature(hHash, pbSignature, dwSigLen,hKey,NULL,0))
	{
		printf("verify OK.\n");
	}
	else
	{
		printf("Error during CryptVerifySignature.\n");
		goto err;
	}

#endif

	BYTE* pbMessage =  

		(BYTE*)"CryptoAPI is a good way to handle security";  
	DWORD cbMessage = strlen((char*) pbMessage)+1;  
	//证书的上下文  

	CRYPT_SIGN_MESSAGE_PARA SigParams;  

	DWORD cbSignedMessageBlob;  

	BYTE *pbSignedMessageBlob;  

	DWORD cbDecodedMessageBlob;  

	BYTE *pbDecodedMessageBlob;  

	CRYPT_VERIFY_MESSAGE_PARA VerifyParams;  

	const BYTE* MessageArray[] = {pbMessage};  

	DWORD MessageSizeArray[1];  

	MessageSizeArray[0] = cbMessage;  

	printf("Begin processing. \n");  
	printf(" The message to be signed is\n-> %s.\n",pbMessage);  

	//--------------------------------------------------------------------  
	//初始化签名结构  
	SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);  

	SigParams.dwMsgEncodingType = (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING);  

	SigParams.pSigningCert = pCertContext;  

	SigParams.HashAlgorithm.pszObjId = szOID_RSA_MD5;  

	SigParams.HashAlgorithm.Parameters.cbData = NULL;  

	SigParams.cMsgCert = 1;  

	SigParams.rgpMsgCert = &pCertContext;  

	SigParams.cAuthAttr = 0;  

	SigParams.dwInnerContentType = 0;  

	SigParams.cMsgCrl = 0;  

	SigParams.cUnauthAttr = 0;  

	SigParams.dwFlags = 0;  

	SigParams.pvHashAuxInfo = NULL;  

	SigParams.rgAuthAttr = NULL;  

	//首先得到BLOB的大小  
	if(CryptSignMessage(  
		&SigParams, // Signature parameters  
		FALSE, // Not detached  
		1, // Number of messages  
		MessageArray, // Messages to be signed  
		MessageSizeArray, // Size of messages  
		NULL, // Buffer for signed message  
		&cbSignedMessageBlob)) // Size of buffer  
	{
		printf("The size of the BLOB is %d.\n",cbSignedMessageBlob);  
	} 
	else  
	{
		printf("Getting signed BLOB size failed");  
	}  

	//--------------------------------------------------------------------  
	//分配BLOB的内存.  

	if(!(pbSignedMessageBlob =  
		(BYTE*)malloc(cbSignedMessageBlob)))  
	{ 
		printf("Memory allocation error while signing.");  
	}  

	if(CryptSignMessage(  
		&SigParams, //  
		FALSE, //  
		1, //消息数量  
		MessageArray, //待签名的消息  
		MessageSizeArray, //消息大小  
		pbSignedMessageBlob, //缓冲区 
		&cbSignedMessageBlob)) //缓冲区大小  
	{  
		printf("The message was signed successfully. \n");  
	} 
	else  
	{  
		printf("Error getting signed BLOB");  
	}  

	//--------------------------------------------------------------------
	//验证签名信息  
	//--------------------------------------------------------------------
	//初始化VerifyParams结构.  

	VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);  

	VerifyParams.dwMsgAndCertEncodingType =  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING); 

	VerifyParams.hCryptProv = 0;  

	VerifyParams.pfnGetSignerCertificate = NULL;  

	VerifyParams.pvGetArg = NULL;  

	if(CryptVerifyMessageSignature(  
		&VerifyParams, //.  
		0, //  
		pbSignedMessageBlob, //.  
		cbSignedMessageBlob, //  
		NULL, //  
		&cbDecodedMessageBlob, //
		NULL)) // Pointer to signer certificate.  
	{  
		printf("%d bytes need for the buffer.\n",cbDecodedMessageBlob);  
	}  
	else  
	{  
		printf("Verification message failed. \n");  
	}  

	//为缓冲区分配内存.  
	if(!(pbDecodedMessageBlob =  
		(BYTE*)malloc(cbDecodedMessageBlob)))  
	{  
		printf("Memory allocation error allocating decode BLOB.");  
	}  

	//得到缓冲区的大小  
	if(CryptVerifyMessageSignature(  
		&VerifyParams, // Verify parameters.  
		0, // Signer index.  
		pbSignedMessageBlob, // Pointer to signed BLOB.  
		cbSignedMessageBlob, // Size of signed BLOB.  
		pbDecodedMessageBlob, // Buffer for decoded message.  
		&cbDecodedMessageBlob, // Size of buffer.  
		NULL)) // Pointer to signer certificate.  

	{  
		printf("The verified message is \n-> %s \n",pbDecodedMessageBlob);  
	}  
	else  
	{  
		printf("Verification message failed. \n"); 
	}  

err:
	WTF_PrintErrorMsg();

	if(pbSignedMessageBlob)  
	{
		free(pbSignedMessageBlob);  
	}

	if(pbDecodedMessageBlob)  
	{
		free(pbDecodedMessageBlob);  
	}

	if (pbSignature)
	{
		free(pbSignature);
	}

	if(hHash) 
	{
		CryptDestroyHash(hHash);
	}
	if (hKey)
	{
		CryptDestroyKey(hKey);
	}

	if (hProv)
	{
		CryptReleaseContext(hProv, 0);
	}
	if (pCertContext)
	{
		CertFreeCertificateContext(pCertContext);
	}
	
	if (hCertStore)
	{
		CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
	}
	
	return 0;
}