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开发最新技术!

你可能感兴趣的:(windows,null,vc++,byte,encoding,2010)