找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 3820|回复: 0

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

[复制链接]
发表于 2012-3-8 14:43:10 | 显示全部楼层 |阅读模式
数字证书采用公钥体制,即利用一对互相匹配的密钥进行加密、解密。每个用户自己设定一把特定的仅为本人所知的私有密钥(私钥),用它进行解密和签名;同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享,用于加密和验证签名。当发送一份保密文件时,发送方使用接收方的公钥对数据加密,而接收方则使用 自己的私钥解密,这样信息就可以安全无误地到达目的地了。通过数字的手段保证加 密过程是一个不可逆过程,即只有用私有密钥才能解密。在公开密钥密码体制中,常用的一种是RSA体制。其数学原理是将一个大数分解成两个质数的乘积,加密和解密用的是两个不同的密钥。即使已知明文、密文和加密密钥(公开密钥),想要推导出解密密钥(私密密钥),在计算上是不可能的。按现在的计算机技术水平,要破解目前采用的1024位RSA密钥,需要上千年的计算时间。公开密钥技术解决了密钥发布的管理问题,商户可以公开其公开密钥,而保留其私有密钥。购物者可以用人人皆知的公开密钥对发送的信息进行加密,安全地传送给商户,然后由商户用自己的私有密钥 进行解密
  用户也可以采用自己的私钥对信息加以处理,由于密钥仅为本人所有,这样就产生了别人无法生成的文件,也就形成了数字签名。采用数字签名,能够确认以下两点:
  (1)保证信息是由签名者自己签名发送的,签名者不能否认或难以否认;
  (2)保证信息自签发后到收到为止未曾作过任何修改,签发的文件是真实文件
  数字签名具体做法是:
  (1)将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证:只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性
  (2)将该报文摘要值用发送者的私人密钥加密,然后连同原报文一起发送给接收者,而产生的报文即称数字签名
  (3)接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较。如相等则说明报文确实来自所称的发送者。
代码如下,分析见注释
  1. #ifndef _WIN32_WINNT
  2. #define _WIN32_WINNT 0x0400
  3. #endif
  4. #include <stdio.h>
  5. #include <windows.h>
  6. #include <wincrypt.h>
  7. #define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  8. #define CERT_SUBJECT_NAME "TEST_SIGNER_NAME"
  9. //函数申明
  10. void HandleError(char *s);
  11. HCRYPTPROV GetCryptProv();
  12. void ByteToStr(
  13.      DWORD cb,
  14.      void* pv,
  15.      LPSTR sz);
  16. void main(void)
  17. {
  18.         //-------------------------------------------------------------------
  19.         // 变量申明与初始化
  20.        
  21.          HCERTSTORE hCertStore = NULL;
  22.          HCRYPTPROV hCertProv = NULL;
  23.          HCRYPTKEY hKeySign = NULL;
  24.          PCCERT_CONTEXT pCertCtxSign = NULL;
  25.          BYTE *Encrypted = NULL;
  26.          DWORD EncryptedLen = 0;
  27.          BYTE *Decrypted= NULL;
  28.          DWORD DecryptedLen = 0;
  29.          CERT_NAME_BLOB certName = {0};
  30.          certName.cbData = 0;
  31.          certName.pbData = NULL;
  32.          DWORD  cbNameEncoded;
  33.          BYTE*  pbNameEncoded;
  34.          //给CERT_NAME_BLOB结构certName赋值
  35.         CERT_RDN_ATTR rgNameAttr[] = {
  36.                         "2.5.4.3",                             
  37.                         CERT_RDN_PRINTABLE_STRING,            
  38.                         strlen(CERT_SUBJECT_NAME),            
  39.                         (BYTE*)CERT_SUBJECT_NAME};            
  40.         CERT_RDN rgRDN[] = {
  41.                          1,                 
  42.                          &rgNameAttr[0]};  
  43.         CERT_NAME_INFO Name = {
  44.                            1,                 
  45.                            rgRDN};            
  46.        
  47.         //-------------------------------------------------------------------
  48.         //    编码CERT_NAME_INFO结构,确定编码后的数据长度
  49.         if(CryptEncodeObject(
  50.                 MY_ENCODING_TYPE,     // Encoding type
  51.                 X509_NAME,            // Structure type
  52.                 &Name,                // Address of CERT_NAME_INFO structure
  53.                 NULL,                 // pbEncoded
  54.                 &cbNameEncoded))      // pbEncoded size
  55.         {
  56.                 printf("首次调用函数CryptEncodeObject成功. \n");
  57.         }
  58.         else
  59.         {
  60.                 HandleError("首次调用函数CryptEncodeObject失败.\
  61.                   \n公私密钥对不能从密钥容器中导出. \n");
  62.         }
  63.         //-------------------------------------------------------------------
  64.         //    分配内存
  65.         if(!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded)))
  66.                 HandleError("pbNamencoded malloc operation failed.\n");
  67.         //-------------------------------------------------------------------
  68.         //  编码结构体
  69.         if(CryptEncodeObject(
  70.                         MY_ENCODING_TYPE,    // Encoding type
  71.                         X509_NAME,           // Structure type
  72.                         &Name,               // Address of CERT_NAME_INFO structure
  73.                         pbNameEncoded,       // pbEncoded
  74.                         &cbNameEncoded))     // pbEncoded size
  75.         {
  76.                 printf("此结构体已被编码. \n");
  77.         }
  78.         else
  79.         {
  80.                 free(pbNameEncoded);
  81.                 HandleError("第二次调用函数CryptEncodeObject 失败.\n");
  82.         }
  83.         //给certName赋值
  84.         certName.cbData = cbNameEncoded;
  85.         certName.pbData = pbNameEncoded;
  86.        
  87.         //获取CSP句柄
  88.         hCertProv = GetCryptProv() ;
  89.          //产生签名密钥对   
  90.          if (CryptGenKey(hCertProv, AT_SIGNATURE, CRYPT_EXPORTABLE, &hKeySign))
  91.          {
  92.                   printf("在服务证书容器中创建签名密钥成功!\n");
  93.                   
  94.          }
  95.          else
  96.          {
  97.                  HandleError("Protection::Initialise -不能在服务证书容器中创建签名密钥- \n");
  98.                   
  99.          }       
  100.          SYSTEMTIME cs;
  101.          GetSystemTime(&cs);
  102.          cs.wYear += 1;
  103.          //创建自签名证书
  104.          if(pCertCtxSign = CertCreateSelfSignCertificate(
  105.                  hCertProv, //CSP句柄
  106.                  &certName, //证书客体名称数据结构指针
  107.                  0,         //标志位。默认行为,创建私钥信息,创建签名
  108.                  NULL,      //密钥信息结构
  109.                  NULL,      //签名算法,null表示默认算法SHA1RSA
  110.                  NULL,      //有效期起始时间 ,null表示取当前系统时间
  111.                  &cs,       //有效期终止时间,null表示起始时间加1年
  112.                  NULL))     //未设置扩展属性
  113.          {
  114.                  printf("一个自签名证书已经被创建.\n");
  115.          }         
  116.          else
  117.          {
  118.                  HandleError("CertCreateSelfSignCertificate Error!");                 
  119.          }
  120.          free(certName.pbData);
  121.          //打开证书库
  122.         if ((hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL , CERT_SYSTEM_STORE_CURRENT_USER , L"My")))
  123.         {
  124.                   printf("打开证书库成功.\n");
  125.         }
  126.         else
  127.         {
  128.                 HandleError("调用函数CertOpenStore 失败.\n");
  129.         }
  130.          //把证书加入证书库
  131.          if(CertAddCertificateContextToStore(hCertStore,
  132.         pCertCtxSign,CERT_STORE_ADD_NEW,NULL))
  133.          {                   
  134.                   printf("将自签名证书加入到系统证书库成功.\n");
  135.          }
  136.          else
  137.          {
  138.                   printf("将自签名证书添加到系统证书库中失败.\n");
  139.          }
  140.          //释放空间
  141.          if (Encrypted)
  142.                 free(Encrypted);
  143.          if (Decrypted)
  144.                 free(Decrypted);
  145.          if (pCertCtxSign)
  146.                 CertFreeCertificateContext(pCertCtxSign);
  147.          if (hKeySign)
  148.                 CryptDestroyKey(hKeySign);
  149.          if (hCertStore)
  150.                 CertCloseStore(hCertStore, 0);
  151.          if (hCertProv)
  152.                 CryptReleaseContext(hCertProv, 0);
  153.        
  154. } // End of main
  155. //获取加密提供者句柄
  156. HCRYPTPROV GetCryptProv()
  157. {
  158.         HCRYPTPROV hCryptProv;                      // 加密服务提供者句柄
  159.        
  160.         //获取加密提供者句柄
  161.         if(CryptAcquireContext(
  162.                                 &hCryptProv,         // 加密服务提供者句柄
  163.                                 "ruanou",                // 密钥容器名
  164.                                 MS_ENHANCED_PROV,    // 加密服务提供者   
  165.                                 PROV_RSA_FULL,       // 加密服务提供者类型,可以提供加密和签名等功能
  166.                                 0))                  // 标志
  167.         {
  168.                 printf("加密服务提供者句柄获取成功!\n");
  169.         }
  170.         else
  171.         {
  172.        
  173.                 //重新建立一个新的密钥集
  174.             if(!CryptAcquireContext(&hCryptProv, "ruanou", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
  175.                 {
  176.                    HandleError("重新建立一个新的密钥集出错!");
  177.                 }
  178.         }
  179.         return hCryptProv;
  180. }
  181. //--------------------------------------------------------------------
  182. // ByteToStr:  转换BYTE类型数组为字符串
  183. //参数:cb[in]  需要转换的BYTE数组的长度
  184. //      pv[in]  需要转换的BYTE数组指针
  185. //      sz[out] 字符串指针
  186. void ByteToStr(
  187.      DWORD cb,
  188.      void* pv,
  189.      LPSTR sz)
  190. {
  191.         BYTE* pb = (BYTE*) pv;
  192.         DWORD i;               
  193.         int b;                 
  194.         for (i = 0; i<cb; i++)
  195.         {
  196.                 //pb的前4位转换为字符
  197.             b = (*pb & 0xF0) >> 4;
  198.             *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
  199.             //pb的后4位转换为字符
  200.                 b = *pb & 0x0F;
  201.             *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
  202.             pb++;
  203.         }
  204.         *sz++ = 0;
  205. }
  206. //  HandleError:错误处理函数,打印错误信息,并退出程序
  207. void HandleError(char *s)
  208. {
  209.     printf("程序执行发生错误!\n");
  210.     printf("%s\n",s);
  211.     printf("错误代码为: %x.\n",GetLastError());
  212.     printf("程序终止执行!\n");
  213.     exit(1);
  214. }
复制代码


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

您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-4-29 06:34 , Processed in 0.011873 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表