您的位置:首页 > 编程语言 > C语言/C++

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

2010-03-01 19:25 525 查看
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开发最新技术!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐