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加解密签名
/*
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.