winzenghua 发表于 2013-2-7 04:36:43

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_NAMEL"DUMMY_SIGNER_NAME"//-------------------------------------------------------------------//   证书库名称#define CERT_STORE_NAMEL"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_PARASigParams; //签名参数结构DWORD cbSignedMessageBlob;          //签名数据块长度BYTE*pbSignedMessageBlob;         //签名数据块DWORD cbDecodedMessageBlob;         //解码数据块长度BYTE*pbDecodedMessageBlob;      //解码数据块CRYPT_VERIFY_MESSAGE_PARA VerifyParams;//验证参数结构//-------------------------------------------------------------------// 创建消息队列及消息长度队列const BYTE* MessageArray[] = {pbMessage};DWORD MessageSizeArray;MessageSizeArray = 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开发最新技术!
页: [1]
查看完整版本: VC++2010基于windows Sdk for windows7 开发CrytoAPI应用--用数字证书签名消息并验证消息签名