VC++2010基于windows Sdk for windows7 开发CrytoAPI应用--消息加密与签名

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

下面演示对于消息加密与签名,详情请见代码。可以用于信息安全。

包括windows的消息都可以进行签名,防止消息hook,防止消息钩子,防止消息被攥改!

//-------------------------------------------------------------------
// 程序功能: 用发送者私钥签名消息,然后用接收者公钥加密签名消息。


#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <wincrypt.h>

#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define MAX_NAME  128


#define SIGNER_NAME L"DUMMY_SIGNER_NAME"     //签名者证书名称
#define RECEIVER_NAME L"China-wuhan-ruanou"  //接收者证书名称

//函数申明
void HandleError(char *s);
void ShowBytes(BYTE *s, DWORD len);
BYTE* SignAndEncrypt(
     const BYTE     *pbToBeSignedAndEncrypted,
     DWORD          cbToBeSignedAndEncrypted,
     DWORD          *pcbSignedAndEncryptedBlob);
BYTE* DecryptAndVerify(
     BYTE  *pbSignedAndEncryptedBlob,
     DWORD  cbSignedAndEncryptedBlob);

void main (void)
{
    //---------------------------------------------------------------
    // 变量申明与初始化

    //---------------------------------------------------------------
    //   pbToBeSignedAndEncrypted 为要签名与加密的消息,即原文消息
    const BYTE *pbToBeSignedAndEncrypted =
            (const unsigned char *)"在这里插入要签名的消息";
    DWORD cbToBeSignedAndEncrypted = 
        lstrlenA((const char *)pbToBeSignedAndEncrypted) + 1;   //消息长度

    BYTE *pbSignedAndEncryptedBlob;  //加密和签名后的消息
    DWORD cbSignedAndEncryptedBlob;  //加密和签名后的消息长度
    BYTE *pReturnMessage;

    //---------------------------------------------------------------
    //  调用SignAndEncrypt函数签名并加密消息,函数返回签名并加密后的消息及消息长度.
    pbSignedAndEncryptedBlob = SignAndEncrypt(
        pbToBeSignedAndEncrypted,
        cbToBeSignedAndEncrypted,
        &cbSignedAndEncryptedBlob);

    printf(TEXT("下面是签名和加密后的")
        TEXT("消息./n"));
    ShowBytes(pbSignedAndEncryptedBlob,cbSignedAndEncryptedBlob/4);


    //---------------------------------------------------------------
    //   调用函数DecryptAndVerify解密消息并验证消息签名     
    if(pReturnMessage = DecryptAndVerify(
        pbSignedAndEncryptedBlob,
        cbSignedAndEncryptedBlob))
    {
       printf(TEXT("返回验证后的消息是 ->/n%s/n"),
		    pReturnMessage);
       printf(TEXT("此程序执行无错./n"));
    }
    else
    {
       printf(TEXT("Verification failed./n"));
    }

} // End Main.

//-------------------------------------------------------------------
// 功能:签名原文消息,并加密此消息
// 返回值:签名并加密后的消息
// 参数:
//      pbToBeSignedAndEncrypted    欲签名并加密消息
//      cbToBeSignedAndEncrypted    欲签名并加密消息长度
//      pcbSignedAndEncryptedBlob   签名并加密后的消息长度

BYTE* SignAndEncrypt(
     const BYTE *pbToBeSignedAndEncrypted,
     DWORD cbToBeSignedAndEncrypted,
     DWORD *pcbSignedAndEncryptedBlob)
{
    //---------------------------------------------------------------
    //  变量申明与初始化
    HCERTSTORE hCertStore;  //证书库
    PCCERT_CONTEXT pSignerCertContext ;  //签名证书
    PCCERT_CONTEXT pReceiverCertContext;  //接收者证书

    TCHAR pszNameString[256];
    CRYPT_SIGN_MESSAGE_PARA SignPara;       //签名参数结构
    CRYPT_ENCRYPT_MESSAGE_PARA EncryptPara; //加密参数结构
    DWORD cRecipientCert;
    PCCERT_CONTEXT rgpRecipientCert[5];
    BYTE *pbSignedAndEncryptedBlob = NULL;
    DWORD dwKeySpec;
    HCRYPTPROV hCryptProv;

    //---------------------------------------------------------------
    //    打开“MY”证书库 
    if ( !( hCertStore = CertOpenStore(
        CERT_STORE_PROV_SYSTEM,
        0,
        NULL,
        CERT_SYSTEM_STORE_CURRENT_USER,
        L"my")))
    {
        HandleError(TEXT("MY 证书库不能打开."));
    }

    //---------------------------------------------------------------
    // 获取签名证书,此证书包含签名密钥对
    if(!(pSignerCertContext = CertFindCertificateInStore(
        hCertStore,
        MY_ENCODING_TYPE,
        0,
        CERT_FIND_SUBJECT_STR,
        SIGNER_NAME,
        NULL)))
    {
        HandleError(TEXT("发送者证书未找到./n"));
    }

    //---------------------------------------------------------------
    //   获取消息签名者证书名称
    if(CertGetNameString(
        pSignerCertContext ,
        CERT_NAME_SIMPLE_DISPLAY_TYPE,
        0,
        NULL,
        pszNameString,
        MAX_NAME) > 1)
    {
        _tprintf(
            TEXT("SIMPLE_DISPLAY_TYPE 消息签名者的名称是 ")
            TEXT("%s /n"),
            pszNameString);
    }
    else
    {
        HandleError(TEXT("获取签名者的名称失败./n"));
    }

	//获取签名者证书私钥
    if(!( CryptAcquireCertificatePrivateKey(
        pSignerCertContext,
        0,
        NULL,
        &hCryptProv,
        &dwKeySpec,
        NULL)))
    {
        HandleError(TEXT("CryptAcquireCertificatePrivateKey./n"));
    }

    
    //  获取接收者证书

	 if(!(pReceiverCertContext = CertFindCertificateInStore(
        hCertStore,
        MY_ENCODING_TYPE,
        0,
        CERT_FIND_SUBJECT_STR,
        RECEIVER_NAME,
        NULL)))
    {
        HandleError(TEXT("接收者证书未找到./n"));
    }

    //---------------------------------------------------------------
    //  获取接收者证书名称.

    if(CertGetNameString(
        pReceiverCertContext ,
        CERT_NAME_SIMPLE_DISPLAY_TYPE,
        0,
        NULL,
        pszNameString,
        MAX_NAME) > 1)
    {
        _tprintf(TEXT("消息接收者是  %s /n"), 
            pszNameString);
    }
    else
    {
        HandleError(TEXT("获取接收者的名称失败./n"));
    }

    //---------------------------------------------------------------
    //  初始化签名参数结构
    SignPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
    SignPara.dwMsgEncodingType = MY_ENCODING_TYPE;
    SignPara.pSigningCert = pSignerCertContext ;
    SignPara.HashAlgorithm.pszObjId = szOID_RSA_MD2;
    SignPara.HashAlgorithm.Parameters.cbData = 0;
    SignPara.pvHashAuxInfo = NULL;
    SignPara.cMsgCert = 1;
    SignPara.rgpMsgCert = &pSignerCertContext ;
    SignPara.cMsgCrl = 0;
    SignPara.rgpMsgCrl = NULL;
    SignPara.cAuthAttr = 0;
    SignPara.rgAuthAttr = NULL;
    SignPara.cUnauthAttr = 0;
    SignPara.rgUnauthAttr = NULL;
    SignPara.dwFlags = 0;
    SignPara.dwInnerContentType = 0;

	//---------------------------------------------------------------
    //  初始化加密参数结构
    EncryptPara.cbSize = sizeof(CRYPT_ENCRYPT_MESSAGE_PARA);
    EncryptPara.dwMsgEncodingType = MY_ENCODING_TYPE;
    EncryptPara.hCryptProv = 0;
    EncryptPara.ContentEncryptionAlgorithm.pszObjId = szOID_RSA_RC4;
    EncryptPara.ContentEncryptionAlgorithm.Parameters.cbData = 0;
    EncryptPara.pvEncryptionAuxInfo = NULL;
    EncryptPara.dwFlags = 0;
    EncryptPara.dwInnerContentType = 0;

    cRecipientCert = 1;
    rgpRecipientCert[0] = pReceiverCertContext;
    *pcbSignedAndEncryptedBlob = 0;
    pbSignedAndEncryptedBlob = NULL;

	//获取签名并加密后的消息长度
    if( CryptSignAndEncryptMessage(
        &SignPara,                          //签名参数结构
        &EncryptPara,                       //加密参数结构
        cRecipientCert,                     //接收者证书数目
        rgpRecipientCert,                   //接收者证书列表
        pbToBeSignedAndEncrypted,           //欲签名并加密消息
        cbToBeSignedAndEncrypted,           //欲签名并加密消息长度
        NULL,                               //签名并加密后的消息
        pcbSignedAndEncryptedBlob))         //签名并加密后的消息长度
    {
        _tprintf(TEXT("%d 字节分配给了缓冲区./n"),
            *pcbSignedAndEncryptedBlob);
    }
    else
    {
        HandleError(TEXT("获取缓冲区长度失败."));
    }

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

    if(!(pbSignedAndEncryptedBlob = 
        (unsigned char *)malloc(*pcbSignedAndEncryptedBlob)))
    {
        HandleError(TEXT("内存分配失败."));
    }

    //---------------------------------------------------------------
    //   签名消息,并对前面消息加密
    if( CryptSignAndEncryptMessage(
		&SignPara,                          //签名参数结构
        &EncryptPara,                       //加密参数结构
        cRecipientCert,                     //接收者证书数目
        rgpRecipientCert,                   //接收者证书列表
        pbToBeSignedAndEncrypted,           //欲签名并加密消息
        cbToBeSignedAndEncrypted,           //欲签名并加密消息长度
        pbSignedAndEncryptedBlob,                               //签名并加密后的消息
        pcbSignedAndEncryptedBlob))         //签名并加密后的消息长度
    {
        _tprintf(TEXT("此消息已经被签名并加密./n"));
    }
    else
    {
        HandleError(TEXT("此消息签名和加密失败."));
    }

    //---------------------------------------------------------------
    //  释放空间
    if(pSignerCertContext )
    {
        CertFreeCertificateContext(pSignerCertContext);
    }
    
    if(pReceiverCertContext )
    {
        CertFreeCertificateContext(pReceiverCertContext);
    }
    
    CertCloseStore(hCertStore, 0);

    //---------------------------------------------------------------
    //   返回签名并加密后的消息
    return pbSignedAndEncryptedBlob;

}  // End SignAndEncrypt.

//-------------------------------------------------------------------
// 功能:解密消息,验证其签名
// 返回值:解密后消息
// 参数:
//      pbSignedAndEncryptedBlob    签名并加密后的消息
//      cbSignedAndEncryptedBlob    签名并加密后的消息长度
BYTE* DecryptAndVerify(
     BYTE  *pbSignedAndEncryptedBlob,
     DWORD  cbSignedAndEncryptedBlob)
{
    //---------------------------------------------------------------
    //  变量申明与初始化
    HCERTSTORE hCertStore;
    CRYPT_DECRYPT_MESSAGE_PARA DecryptPara;
    CRYPT_VERIFY_MESSAGE_PARA VerifyPara;
    DWORD dwSignerIndex = 0;
    BYTE *pbDecrypted;
    DWORD cbDecrypted;

    //---------------------------------------------------------------
    //   打开“my”证书库
    if ( !( hCertStore = CertOpenStore(
        CERT_STORE_PROV_SYSTEM,
        0,
        NULL,
        CERT_SYSTEM_STORE_CURRENT_USER,
        L"my")))
    {
        HandleError(TEXT("MY 证书库不能被打开."));
    }

    //---------------------------------------------------------------
    //   初始化解密参数结构
    DecryptPara.cbSize = sizeof(CRYPT_DECRYPT_MESSAGE_PARA);
    DecryptPara.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
    DecryptPara.cCertStore = 1;
    DecryptPara.rghCertStore = &hCertStore;

	//---------------------------------------------------------------
    //   初始化验证参数结构
    VerifyPara.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
    VerifyPara.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
    VerifyPara.hCryptProv = 0;
    VerifyPara.pfnGetSignerCertificate = NULL;
    VerifyPara.pvGetArg = NULL;
    pbDecrypted = NULL;
    cbDecrypted = 0;

    //---------------------------------------------------------------
    //     确定解密后消息长度
    if(!(CryptDecryptAndVerifyMessageSignature(
        &DecryptPara,                  //解密参数结构体
        &VerifyPara,                   //验证参数结构体
        dwSignerIndex,                 //签名消息序号
        pbSignedAndEncryptedBlob,      //签名、加密、编码后的数据
        cbSignedAndEncryptedBlob,      //签名、加密、编码后的数据长度
        NULL,                          //解密后的数据
        &cbDecrypted,                  //解密后的数据长度
        NULL,
        NULL)))
    {
        HandleError(TEXT("获取解密后消息长度失败."));
    }

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

    if(!(pbDecrypted = (BYTE *)malloc(cbDecrypted)))
    {
        HandleError(TEXT("Memory allocation failed."));
    }

	//---------------------------------------------------------------
    //     解密消息,并验证消息
    if(!(CryptDecryptAndVerifyMessageSignature(
		&DecryptPara,                  //解密参数结构体
        &VerifyPara,                   //验证参数结构体
        dwSignerIndex,                 //签名消息序号
        pbSignedAndEncryptedBlob,      //签名、加密、编码后的数据
        cbSignedAndEncryptedBlob,      //签名、加密、编码后的数据长度
        pbDecrypted,                   //解密后的数据
        &cbDecrypted,                  //解密后的数据长度
        NULL,
        NULL)))
    {
        pbDecrypted = NULL;
    }

    //---------------------------------------------------------------
    //  关闭证书库
    CertCloseStore(
        hCertStore,
        0);

    //---------------------------------------------------------------
    //    返回解密后消息
    return pbDecrypted;

} // End of DecryptandVerify.


//-------------------------------------------------------------------
//  功能:显示BYTE数据,小于'0'及大于'-'的字符都显示为'-'
//  参数:s BYTE数据;len  数据长度 
void ShowBytes(BYTE *s, DWORD len)
{
    DWORD TotalChars = 0;
    DWORD ThisLine = 0;

    while(TotalChars < len)
    {
        if(ThisLine > 70)
        {
            ThisLine = 0;
            _tprintf(TEXT("/n"));
        }
        if( s[TotalChars] < '0' || s[TotalChars] > 'z')
        {
            _tprintf(TEXT("-"));
        }
        else
        {
            _tprintf(TEXT("%c"), s[TotalChars]);
        }

        TotalChars++;
        ThisLine++;
    }

    _tprintf(TEXT("/n"));
} // End of ShowBytes.

//  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/5336680

你可能感兴趣的:(VC++2010基于windows Sdk for windows7 开发CrytoAPI应用--消息加密与签名)