winston 发表于 2012-3-8 14:43:10

[原]VC++网络安全编程范例(2)-创建自签名证书

数字证书采用公钥体制,即利用一对互相匹配的密钥进行加密、解密。每个用户自己设定一把特定的仅为本人所知的私有密钥(私钥),用它进行解密和签名;同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享,用于加密和验证签名。当发送一份保密文件时,发送方使用接收方的公钥对数据加密,而接收方则使用 自己的私钥解密,这样信息就可以安全无误地到达目的地了。通过数字的手段保证加 密过程是一个不可逆过程,即只有用私有密钥才能解密。在公开密钥密码体制中,常用的一种是RSA体制。其数学原理是将一个大数分解成两个质数的乘积,加密和解密用的是两个不同的密钥。即使已知明文、密文和加密密钥(公开密钥),想要推导出解密密钥(私密密钥),在计算上是不可能的。按现在的计算机技术水平,要破解目前采用的1024位RSA密钥,需要上千年的计算时间。公开密钥技术解决了密钥发布的管理问题,商户可以公开其公开密钥,而保留其私有密钥。购物者可以用人人皆知的公开密钥对发送的信息进行加密,安全地传送给商户,然后由商户用自己的私有密钥 进行解密
  用户也可以采用自己的私钥对信息加以处理,由于密钥仅为本人所有,这样就产生了别人无法生成的文件,也就形成了数字签名。采用数字签名,能够确认以下两点:
  (1)保证信息是由签名者自己签名发送的,签名者不能否认或难以否认;
  (2)保证信息自签发后到收到为止未曾作过任何修改,签发的文件是真实文件
  数字签名具体做法是:
  (1)将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证:只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性
  (2)将该报文摘要值用发送者的私人密钥加密,然后连同原报文一起发送给接收者,而产生的报文即称数字签名
  (3)接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较。如相等则说明报文确实来自所称的发送者。
代码如下,分析见注释

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif

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

#define MY_ENCODING_TYPE(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define CERT_SUBJECT_NAME "TEST_SIGNER_NAME"
//函数申明
void HandleError(char *s);
HCRYPTPROV GetCryptProv();
void ByteToStr(
   DWORD cb,
   void* pv,
   LPSTR sz);

void main(void)
{
        //-------------------------------------------------------------------
        // 变量申明与初始化
       
       HCERTSTORE hCertStore = NULL;
       HCRYPTPROV hCertProv = NULL;
       HCRYPTKEY hKeySign = NULL;
       PCCERT_CONTEXT pCertCtxSign = NULL;

       BYTE *Encrypted = NULL;
       DWORD EncryptedLen = 0;
       BYTE *Decrypted= NULL;
       DWORD DecryptedLen = 0;
       CERT_NAME_BLOB certName = {0};
       certName.cbData = 0;
       certName.pbData = NULL;
       DWORDcbNameEncoded;
       BYTE*pbNameEncoded;

       //给CERT_NAME_BLOB结构certName赋值

        CERT_RDN_ATTR rgNameAttr[] = {
                        "2.5.4.3",                           
                        CERT_RDN_PRINTABLE_STRING,            
                        strlen(CERT_SUBJECT_NAME),            
                        (BYTE*)CERT_SUBJECT_NAME};            

        CERT_RDN rgRDN[] = {
                       1,               
                       &rgNameAttr};


        CERT_NAME_INFO Name = {
                           1,               
                           rgRDN};            
       
        //-------------------------------------------------------------------
        //    编码CERT_NAME_INFO结构,确定编码后的数据长度

        if(CryptEncodeObject(
                MY_ENCODING_TYPE,   // Encoding type
                X509_NAME,            // Structure type
                &Name,                // Address of CERT_NAME_INFO structure
                NULL,               // pbEncoded
                &cbNameEncoded))      // pbEncoded size
        {
                printf("首次调用函数CryptEncodeObject成功. \n");
        }
        else
        {
                HandleError("首次调用函数CryptEncodeObject失败.\
                  \n公私密钥对不能从密钥容器中导出. \n");
        }
        //-------------------------------------------------------------------
        //    分配内存

        if(!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded)))
                HandleError("pbNamencoded malloc operation failed.\n");

        //-------------------------------------------------------------------
        //编码结构体

        if(CryptEncodeObject(
                        MY_ENCODING_TYPE,    // Encoding type
                        X509_NAME,         // Structure type
                        &Name,               // Address of CERT_NAME_INFO structure
                        pbNameEncoded,       // pbEncoded
                        &cbNameEncoded))   // pbEncoded size
        {
                printf("此结构体已被编码. \n");
        }
        else
        {
                free(pbNameEncoded);
                HandleError("第二次调用函数CryptEncodeObject 失败.\n");
        }

        //给certName赋值
        certName.cbData = cbNameEncoded;
        certName.pbData = pbNameEncoded;
       

        //获取CSP句柄
        hCertProv = GetCryptProv() ;

       //产生签名密钥对   
       if (CryptGenKey(hCertProv, AT_SIGNATURE, CRYPT_EXPORTABLE, &hKeySign))
       {
                  printf("在服务证书容器中创建签名密钥成功!\n");
                  
       }
       else
       {
               HandleError("Protection::Initialise -不能在服务证书容器中创建签名密钥- \n");
                  
       }       

       SYSTEMTIME cs;
       GetSystemTime(&cs);
       cs.wYear += 1;


       //创建自签名证书
       if(pCertCtxSign = CertCreateSelfSignCertificate(
               hCertProv, //CSP句柄
               &certName, //证书客体名称数据结构指针
               0,         //标志位。默认行为,创建私钥信息,创建签名
               NULL,      //密钥信息结构
               NULL,      //签名算法,null表示默认算法SHA1RSA
               NULL,      //有效期起始时间 ,null表示取当前系统时间
               &cs,       //有效期终止时间,null表示起始时间加1年
               NULL))   //未设置扩展属性
       {
               printf("一个自签名证书已经被创建.\n");
       }       
       else
       {
               HandleError("CertCreateSelfSignCertificate Error!");               
       }
       free(certName.pbData);


       //打开证书库
        if ((hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL , CERT_SYSTEM_STORE_CURRENT_USER , L"My")))
        {
                  printf("打开证书库成功.\n");
        }
        else
        {
                HandleError("调用函数CertOpenStore 失败.\n");
        }

       //把证书加入证书库
       if(CertAddCertificateContextToStore(hCertStore,
        pCertCtxSign,CERT_STORE_ADD_NEW,NULL))
       {                   
                  printf("将自签名证书加入到系统证书库成功.\n");
       }
       else
       {
                  printf("将自签名证书添加到系统证书库中失败.\n");
       }

       //释放空间
       if (Encrypted)
                free(Encrypted);
       if (Decrypted)
                free(Decrypted);
       if (pCertCtxSign)
                CertFreeCertificateContext(pCertCtxSign);
       if (hKeySign)
                CryptDestroyKey(hKeySign);
       if (hCertStore)
                CertCloseStore(hCertStore, 0);
       if (hCertProv)
                CryptReleaseContext(hCertProv, 0);
       
} // End of main

//获取加密提供者句柄
HCRYPTPROV GetCryptProv()
{
        HCRYPTPROV hCryptProv;                      // 加密服务提供者句柄
       
        //获取加密提供者句柄
        if(CryptAcquireContext(
                                &hCryptProv,         // 加密服务提供者句柄
                                "ruanou",                // 密钥容器名
                                MS_ENHANCED_PROV,    // 加密服务提供者   
                                PROV_RSA_FULL,       // 加密服务提供者类型,可以提供加密和签名等功能
                                0))                  // 标志
        {
                printf("加密服务提供者句柄获取成功!\n");
        }
        else
        {
       
                //重新建立一个新的密钥集
          if(!CryptAcquireContext(&hCryptProv, "ruanou", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
                {
                   HandleError("重新建立一个新的密钥集出错!");
                }

        }
        return hCryptProv;
}

//--------------------------------------------------------------------
// ByteToStr:转换BYTE类型数组为字符串
//参数:cb需要转换的BYTE数组的长度
//      pv需要转换的BYTE数组指针
//      sz 字符串指针
void ByteToStr(
   DWORD cb,
   void* pv,
   LPSTR sz)
{
        BYTE* pb = (BYTE*) pv;
        DWORD i;               
        int b;               

        for (i = 0; i<cb; i++)
        {
                //pb的前4位转换为字符
          b = (*pb & 0xF0) >> 4;
          *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
          //pb的后4位转换为字符
                b = *pb & 0x0F;
          *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
          pb++;
        }
        *sz++ = 0;
}

//HandleError:错误处理函数,打印错误信息,并退出程序
void HandleError(char *s)
{
    printf("程序执行发生错误!\n");
    printf("%s\n",s);
    printf("错误代码为: %x.\n",GetLastError());
    printf("程序终止执行!\n");
    exit(1);
}



作者:yincheng01 发表于2011-10-5 21:18:20 原文链接

页: [1]
查看完整版本: [原]VC++网络安全编程范例(2)-创建自签名证书