openssl rsa加密签名

要使用rsa加密,本来准备在网上找rsa加密算法,但是找到的c源码都不太好用,后来搜索到openssl库有实现rsa算法的函数,就根据网上搜索的内容,自己封装了几个rsa加密API.

rsa算法原理说明网上有很多,大家可以自行搜索。

下面重点介绍openssl 下rsa加密的实现


参考文章:

http://blog.csdn.net/small_qch/article/details/19330211?utm_source=tuicool

http://www.cnblogs.com/aLittleBitCool/archive/2011/09/22/2185418.html

http://www.cppblog.com/sleepwom/archive/2010/01/11/105418.html

http://bbs.csdn.net/topics/360083130

http://blog.csdn.net/huyiyang2010/article/details/38066273

http://wenku.baidu.com/link?url=y-KjF6NakXZHVGYdjjcM6nRyyjLGZM43B7TbQRAMv2wMLNbdwSlXrrPGZ-RJEFCPNt5qMMtgIupK6qmB7rWZtJ6PhSZfF7i28vHYZohhCSO

http://bbs.csdn.net/topics/290034327

http://blog.csdn.net/sagely/article/details/367125


根据网上搜索及自己亲自代码调试,完成rsa加解密签名

1:输入命令,生成公钥和私钥(1024位)

openssl genrsa -out prikey.pem 1024
openssl rsa -in privkey.pem -pubout -out pubkey.pem

2.  c代码实现

/*
rsa.h
openssl genrsa -out prikey.pem 1024
openssl rsa -in prikey.pem -pubout -out pubkey.pem
*/
#include 
/*my_rsa_public_encrypt公钥加密与my_rsa_public_encrypt公钥解密配对
	公钥加密,读取pubkey.pem来做加密
	入参filename,保存公钥的文件名称,src待加密数据,加密数据长度
	出参des加密后数据,deslen加密数据长度
	src长度大于公钥长度时(RSA_size),会分段加密。
	加密结果des比src长度大,所以需要给des分配比src更大的空间
	例如密钥长度(RSA_size)为128,src长度为1~117,加密结果为128个字节。src长度为118~234,加密结果为256字节
*/
int my_rsa_public_encrypt(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen);
/*私钥解密,读取prikey.pem来做解密
入参filename,保存公钥的文件名称,src待解密数据,srclen解密数据长度
出参des解密后数据,deslen解密数据长度*/
int my_rsa_prikey_decrypt(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen);



/*my_rsa_prikey_encrypt私钥加密与my_rsa_public_decrypt公钥解密配对
	私钥加密,读取prikey.pem来做加密。
	入参filename,保存公钥的文件名称,src待加密数据,加密数据长度
	出参des加密后数据,deslen加密数据长度
	src长度大于公钥长度时(RSA_size),会分段加密。
	加密结果des比src长度大,所以需要给des分配比src更大的空间
	例如密钥长度(RSA_size)为128,src长度为1~117,加密结果为128个字节。src长度为118~234,加密结果为256字节
	因此des的长度,应该比 RSA_size*(strlen(src)/(RSA_size-11)+1)大才行。
*/
int my_rsa_prikey_encrypt(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen);
/*
	公钥解密,读取public.pem来做解密
	入参filename,保存公钥的文件名称,src待解密数据,srclen解密数据长度
	出参des解密后数据,deslen解密数据长度
*/
int my_rsa_public_decrypt(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen);

/* my_rsa_prikey_sign私钥签名
	入参filename,私钥文件名称;
			src待签名数据;
			srclen待签名数据长度
	出参des签名结果,返回结果长度为秘钥长度值,需分配比秘钥长度更大的空间,以免内存越界
			deslen签名结果长度,初始化为des数组大小
*/
int my_rsa_prikey_sign(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen);
/* my_rsa_public_verify公钥签名验证
	入参filename,公钥文件名称
			src待验数据;
			srclen待验数据长度
	    sign签名
			signlen签名长度
*/
int my_rsa_public_verify(char *filename,unsigned char *src,int srclen,unsigned char *sign,int signlen);

/* my_EVP_rsa_prikey_sign私钥签名,使用EVP
	入参filename,私钥文件名称;
			src待签名数据;
			srclen待签名数据长度
	出参des签名结果,返回结果长度为秘钥长度值,需分配比秘钥长度更大的空间,以免内存越界
			deslen签名数据长度,初始化为des数组大小
*/
int my_EVP_rsa_prikey_sign(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen);
/* my_EVP_rsa_public_verify公钥签名验证,使用EVP
	入参filename,公钥文件名称
			src待验数据;
			srclen待验数据长度
	    sign签名
			signlen签名长度
*/
int my_EVP_rsa_public_verify(char *filename,unsigned char *src,int srclen,unsigned char *sign,int signlen);
/*rsa.c*/
#include 
#include 
#include  
#include
#include
#include"rsa.h"
//公钥加密
int my_rsa_public_encrypt(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen)
{
	  int ret=0, isrclen=0,ideslen=0,i=0,n=0,ienclen=0,rsalen=0;
    if(filename==NULL || src==NULL || des==NULL)
    	return -1;

    RSA *r = RSA_new();

    FILE *fp=NULL;
    fp = fopen(filename, "rt" );
    if ( fp == NULL )
    {
    		printf("fopen [%s] error\n",filename);
    		return -2;
    }
    if(PEM_read_RSA_PUBKEY(fp,&r,0,0)==NULL)
    {
     		fclose( fp );
     		printf("PEM_read_RSA_PUBKEY error\n");
     		return -3;
    }
    fclose( fp );
     //RSA_print_fp(stdout, r, 5);  

		//加密数据最大长度,是秘钥长度-11,加密结果,是RSA_size的返回值。
    rsalen = RSA_size(r)-11;
    unsigned char *out = (unsigned char *)malloc(rsalen+12);
    
    n=srclen/rsalen;
    for(i=0;i<=n;i++)
    {
    	ienclen=(i!=n?rsalen:srclen%(rsalen));
    	if(ienclen==0)
    		break;
	    memset(out, 0, rsalen+12);
	    ret = RSA_public_encrypt(ienclen, src+isrclen, out, r,RSA_PKCS1_PADDING);
	    if (ret < 0)
	    {
	        printf("RSA_public_encrypt failed,ret is [%d]\n",ret);
	        return -4;
	    }
			
			isrclen+=ienclen;
			memcpy(des+ideslen,out,ret);
			ideslen+=ret;
		}
		des[ideslen]=0;
		*deslen=ideslen;		
		
   	free(out);
  	RSA_free(r);
    CRYPTO_cleanup_all_ex_data();
    
    return 0;
}
//私钥解密
int my_rsa_prikey_decrypt(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen)
{
	  int ret=0, isrclen=0,ideslen=0,i=0,n=0,ienclen=0,rsalen=0;
	  
    if(filename==NULL || src==NULL || des==NULL)
    	return -1;

    RSA *r = RSA_new();

    FILE *fp=NULL;
    fp = fopen(filename, "rt" );
    if ( fp == NULL )
    {
    		printf("fopen [%s] error\n",filename);
    		return -2;
    }
    if(PEM_read_RSAPrivateKey(fp,&r,0,0)==NULL)
    {
     		fclose( fp );
     		printf("PEM_read_RSAPrivateKey error\n");
     		return -3;
    }
    fclose( fp );
     //RSA_print_fp(stdout, r, 5);
		
		rsalen = RSA_size(r);
    unsigned char *out = (unsigned char *)malloc(rsalen+1);
    
    n=srclen/rsalen;
    for(i=0;i<=n;i++)
    {

    	ienclen=(i!=n?rsalen:srclen%(rsalen));
    	if(ienclen==0)
    		break;
	    memset(out, 0, rsalen+1);
	    ret = RSA_private_decrypt(ienclen, src+isrclen, out, r,RSA_PKCS1_PADDING);
	    if (ret < 0)
	    {
	        printf("RSA_private_decrypt failed,ret is [%d]\n",ret);
	        return -4;
	    }
			
			isrclen+=ienclen;
			memcpy(des+ideslen,out,ret);
			ideslen+=ret;
		}
		des[ideslen]=0;
		*deslen=ideslen;
		
   	free(out);
  	RSA_free(r);
    CRYPTO_cleanup_all_ex_data();
    
    return 0;
}


//私钥加密
int my_rsa_prikey_encrypt(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen)
{
	  int ret=0, isrclen=0,ideslen=0,i=0,n=0,ienclen=0,rsalen=0;
    if(filename==NULL || src==NULL || des==NULL)
    	return -1;

    RSA *r = RSA_new();

    FILE *fp=NULL;
    fp = fopen(filename, "rt" );
    if ( fp == NULL )
    {
    		RSA_free(r);
    		printf("fopen [%s] error\n",filename);
    		return -2;
    }
    if(PEM_read_RSAPrivateKey(fp,&r,0,0)==NULL)
    {
    		RSA_free(r);
     		fclose( fp );
     		printf("PEM_read_RSAPrivateKey error\n");
     		return -3;
    }
    fclose( fp );
     //RSA_print_fp(stdout, r, 5);
     //加密数据最大长度,是秘钥长度-11,加密结果,是RSA_size的返回值。
    rsalen = RSA_size(r)-11;
    unsigned char *out = (unsigned char *)malloc(rsalen+12);
    
    n=srclen/rsalen;
    for(i=0;i<=n;i++)
    {
    	ienclen=(i!=n?rsalen:srclen%(rsalen));
    	if(ienclen==0)
    		break;
	    memset(out, 0, rsalen+12);
	    ret = RSA_private_encrypt(ienclen, src+isrclen, out, r,RSA_PKCS1_PADDING);
	    if (ret < 0)
	    {
	    	  free(out);
  				RSA_free(r);
	        printf("RSA_private_encrypt failed,ret is [%d]\n",ret);
	        return -4;
	    }
			
			isrclen+=ienclen;
			memcpy(des+ideslen,out,ret);
			ideslen+=ret;
		}
		des[ideslen]=0;
		*deslen=ideslen;
   	free(out);
  	RSA_free(r);
    CRYPTO_cleanup_all_ex_data();
    
    return 0;
}
//公钥解密
int my_rsa_public_decrypt(char *filename,unsigned char *src,int srclen,unsigned char *des,int *deslen)
{
	  int ret=0, isrclen=0,ideslen=0,i=0,n=0,ienclen=0,rsalen=0;
	 
    if(filename==NULL || src==NULL || des==NULL)
    	return -1;

    RSA *r = RSA_new();

    FILE *fp=NULL;
    fp = fopen(filename, "rt" );
    if ( fp == NULL )
    {
    		RSA_free(r);
    		printf("fopen [%s] error\n",filename);
    		return -2;
    }
    if(PEM_read_RSA_PUBKEY(fp,&r,0,0)==NULL)
    {
    		RSA_free(r);
     		fclose( fp );
     		printf("PEM_read_RSA_PUBKEY error\n");
     		return -3;
    }
    fclose( fp );
     //RSA_print_fp(stdout, r, 5);
		rsalen = RSA_size(r);
    unsigned char *out = (unsigned char *)malloc(rsalen+1);
    
    n=srclen/rsalen;
    for(i=0;i<=n;i++)
    {

    	ienclen=(i!=n?rsalen:srclen%(rsalen));
    	if(ienclen==0)
    		break;
	    memset(out, 0, rsalen+1);
	    ret = RSA_public_decrypt(ienclen, src+isrclen, out, r,RSA_PKCS1_PADDING);
	    if (ret < 0)
	    {
	    	  free(out);
  				RSA_free(r);
	        printf("RSA_public_decrypt failed,ret is [%d]\n",ret);
	        return -4;
	    }
			
			isrclen+=ienclen;
			memcpy(des+ideslen,out,ret);
			ideslen+=ret;
		}
		des[ideslen]=0;
		*deslen=ideslen;
		
   	free(out);
  	RSA_free(r);
    CRYPTO_cleanup_all_ex_data();
    
    return 0;
}


//私钥签名
int my_rsa_prikey_sign(char *filename,unsigned char *src,int srclen,unsigned char *sign,int *signlen)
{
		int ret=0, isrclen=0,ideslen=0,i=0,n=0,ienclen=0,rsalen=0;
		
    if(filename==NULL || src==NULL || sign==NULL)
    	return -1;
    
		unsigned char hash[SHA_DIGEST_LENGTH]="";
		//unsigned sign_len = sizeof( sign );
    RSA *rsa_pri_key = RSA_new();

    FILE *fp=NULL;
    fp = fopen(filename, "rt" );
    if ( fp == NULL )
    {
    		RSA_free(rsa_pri_key);
    		printf("fopen [%s] error\n",filename);
    		return -2;
    }
    if(PEM_read_RSAPrivateKey(fp,&rsa_pri_key,0,0)==NULL)
    {
    		RSA_free(rsa_pri_key);
     		fclose( fp );
     		printf("PEM_read_RSAPrivateKey error\n");
     		return -3;
    }
    fclose( fp );
    
    
    SHA1(src,srclen,hash);

    ret = RSA_sign(NID_sha1,hash,SHA_DIGEST_LENGTH,sign,signlen,rsa_pri_key);
    if(1!=ret)
    {
    	RSA_free(rsa_pri_key);
   		printf("RSA_sign err,r is [%d],sign_len is [%d]\n",ret,signlen);
   		return -4;
   	}
   	
    RSA_free(rsa_pri_key);
		return 0;
}
//公钥签名验证
int my_rsa_public_verify(char *filename,unsigned char *src,int srclen,unsigned char *sign,int signlen)
{
		int ret=0, isrclen=0,ideslen=0,i=0,n=0,ienclen=0,rsalen=0;
	 	
    if(filename==NULL || src==NULL || sign==NULL)
    	return -1;
		
		unsigned char hash[SHA_DIGEST_LENGTH]="";
    RSA *rsa_pub_key=RSA_new();

    FILE *fp=NULL;
    fp = fopen(filename, "rt" );
    if ( fp == NULL )
    {
    		RSA_free(rsa_pub_key);
    		printf("fopen [rsa_private_key] error\n");
    		return -2;
    }
    if(!PEM_read_RSA_PUBKEY(fp,&rsa_pub_key,0,0))
    {
    	  RSA_free(rsa_pub_key);
     		fclose( fp );
     		printf("PEM_read_RSAPrivateKey error\n");
     		return -3;
    }
    fclose( fp );
    
    SHA1(src,srclen,hash);
    ret = RSA_verify( NID_sha1,hash,SHA_DIGEST_LENGTH,sign,signlen,rsa_pub_key);
    if(1!=ret)
    {
    	 RSA_free(rsa_pub_key);
       printf("RSA_verify err,ret is [%d],sign_len is [%d]\n",ret,signlen);
   		 return -4;
    }
 		printf("RSA_verify ok\n");

		RSA_free(rsa_pub_key);

    
	 return 0;
}
//私钥签名EVP
int my_EVP_rsa_prikey_sign(char *filename,unsigned char *src,int srclen,unsigned char *sign,int *signlen)
{
			int ret=0, isrclen=0,ideslen=0,i=0,n=0,ienclen=0,rsalen=0;
	 	
    if(filename==NULL || src==NULL || sign==NULL)
    	return -1;

	  //RSA结构体变量
		RSA *rsa_pri_key=RSA_new();
		
		FILE *fp=NULL;
    fp = fopen(filename, "rt" );
    if ( fp == NULL )
    {
    		printf("fopen [rsa_private_key] error\n");
    		return;
    }
    if(!PEM_read_RSAPrivateKey(fp,&rsa_pri_key,0,0))
    {
     		fclose( fp );
     		printf("PEM_read_RSAPrivateKey error\n");
     		return;
    }
    fclose( fp );
		
		//新建一个EVP_PKEY变量
		EVP_PKEY *evpKey=EVP_PKEY_new();
		
		if(evpKey==NULL)
		{  
			 printf("EVP_PKEY_new err\n");
		   RSA_free(rsa_pri_key);
		   return; 
		}   
		if(EVP_PKEY_set1_RSA(evpKey,rsa_pri_key) != 1)   //保存RSA结构体到EVP_PKEY结构体  
		{    
				printf("EVP_PKEY_set1_RSA err\n");
				RSA_free(rsa_pri_key);
				EVP_PKEY_free(evpKey);
				return;
		}
		//摘要算法上下文变量  
		EVP_MD_CTX mdctx;
		//以下是计算签名代码   
		EVP_MD_CTX_init(&mdctx);
		//初始化摘要上下文   
		if(!EVP_SignInit_ex(&mdctx, EVP_sha1(), NULL)) //签名初始化,设置摘要算法,本例为sha1  
		{    
				printf("err\n");
				EVP_PKEY_free(evpKey);
				RSA_free(rsa_pri_key);
				return;
		}
		if(!EVP_SignUpdate(&mdctx, src, srclen)) //计算签名(摘要)Update
		{    
				printf("err\n");
				EVP_PKEY_free(evpKey);
				RSA_free(rsa_pri_key);
				return;
		}
		if(!EVP_SignFinal(&mdctx,sign,signlen,evpKey)) //签名输出  
		{    
				printf("err\n");
				EVP_PKEY_free(evpKey);
				RSA_free(rsa_pri_key);
				return;
		}
    /*printf("消息\"%s\"的签名值是: \n",src);
		for(i = 0; i < *signlen; i++)  
		{    
				if(i%16==0)    
				 printf("\n%08xH: ",i);
		    printf("%02x ", sign[i]);
		}
		printf("\n");   
    */
		//释放内存
		EVP_PKEY_free(evpKey);
		RSA_free(rsa_pri_key);
		EVP_MD_CTX_cleanup(&mdctx);
}
//公钥签名EVP验证
int my_EVP_rsa_public_verify(char *filename,unsigned char *src,int srclen,unsigned char *sign,int signlen)
{
		int ret=0, isrclen=0,ideslen=0,i=0,n=0,ienclen=0,rsalen=0;
	 	
    if(filename==NULL || src==NULL || sign==NULL)
    	return -1;
		
		//摘要算法上下文变量 
		EVP_MD_CTX mdctx;
		
    RSA *rsa_pub_key=RSA_new();

    //rsa_public_key测试
    FILE *fp=NULL;
    fp = fopen(filename, "rt" );
    if ( fp == NULL )
    {
    		printf("fopen [rsa_private_key] error\n");
    		return -2;
    }
    if(!PEM_read_RSA_PUBKEY(fp,&rsa_pub_key,0,0))
    {
     		fclose( fp );
     		printf("PEM_read_RSAPrivateKey error\n");
     		return -3;
    }
    fclose( fp );
    
    EVP_PKEY *pubKey=EVP_PKEY_new();
		//新建一个EVP_PKEY变量
		if(pubKey==NULL)
		{  
			 printf("EVP_PKEY_new err\n");
		   RSA_free(rsa_pub_key);
		   return -4; 
		}
		if(EVP_PKEY_set1_RSA(pubKey,rsa_pub_key) != 1)   //保存RSA结构体到EVP_PKEY结构体  
		{    
				printf("EVP_PKEY_set1_RSA err\n");
				RSA_free(rsa_pub_key);
				EVP_PKEY_free(pubKey);
				return -5;
		}
    
   // printf("\n正在验证签名...\n");
    //以下是验证签名代码   
    EVP_MD_CTX_init(&mdctx);
    //初始化摘要上下文   
    if(!EVP_VerifyInit_ex(&mdctx, EVP_sha1(), NULL))  //验证初始化,设置摘要算法,一定要和签名一致。  
		{    
			 printf("EVP_VerifyInit_ex err\n");
		   EVP_PKEY_free(pubKey);
		   RSA_free(rsa_pub_key);
		   return -6;
		}
		if(!EVP_VerifyUpdate(&mdctx,src,srclen))
		//验证签名(摘要)Update
		{
				printf("err\n");
				EVP_PKEY_free(pubKey);
				RSA_free(rsa_pub_key);
				return -7;
		}
		if(!EVP_VerifyFinal(&mdctx,sign,signlen,pubKey))//验证签名
		{
				printf("verify err\n");
				EVP_PKEY_free(pubKey);
				RSA_free(rsa_pub_key);
				return -8;
		}
		//else
		//{
			//	printf("验证签名正确.\n");
		//}
    
    EVP_PKEY_free(pubKey);
		RSA_free(rsa_pub_key);
		EVP_MD_CTX_cleanup(&mdctx);
    
	 return 0;
}

/*main.c*/
#include
#include
#include"rsa.h"

int main(char agrc,char *argv)
{


char out[1024]="abcdefghigklmnopqrstuvwsyz";
char rsa[1024]="";
int outlen=0,rsalen=0;
int ret=0;
printf("out [%s]\n",out);
/* ret=my_rsa_prikey_encrypt("prikey.pem",out,strlen(out),rsa,&rsalen);
if(ret<0)
{
printf("my_rsa_prikey_encrypt err [%d]\n",ret);
return -1;
}
printf("my_rsa_prikey_encrypt ok,rsalen is [%d]\n",rsalen);
memset(out,0,sizeof(out));
ret=my_rsa_public_decrypt("pubkey.pem",rsa,rsalen,out,&outlen);
if(ret<0)
{
printf("my_rsa_public_decrypt err [%d]\n",ret);
return -2;
}
*/

ret=my_rsa_public_encrypt("pubkey.pem",out,strlen(out),rsa,&rsalen);
if(ret<0)
{
printf("my_rsa_public_encrypt err [%d]\n",ret);
return -1;
}
printf("my_rsa_prikey_encrypt ok,rsalen is [%d]\n",rsalen);
memset(out,0,sizeof(out));
ret=my_rsa_prikey_decrypt("prikey.pem",rsa,rsalen,out,&outlen);
if(ret<0)
{
printf("my_rsa_prikey_decrypt err [%d]\n",ret);
return -2;
}


printf("out [%s]\n",out);
return 0;
}


3.开发过程遇到的问题

  3.1 读取公钥时,使用函数PEM_read_RSA_PUBKEY才能读取成功,使用PEM_read_RSAPublicKey是无法读取的。

 3.2 待加密的数据过长时,需要分段加密。在第一步时生成的密钥长度时1024,1024位=1024bit=128byte,用RSA_size函数得出的是128,

而待加密的数据需要比128小11个字节,所以是117.


你可能感兴趣的:(c)