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

// PKCS7Sign.cpp : Defines the entry point for the console application.
//


#include "stdafx.h"


#include <iostream>    
#include <openssl/md5.h>  


#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h> 
#include <openssl/ssl.h>


#pragma comment(lib, "libeay32.lib")   
#pragma comment(lib, "ssleay32.lib")   


/*
PKCS7Sign.cpp
Auth:Kagula
功能:调用OpenSSL实现数字签名功能例程(二)
环境:VS2008+SP1,OpenSSL1.0.1
*/


/*
功能:初始化OpenSSL
*/
void InitOpenSSL()
{
CRYPTO_malloc_init();
/* Just load the crypto library error strings,
* SSL_load_error_strings() loads the crypto AND the SSL ones */
/* SSL_load_error_strings();*/
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms(); 
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
}


/*
功能:对length长度的input指向的内存块进行BASE64编码
入口:
const void *input           指向内存块的指针
int length                  内存块的有效长度
返回:
char *                      返回字符串指针,使用完毕后,必须用free函数释放。
*/
char *base64(const void *input, int length)
{
  BIO *bmem, *b64;
  BUF_MEM *bptr;


  b64 = BIO_new(BIO_f_base64());
  bmem = BIO_new(BIO_s_mem());
  b64 = BIO_push(b64, bmem);
  BIO_write(b64, input, length);
  BIO_flush(b64);
  BIO_get_mem_ptr(b64, &bptr);


  char *buff = (char *)malloc(bptr->length);
  memcpy(buff, bptr->data, bptr->length-1);
  buff[bptr->length-1] = 0;


  BIO_free_all(b64);


  return buff;
}


/*
功能:base64解码
入口:
char *inputBase64  BASE64编码的签名
void *retBuf       缓存大小
返回:
void *retBuf       解码后数据存放在这块内存中
int *retBufLen     解码后数据的长度
*/
void *decodeBase64(char *inputBase64, void *retBuf,int *retBufLen)
{
BIO *b64, *bmem;

b64 = BIO_new(BIO_f_base64());
bmem = BIO_new_mem_buf(inputBase64, strlen((const char *)inputBase64));
bmem = BIO_push(b64, bmem); 
int err=0;
int i=0;
do{
err = BIO_read(bmem, (void *)( (char *)retBuf+i++), 1);
}while( err==1 && i<*retBufLen );
BIO_free_all(bmem);


*retBufLen = --i;

return retBuf;
}






/*
功能:对明文进行签名
入口:
char*certFile    证书(例如:xxx.pfx)
char* pwd        证书的密码
char* plainText  待签名的字符串
int flag         签名方式
出口:
char *           签名后的数据以BASE64形式返回
                 使用完毕后,必须用free函数释放。
*/


char * PKCS7_GetSign(char*certFile,char* pwd, char* plainText,int flag)
{
//取PKCS12對象
FILE* fp;
if (!(fp = fopen(certFile, "rb"))) 

fprintf(stderr, "Error opening file %s\n", certFile);        
return NULL;     
}    
PKCS12 *p12= d2i_PKCS12_fp(fp, NULL);  
fclose (fp);    
if (!p12) {      
fprintf(stderr, "Error reading PKCS#12 file\n");   
ERR_print_errors_fp(stderr);  
return NULL;   

 
//取pkey對象、X509證書、證書鏈
EVP_PKEY *pkey=NULL;     
X509 *x509=NULL;
STACK_OF(X509) *ca = NULL;
if (!PKCS12_parse(p12, pwd, &pkey, &x509, &ca)) {         
fprintf(stderr, "Error parsing PKCS#12 file\n");       
ERR_print_errors_fp(stderr);
return NULL;

PKCS12_free(p12);


//明文轉為BIO對象
//《vc++网络安全编程范例(14)-openssl bio编程 》   http://www.2cto.com/kf/201112/115018.html
BIO *bio = BIO_new(BIO_s_mem());  
BIO_puts(bio,plainText);


//數字簽名
//PKCS7_NOCHAIN:签名中不包含证书链,第三个参数为NULL值的话,可不加这个FLAG标记
//PKCS7_NOSMIMECAP:签名不需要支持SMIME
PKCS7* pkcs7 = PKCS7_sign(x509,pkey, ca,bio, flag);
if(pkcs7==NULL)
{
ERR_print_errors_fp(stderr);
return NULL;
}


//共有两种编码,一种是ASN1,另一种是DER编码。
//取數據簽名(DER格式)
//openssl学习笔记之pkcs7-data内容类型的编码解码
//http://ipedo.i.sohu.com/blog/view/114822358.htm
//入口:pkcs7对象
//出口:der对象
unsigned char *der;
unsigned char *derTmp;
unsigned long derlen;
derlen = i2d_PKCS7(pkcs7,NULL);
der = (unsigned char *) malloc(derlen);
memset(der,0,derlen);
derTmp = der;
    i2d_PKCS7(pkcs7,&derTmp);


//DER转BASE64
return base64(der,derlen);
}


/*
功能:验证签名
入口:
char*certFile    证书(含匙)
char* plainText  明文
char* cipherText 签名
出口:
bool true  签名验证成功
bool false 验证失败
*/
bool PKCS7_VerifySign(char*certFile,char* plainText,char* cipherText )
{
/* Get X509 */
FILE* fp = fopen (certFile, "r");
if (fp == NULL) 
return false;
X509* x509 = PEM_read_X509(fp, NULL, NULL, NULL);
fclose (fp);


if (x509 == NULL) {
ERR_print_errors_fp (stderr);
return false;
}


//BASE64解码
unsigned char *retBuf[1024*8];
int retBufLen = sizeof(retBuf);
memset(retBuf,0,sizeof(retBuf));
decodeBase64(cipherText,(void *)retBuf,&retBufLen);


//从签名中取PKCS7对象
BIO* vin = BIO_new_mem_buf(retBuf,retBufLen);
PKCS7 *p7 = d2i_PKCS7_bio(vin,NULL);




//取STACK_OF(X509)对象
STACK_OF(X509) *stack=sk_X509_new_null();//X509_STORE_new()
sk_X509_push(stack,x509);




//明码数据转为BIO
BIO *bio = BIO_new(BIO_s_mem());  
BIO_puts(bio,plainText);


//验证签名
int err = PKCS7_verify(p7, stack, NULL,bio, NULL, PKCS7_NOVERIFY);


if (err != 1) {
ERR_print_errors_fp (stderr);
return false;
}


return true;
}


int  main(int argc, char* argv[])
{
char certFile[] = "demo.pfx";
char plainText[]= "Hello,World!";


InitOpenSSL();


//數字簽名
//PKCS7_NOCHAIN:签名中不包含证书链
//PKCS7_NOSMIMECAP:签名不需要支持SMIME
char * cipherText = PKCS7_GetSign(certFile,"11111111",plainText,PKCS7_DETACHED|PKCS7_NOSMIMECAP);


//打印出BASE64编码后的签名
std::cout<<cipherText<<std::endl;


//验证数字签名,BOC-CA.cer 为含有公钥的证书,最简单的验证是由p12转化为pem,如xxx.pem
if(PKCS7_VerifySign("BOC-CA.cer",plainText,cipherText))
std::cout<<"Verify OK!"<<std::endl;
else
std::cout<<"Verify Failed!"<<std::endl;

//释放签名字符串(缓存)
free(cipherText);


//输入任意字符继续
getchar();
return 0;
}


/*
关于OpenSSL的补充参考资料
[1]convert a PKCS 12 cert to PEM format .
http://blog.csdn.net/immcss/article/details/4443319
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenSSL是一个强大的密码库,包含了各种加密算法和工具,其中包括数字签名数字签名是一种用于验证消息真实性和完整性的技术。数字签名基于公钥加密和私钥解密的原理,通过对消息进行哈希运算,然后使用私钥对哈希值进行加密,生成数字签名。接收方使用公钥对数字签名进行解密,然后对接收到的消息进行哈希运算,并将哈希值与数字签名进行比较,从而验证消息的真实性和完整性。 使用OpenSSL实现数字签名的过程如下: 1. 生成公钥和私钥 使用OpenSSL生成RSA公钥和私钥对,其中私钥用于对消息进行签名,公钥用于验证签名。生成RSA公钥和私钥对的命令如下: ``` openssl genrsa -out private_key.pem 2048 openssl rsa -in private_key.pem -pubout -out public_key.pem ``` 2. 对消息进行哈希运算 使用OpenSSL对要签名的消息进行哈希运算,通常使用SHA1或SHA256算法进行哈希运算。以SHA256算法为例,对消息进行哈希运算的命令如下: ``` echo "message to be signed" | openssl dgst -sha256 > message.sha256 ``` 3. 使用私钥对哈希值进行加密,生成数字签名 使用OpenSSL使用私钥对哈希值进行加密,生成数字签名。生成数字签名的命令如下: ``` openssl rsautl -sign -inkey private_key.pem -in message.sha256 -out signature.sha256 ``` 4. 使用公钥对数字签名进行解密,验证签名 接收方使用OpenSSL使用公钥对数字签名进行解密,然后对接收到的消息进行哈希运算,并将哈希值与数字签名进行比较,从而验证签名。验证签名的命令如下: ``` openssl rsautl -verify -inkey public_key.pem -in signature.sha256 -pubin -in message.sha256 ``` 如果数字签名验证成功,则表示消息的真实性和完整性得到了保证。 需要注意的是,在使用OpenSSL进行数字签名时,需要保护私钥的安全性,避免私钥被泄露,从而导致数字签名被篡改。同时,需要保证公钥的准确性,避免使用错误的公钥验证数字签名

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值