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]