调用OpenSSL实现数字签名功能例程(二)

from http://blog.csdn.net/lee353086/article/details/7489870

  1. // PKCS7Sign.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6. #include <iostream>      
  7. #include <openssl/md5.h>    
  8.   
  9. #include <stdio.h>  
  10. #include <openssl/rsa.h>  
  11. #include <openssl/evp.h>  
  12. #include <openssl/objects.h>  
  13. #include <openssl/x509.h>  
  14. #include <openssl/err.h>  
  15. #include <openssl/pem.h>  
  16. #include <openssl/pkcs12.h>   
  17. #include <openssl/ssl.h>  
  18.   
  19. #pragma comment(lib, "libeay32.lib")     
  20. #pragma comment(lib, "ssleay32.lib")     
  21.   
  22. /* 
  23. PKCS7Sign.cpp 
  24. Auth:Kagula 
  25. 功能:调用OpenSSL实现数字签名功能例程(二) 
  26. 环境:VS2008+SP1,OpenSSL1.0.1 
  27. */  
  28.   
  29. /* 
  30. 功能:初始化OpenSSL 
  31. */  
  32. void InitOpenSSL()  
  33. {  
  34.     CRYPTO_malloc_init();  
  35.     /* Just load the crypto library error strings, 
  36.     * SSL_load_error_strings() loads the crypto AND the SSL ones */  
  37.     /* SSL_load_error_strings();*/  
  38.     ERR_load_crypto_strings();  
  39.     OpenSSL_add_all_algorithms();   
  40.     OpenSSL_add_all_ciphers();  
  41.     OpenSSL_add_all_digests();  
  42. }  
  43.   
  44. /* 
  45. 功能:对length长度的input指向的内存块进行BASE64编码 
  46. 入口: 
  47. const void *input           指向内存块的指针 
  48. int length                  内存块的有效长度 
  49. 返回: 
  50. char *                      返回字符串指针,使用完毕后,必须用free函数释放。 
  51. */  
  52. char *base64(const void *input, int length)  
  53. {  
  54.   BIO *bmem, *b64;  
  55.   BUF_MEM *bptr;  
  56.   
  57.   b64 = BIO_new(BIO_f_base64());  
  58.   bmem = BIO_new(BIO_s_mem());  
  59.   b64 = BIO_push(b64, bmem);  
  60.   BIO_write(b64, input, length);  
  61.   BIO_flush(b64);  
  62.   BIO_get_mem_ptr(b64, &bptr);  
  63.   
  64.   char *buff = (char *)malloc(bptr->length);  
  65.   memcpy(buff, bptr->data, bptr->length-1);  
  66.   buff[bptr->length-1] = 0;  
  67.   
  68.   BIO_free_all(b64);  
  69.   
  70.   return buff;  
  71. }  
  72.   
  73. /* 
  74. 功能:base64解码 
  75. 入口: 
  76. char *inputBase64  BASE64编码的签名 
  77. void *retBuf       缓存大小 
  78. 返回: 
  79. void *retBuf       解码后数据存放在这块内存中 
  80. int *retBufLen     解码后数据的长度 
  81. */  
  82. void *decodeBase64(char *inputBase64, void *retBuf,int *retBufLen)  
  83. {  
  84.     BIO *b64, *bmem;  
  85.       
  86.     b64 = BIO_new(BIO_f_base64());  
  87.     bmem = BIO_new_mem_buf(inputBase64, strlen((const char *)inputBase64));  
  88.     bmem = BIO_push(b64, bmem);   
  89.     int err=0;  
  90.     int i=0;  
  91.     do{  
  92.         err = BIO_read(bmem, (void *)( (char *)retBuf+i++), 1);  
  93.     }while( err==1 && i<*retBufLen );  
  94.     BIO_free_all(bmem);  
  95.   
  96.     *retBufLen = --i;  
  97.       
  98.     return retBuf;  
  99. }  
  100.   
  101.   
  102.   
  103. /* 
  104. 功能:对明文进行签名 
  105. 入口: 
  106. char*certFile    证书(例如:xxx.pfx) 
  107. char* pwd        证书的密码 
  108. char* plainText  待签名的字符串 
  109. int flag         签名方式 
  110. 出口: 
  111. char *           签名后的数据以BASE64形式返回 
  112.                  使用完毕后,必须用free函数释放。 
  113. */  
  114.   
  115. char * PKCS7_GetSign(char*certFile,char* pwd, char* plainText,int flag)  
  116. {  
  117.     //取PKCS12對象  
  118.     FILE* fp;  
  119.     if (!(fp = fopen(certFile, "rb")))   
  120.     {   
  121.         fprintf(stderr, "Error opening file %s\n", certFile);          
  122.         return NULL;       
  123.     }      
  124.     PKCS12 *p12= d2i_PKCS12_fp(fp, NULL);    
  125.     fclose (fp);      
  126.     if (!p12) {        
  127.         fprintf(stderr, "Error reading PKCS#12 file\n");     
  128.         ERR_print_errors_fp(stderr);    
  129.         return NULL;     
  130.     }   
  131.        
  132.     //取pkey對象、X509證書、證書鏈  
  133.     EVP_PKEY *pkey=NULL;       
  134.     X509 *x509=NULL;  
  135.     STACK_OF(X509) *ca = NULL;  
  136.     if (!PKCS12_parse(p12, pwd, &pkey, &x509, &ca)) {           
  137.         fprintf(stderr, "Error parsing PKCS#12 file\n");         
  138.         ERR_print_errors_fp(stderr);  
  139.         return NULL;  
  140.     }   
  141.     PKCS12_free(p12);  
  142.   
  143.     //明文轉為BIO對象  
  144.     //《vc++网络安全编程范例(14)-openssl bio编程 》   http://www.2cto.com/kf/201112/115018.html  
  145.     BIO *bio = BIO_new(BIO_s_mem());    
  146.     BIO_puts(bio,plainText);  
  147.   
  148.     //數字簽名  
  149.     //PKCS7_NOCHAIN:签名中不包含证书链,第三个参数为NULL值的话,可不加这个FLAG标记  
  150.     //PKCS7_NOSMIMECAP:签名不需要支持SMIME  
  151.     PKCS7* pkcs7 = PKCS7_sign(x509,pkey, ca,bio, flag);  
  152.     if(pkcs7==NULL)  
  153.     {  
  154.         ERR_print_errors_fp(stderr);  
  155.         return NULL;  
  156.     }  
  157.   
  158.     //共有两种编码,一种是ASN1,另一种是DER编码。  
  159.     //取數據簽名(DER格式)  
  160.     //openssl学习笔记之pkcs7-data内容类型的编码解码  
  161.     //http://ipedo.i.sohu.com/blog/view/114822358.htm  
  162.     //入口:pkcs7对象  
  163.     //出口:der对象  
  164.     unsigned char *der;  
  165.     unsigned char *derTmp;  
  166.     unsigned long derlen;  
  167.     derlen = i2d_PKCS7(pkcs7,NULL);  
  168.     der = (unsigned char *) malloc(derlen);  
  169.     memset(der,0,derlen);  
  170.     derTmp = der;  
  171.     i2d_PKCS7(pkcs7,&derTmp);  
  172.   
  173.     //DER转BASE64  
  174.     return base64(der,derlen);  
  175. }  
  176.   
  177. /* 
  178. 功能:验证签名 
  179. 入口: 
  180. char*certFile    证书(含匙) 
  181. char* plainText  明文 
  182. char* cipherText 签名 
  183. 出口: 
  184. bool true  签名验证成功 
  185. bool false 验证失败 
  186. */  
  187. bool PKCS7_VerifySign(char*certFile,char* plainText,char* cipherText )  
  188. {  
  189.     /* Get X509 */  
  190.     FILE* fp = fopen (certFile, "r");  
  191.     if (fp == NULL)   
  192.         return false;  
  193.     X509* x509 = PEM_read_X509(fp, NULL, NULL, NULL);  
  194.     fclose (fp);  
  195.   
  196.     if (x509 == NULL) {  
  197.         ERR_print_errors_fp (stderr);  
  198.         return false;  
  199.     }  
  200.   
  201.     //BASE64解码  
  202.     unsigned char *retBuf[1024*8];  
  203.     int retBufLen = sizeof(retBuf);  
  204.     memset(retBuf,0,sizeof(retBuf));  
  205.     decodeBase64(cipherText,(void *)retBuf,&retBufLen);  
  206.   
  207.     //从签名中取PKCS7对象  
  208.     BIO* vin = BIO_new_mem_buf(retBuf,retBufLen);  
  209.     PKCS7 *p7 = d2i_PKCS7_bio(vin,NULL);  
  210.   
  211.   
  212.     //取STACK_OF(X509)对象  
  213.     STACK_OF(X509) *stack=sk_X509_new_null();//X509_STORE_new()  
  214.     sk_X509_push(stack,x509);  
  215.   
  216.   
  217.     //明码数据转为BIO  
  218.     BIO *bio = BIO_new(BIO_s_mem());    
  219.     BIO_puts(bio,plainText);  
  220.   
  221.     //验证签名  
  222.     int err = PKCS7_verify(p7, stack, NULL,bio, NULL, PKCS7_NOVERIFY);  
  223.   
  224.     if (err != 1) {  
  225.         ERR_print_errors_fp (stderr);  
  226.         return false;  
  227.     }  
  228.   
  229.     return true;  
  230. }  
  231.   
  232. int _tmain(int argc, _TCHAR* argv[])  
  233. {  
  234.     char certFile[] = "demo.pfx";  
  235.     char plainText[]= "Hello,World!";  
  236.   
  237.     InitOpenSSL();  
  238.   
  239.     //數字簽名  
  240.     //PKCS7_NOCHAIN:签名中不包含证书链  
  241.     //PKCS7_NOSMIMECAP:签名不需要支持SMIME  
  242.     char * cipherText = PKCS7_GetSign(certFile,"11111111",plainText,PKCS7_DETACHED|PKCS7_NOSMIMECAP);  
  243.   
  244.     //打印出BASE64编码后的签名  
  245.     std::cout<<cipherText<<std::endl;  
  246.   
  247.     //验证数字签名  
  248.     if(PKCS7_VerifySign("BOC-CA.cer",plainText,cipherText))  
  249.         std::cout<<"Verify OK!"<<std::endl;  
  250.     else  
  251.         std::cout<<"Verify Failed!"<<std::endl;  
  252.       
  253.     //释放签名字符串(缓存)  
  254.     free(cipherText);  
  255.   
  256.     //输入任意字符继续  
  257.     getchar();  
  258.     return 0;  
  259. }  
  260.   
  261. /* 
  262. 关于OpenSSL的补充参考资料 
  263. [1]convert a PKCS 12 cert to PEM format . 
  264. http://blog.csdn.net/immcss/article/details/4443319 
  265. */  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值