VC++2010基于windows Sdk for windows7 开发CrytoAPI应用--用数字证书签名消息并验证消息签名

 

windows Sdk for windows7 提供的CrytoAPI是微软推出的安全应用调用函数,用很小的代码就可以实现复杂的安全信息加密。

下面演示用数字证书签名消息并验证消息签名,详情请见代码。可以用于信息安全。

包括windows的消息都可以进行签名,防止消息hook,

 

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif 

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#define MY_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

//-------------------------------------------------------------------
//   签名证书名称,此证书必须为签名证书,并带有私钥
//   它必须具有CERT_KEY_PROV_INFO_PROP_ID或CERT_KEY_CONTEXT_PROP_ID属性
#define SIGNER_NAME  L"DUMMY_SIGNER_NAME"

//-------------------------------------------------------------------
//   证书库名称
#define CERT_STORE_NAME  L"MY"

//-------------------------------------------------------------------
//    函数申明
void HandleError(char *s);

void main(void)
{
	//-------------------------------------------------------------------
	// 变量申明与初始化
	HCERTSTORE hStoreHandle;        //系统证书库
	BYTE* pbMessage = 
		(BYTE*)"CryptoAPI is a good way to handle security"; //预签名消息
	DWORD cbMessage = strlen((char*) pbMessage)+1;    //预签名消息长度
	PCCERT_CONTEXT pSignerCert;         //签名证书
	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("开始处理. /n");

	printf(" 将要被签名的消息是/n-> %s./n",pbMessage);

	//-------------------------------------------------------------------
	// 打开证书库

	if ( !( hStoreHandle = CertOpenStore(
	   CERT_STORE_PROV_SYSTEM,
	   0,
	   NULL,
	   CERT_SYSTEM_STORE_CURRENT_USER,
	   CERT_STORE_NAME)))
	{
		 HandleError("MY 证书库不能被打开.");
	}

	//-------------------------------------------------------------------
	//获取签名证书指针,此证书必须拥有签名私钥
	if(pSignerCert = CertFindCertificateInStore(
	   hStoreHandle,
	   MY_TYPE,
	   0,
	   CERT_FIND_SUBJECT_STR,
	   SIGNER_NAME,
	   NULL))
	{
	   printf("签名者证书被找到./n");
	}
	else
	{
		HandleError( "签名证书未找到.");
	}

	//-------------------------------------------------------------------
	// 初始化签名数据结构

	SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
	SigParams.dwMsgEncodingType = MY_TYPE;
	SigParams.pSigningCert = pSignerCert;
	SigParams.HashAlgorithm.pszObjId = szOID_RSA_MD5;
	SigParams.HashAlgorithm.Parameters.cbData = NULL;
	SigParams.cMsgCert = 1;
	SigParams.rgpMsgCert = &pSignerCert;
	SigParams.cAuthAttr = 0;
	SigParams.dwInnerContentType = 0;
	SigParams.cMsgCrl = 0;
	SigParams.cUnauthAttr = 0;
	SigParams.dwFlags = 0;
	SigParams.pvHashAuxInfo = NULL;
	SigParams.rgAuthAttr = NULL;

	//-------------------------------------------------------------------
	// 两次调用 CryptSignMessage,签名消息.
	// 第一次获取签名数据 大小
	if(CryptSignMessage(
		&SigParams,            // 签名参数结构
		FALSE,                 // 是否拆开
		1,                     // 消息队列数目
		MessageArray,          // 消息队列
		MessageSizeArray,      // 消息大小队列
		NULL,                  // 签名后的数据
		&cbSignedMessageBlob)) // 签名数据长度
	{
		printf("签名数据块的大小是 %d./n",cbSignedMessageBlob);
	}
	else
	{
		HandleError("获取签名数据块长度失败.");
	}

	//-------------------------------------------------------------------
	// 分配内存

	if(!(pbSignedMessageBlob = 
	   (BYTE*)malloc(cbSignedMessageBlob)))
	{
		HandleError("签名时内存分配出错.");
	}

	//-------------------------------------------------------------------
	// 签名操作,pbSignedMessageBlob指向签名数据块
	if(CryptSignMessage(
		  &SigParams,            // 签名参数结构
		  FALSE,                 // 是否拆开
		  1,                     // 消息队列数目
		  MessageArray,          // 消息队列
		  MessageSizeArray,      // 消息大小队列
		  pbSignedMessageBlob,   // 签名后的数据
		  &cbSignedMessageBlob)) // 签名数据长度
	{
		printf("此消息被签名成功. /n");
	}
	else
	{
		HandleError("获取签名数据块出错.");
	}



	//-------------------------------------------------------------------
	//  第二阶段:验证数字签名
	//  一般的,这段程序由另一用户在另一应用程序中完成

	//-------------------------------------------------------------------
	//  初始化验证消息结构.

	VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
	VerifyParams.dwMsgAndCertEncodingType = MY_TYPE;
	VerifyParams.hCryptProv = 0;
	VerifyParams.pfnGetSignerCertificate = NULL;
	VerifyParams.pvGetArg = NULL;

	//-------------------------------------------------------------------
	//   两次调用CryptVerifyMessageSignature, 验证、解码签名消息
	//   第一次,获取解码消息长度

	if(CryptVerifyMessageSignature(
		&VerifyParams,           // 验证参数结构
		0,                       // 签名序号
		pbSignedMessageBlob,     // 签名数据
		cbSignedMessageBlob,     // 签名数据长度
		NULL,                    // 解码后数据
		&cbDecodedMessageBlob,   // 解码后数据长度
		NULL))                   // 签名证书指针
	{
		printf(" %d 字节的空间分配给了缓冲区./n",cbDecodedMessageBlob);
	}
	else
	{
		printf("验证消息失败. /n");
	}

	//-------------------------------------------------------------------
	//   分配空间

	if(!(pbDecodedMessageBlob = 
	   (BYTE*)malloc(cbDecodedMessageBlob)))
	{
		HandleError("为解码数据块分配空间出错.");
	}

	//-------------------------------------------------------------------
	//  验证签名,获取解码消息

	if(CryptVerifyMessageSignature(
		&VerifyParams,           // 验证参数结构
		0,                       // 签名序号
		pbSignedMessageBlob,     // 签名数据
		cbSignedMessageBlob,     // 签名数据长度
		pbDecodedMessageBlob,    // 解码后数据
		&cbDecodedMessageBlob,   // 解码后数据长度
		NULL))                   // 签名证书指针
	{
		printf("被验证的消息是 /n-> %s /n",
			pbDecodedMessageBlob);
	}
	else
	{
		HandleError("验证消息失败. /n");
	}

	//-------------------------------------------------------------------
	// 释放空间、资源

	if(pbSignedMessageBlob)
		 free(pbSignedMessageBlob);
	if(pbDecodedMessageBlob)
		 free(pbDecodedMessageBlob);
	if(pSignerCert)
		 CertFreeCertificateContext(pSignerCert);
	if(CertCloseStore(
		  hStoreHandle, 
		  CERT_CLOSE_STORE_CHECK_FLAG))
	{
		printf("证书库已关闭并且所有证书已经被释放. /n");
	}
	else
	{
		printf("签名之后证书库关闭 -- /n"
			  "但不是所有证书,证书撤消列表或证书信任列表都被释放了.");
	}
} // End of main

//  HandleError:错误处理函数,打印错误信息,并退出程序
void HandleError(char *s)
{
    printf("程序执行发生错误!/n");
    printf("%s/n",s);
    printf("错误代码为: %x./n",GetLastError());
    printf("程序终止执行!/n");
    exit(1);
}

 

本文作者专著《Visual C++2010开发权威指南》即将推出,敬请关注,Visual C++2010最近技术,Windows7开发最新技术!


原文链接: http://blog.csdn.net/yincheng01/article/details/5336676

你可能感兴趣的:(VC++2010基于windows Sdk for windows7 开发CrytoAPI应用--用数字证书签名消息并验证消息签名)