使用openssl中的RSA加密解密
1. 概念理解
RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。
2. openssl中的RSA使用
linux控制台下openssl工具的简单使用:
1)安装openssl
sudo apt-get install libssl-dev
2)生成一个密钥:
openssl genrsa -out test.key 1024
这里-out指定生成文件的,即私钥,后面的1024是生成密钥的长度。
3)openssl可以将这个文件中的公钥提取出来:
openssl rsa -in test.key -pubout -out test_pub.key
-in指定输入文件,-out指定提取生成公钥的文件名。现在得到了公钥test_pub.key,私钥test.key。
4)在目录中创建一个hello的文本文件,然后利用此前生成的公钥加密文件:
openssl rsautl -encrypt -in hello -inkey test_pub.key -pubin -out hello.en
-in指定要加密的文件,-inkey指定密钥,-pubin表明是用纯公钥文件加密,-out为加密后的文件。
5)解密文件:
openssl rsautl -decrypt -in hello.en -inkey test.key -out hello.de
-in指定被加密的文件,-inkey指定私钥文件,-out为解密后的文件。
至此,一次加密解密的过程告终。
3. C语言使用RSA加密解密
使用C语言加密解密时,公钥密钥必须按照64个字节一换行的形式传入,如下面代码所示,在文件中调用也要按照64个字节换行保存。以下代码实现对输入的字符串公钥加密,base64编码,然后base64解码,再用私钥解密。一般通信中,加密解密分别在两端执行。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<openssl/rsa.h>
#include<openssl/pem.h>
#include<openssl/err.h>
#include<openssl/bio.h>
#include<openssl/evp.h>
#define RSAPUBKEY
#define KEYFORMFILE 1
#define KEYFORMMEM 2
#define KEYFORM KEYFORMMEM //内存导入
//#define KEYFORM KEYFORMFILE //文件导入
#define PRIVATEKEY "key.pem"
#define PUBLICKEY "key_pub.pem"
/*
2020年11月11日
rsa 加密解密
base64 编码解码
通过给定私钥 公钥完成加密解密
公钥私钥放在内存或文件中
*/
int rsa_pub_encrypt(char *str,char *path_key,char** outstr);
int rsa_prv_decrypt(char *str,char *path_key,int inlen,char** outstr);
char* pubkey="-----BEGIN PUBLIC KEY-----\n\
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv1Gt1Q3FCo9rgwR1+bsR\
qaInU+2OFnoYdhp2189doeAwP+XH3LLBnxeDRfH1PZKrvEFtKBWaB2112lN4dL/T\
/dSOezszKHPTSg0PaxW4F+ooAY0gTQWGSuSMcY8H4RpkI7sNFFfOYQZYT0albs+e\
RepaHtfQCfM/cFTmpHVDXqdK4uCRNZbhff2+5oEN/j0eW5t4aq+G+Qu1gz9poH5B\
uqea69foG4LRcnwVKCXz+5ZrzE2YWYayvCEgpojXmkLcemvWkJD+K0SUsKoZ/7Wn\
vMBg1mfkSlNTFzpDgKjYESnnUgUobwDtBT9Wdq0RHVVTyZLh4CvZMeS1NcHBqDxp\
PQIDAQAB\
\n-----END PUBLIC KEY-----\n";
char* prikey="-----BEGIN RSA PRIVATE KEY-----\n\
MIIEogIBAAKCAQEAv1Gt1Q3FCo9rgwR1+bsRqaInU+2OFnoYdhp2189doeAwP+XH\
3LLBnxeDRfH1PZKrvEFtKBWaB2112lN4dL/T/dSOezszKHPTSg0PaxW4F+ooAY0g\
TQWGSuSMcY8H4RpkI7sNFFfOYQZYT0albs+eRepaHtfQCfM/cFTmpHVDXqdK4uCR\
NZbhff2+5oEN/j0eW5t4aq+G+Qu1gz9poH5Buqea69foG4LRcnwVKCXz+5ZrzE2Y\
WYayvCEgpojXmkLcemvWkJD+K0SUsKoZ/7WnvMBg1mfkSlNTFzpDgKjYESnnUgUo\
bwDtBT9Wdq0RHVVTyZLh4CvZMeS1NcHBqDxpPQIDAQABAoIBAGleFLzoLoMYZf/s\
bwUxEBM66SoCBWU/rUUuYhGNdWX30NsANEjKcnSqQHQ/Q++7XbX62qFe9Evu7x9l\
JUw3cgu0Cxy3h/9Zex6nfrxdY9xX69ye2xFQX5vTr73DJnXFUS2UkSmJCnLJSc2v\
fOFAm0yqOyQNe9hfDatSNwyQQKBZ0iiBP4DMfZyW0L0uREDb1Zex4PL5EMt9dlNh\
m6rObetXBXU9Fu1UFSbH2BFzjbsgCJ/kr2ty3hwTv8ygFrNrFJtDfEGdln6vmIiE\
Lbq12UElXtKi2Ko+uulzILFNSSHzi7aJt0y+szBnXkF0XVirvBgIEGCQvL2ynf5O\
Vr96N0kCgYEA7ixwmmjevu4zvcW2nVrXbV+0H0088OKKJMrs92daECL1H/lRCAxI\
MOK6nXEgPy6siMPbErPt3j2bj63HAZVXMfkv4xhn5kCbbhqxS6EsBwoy3hH8Mg9a\
EIbIurdtIZPaElC/nMbD8EoLZpruNhuezQJpsJOm9zIswpj5SYLmEIsCgYEAzaN5\
2eAyEWPTf8Jd+EwhHfGYRnvdNCnlO1G4mbY5w6UU0grko1uuE7XzCfDYAeRgqUHc\
FDFcj3K/wTofj/KqcUBATy7WolkQOc5TF9P6z8HBPpCaxIHgIT3xMzCLSeSlZkK5\
5MBEl0kCGYdTOhGFlQkmNfYb9b3Y3AmJ3NVlnlcCgYA2w3ccufJFmoXBI93qboHM\
P04uSFcz2BMFhLdZ56S4wyDzuiLco95Rh0B7hRByFqxLQiV0NnUCPc4wCjgQ8CK9\
dduB7xGsyrwyY+bSSfvSnpC1qRMA+7CsziEHdbedGd7xiSmVxco1zQC0Ffmh7VXl\
M6HTnQ+uFRZfpEbllTiLIwKBgGW2lm7OFfXECrkGyrQl87t75HX4jlFe56OPqF9f\
YvMClGnQOYcTsebN+IjSOAW3kJgnm1PhlobdmztYJIRu4x9hSG3iHQfwRbZR94ex\
sj1Q+OSZYfQQyWun18YaHMtP7P/HwWsELuklk4RNCz2NrSUqgVvvf6TtYnZzwV0Z\
sEnBAoGAF7be2xB6tDoGic/oKahwbR9rviur7zKA+LPapeRwxXElWYCE2ON1NUlF\
+Z+5ajqGjUtQWXDCPqaLO5gSPipPHxX6tYIeolk1C5veZBkeHgG4TLMuIxtpGayw\
6/P3Pru8xzm8gZZTYqpmnFoXS6gQ2sNtrbyLJNNzH9bUNH7diVU=\
\n-----END RSA PRIVATE KEY-----\n";
static int do_operation(RSA* rsa_ctx,char *instr,char* path_key,int inlen,char** outstr,int type)
{
if(rsa_ctx == NULL || instr == NULL || path_key == NULL)
{
perror("input elems error,please check them!");
return -1;
}
int rsa_len,num;
rsa_len=RSA_size(rsa_ctx);
*outstr=(unsigned char *)malloc(rsa_len+1);
memset(*outstr,0,rsa_len+1);
switch(type){
case 1: //pub enc
if(inlen == 0){
perror("input str len is zero!");
goto err;
}
num = RSA_public_encrypt(inlen,(unsigned char *)instr,(unsigned char*)*outstr,rsa_ctx,RSA_PKCS1_PADDING);
break;
case 2: //prv dec
num = RSA_private_decrypt(inlen,(unsigned char *)instr,(unsigned char*)*outstr,rsa_ctx,RSA_PKCS1_PADDING);
break;
default:
break;
}
if(num == -1)
{
printf("Got error on enc/dec!\n");
err:
free(*outstr);
*outstr = NULL;
num = -1;
}
return num;
}
int rsa_pub_encrypt(char *str,char *path_key,char** outstr)
{
RSA *p_rsa;
BIO *bio = NULL;
FILE *file;
int flen,rsa_len,num;
#if KEYFORM==KEYFORMFILE
if((file=fopen(path_key,"r"))==NULL){
perror("open key file error");
return -1;
}
#else
if ((bio = BIO_new_mem_buf(pubkey, -1)) == NULL) //从字符串读取RSA公钥
{
perror("BIO_new_mem_buf failed!");
}
#endif
#ifdef RSAPUBKEY
#if KEYFORM==KEYFORMFILE
if((p_rsa=PEM_read_RSA_PUBKEY(file,NULL,NULL,NULL))==NULL){
#else
if((p_rsa=PEM_read_bio_RSA_PUBKEY(bio,NULL,NULL,NULL))==NULL){
#endif
#else
if((p_rsa=PEM_read_RSAPublicKey(file,NULL,NULL,NULL))==NULL){
#endif
ERR_print_errors_fp(stdout);
return -1;
}
num = do_operation(p_rsa,str,path_key,strlen(str),outstr,1);
RSA_free(p_rsa);
#if KEYFORM==KEYFORMFILE
fclose(file);
#else
BIO_free_all(bio);
#endif
return num;
}
int rsa_prv_decrypt(char *str,char *path_key,int inlen,char** outstr)
{
RSA *p_rsa;
BIO *bio = NULL;
FILE *file;
int rsa_len,num;
#if KEYFORM==KEYFORMFILE
if((file=fopen(path_key,"r"))==NULL){
perror("open key file error");
return -1;
}
#else
if ((bio = BIO_new_mem_buf(prikey, -1)) == NULL) //从字符串读取RSA公钥
{
perror("BIO_new_mem_buf failed!");
}
#endif
#if KEYFORM==KEYFORMFILE
if((p_rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL))==NULL){
#else
if((p_rsa=PEM_read_bio_RSAPrivateKey(bio,NULL,NULL,NULL))==NULL){
#endif
ERR_print_errors_fp(stdout);
return -1;
}
num = do_operation(p_rsa,str,path_key,inlen,outstr,2);
RSA_free(p_rsa);
#if KEYFORM==KEYFORMFILE
fclose(file);
#else
BIO_free_all(bio);
#endif
return num;
}
unsigned char *base64_encode(unsigned char *str,int strlen)
{
long len;
long str_len;
unsigned char *res;
int i,j;
//定义base64编码表
unsigned char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//计算经过base64编码后的字符串长度
str_len=strlen;
if(str_len % 3 == 0)
len=str_len/3*4;
else
len=(str_len/3+1)*4;
res=malloc(sizeof(unsigned char)*len+1);
res[len]='\0';
//以3个8位字符为一组进行编码
for(i=0,j=0;i<len-2;j+=3,i+=4)
{
res[i]=base64_table[str[j]>>2]; //取出第一个字符的前6位并找出对应的结果字符
res[i+1]=base64_table[(str[j]&0x3)<<4 | (str[j+1]>>4)]; //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符
res[i+2]=base64_table[(str[j+1]&0xf)<<2 | (str[j+2]>>6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符
res[i+3]=base64_table[str[j+2]&0x3f]; //取出第三个字符的后6位并找出结果字符
}
switch(str_len % 3)
{
case 1:
res[i-2]='=';
res[i-1]='=';
break;
case 2:
res[i-1]='=';
break;
}
return res;
}
unsigned char *base64_decode(unsigned char *code,int *codelen)
{
//根据base64表,以字符找到对应的十进制数据
int table[]={0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,62,0,0,0,
63,52,53,54,55,56,57,58,
59,60,61,0,0,0,0,0,0,0,0,
1,2,3,4,5,6,7,8,9,10,11,12,
13,14,15,16,17,18,19,20,21,
22,23,24,25,0,0,0,0,0,0,26,
27,28,29,30,31,32,33,34,35,
36,37,38,39,40,41,42,43,44,
45,46,47,48,49,50,51
};
long len;
long str_len;
unsigned char *res;
int i,j;
//计算解码后的字符串长度
len=strlen(code);
//判断编码后的字符串后是否有=
if(strstr(code,"=="))
str_len=len/4*3-2;
else if(strstr(code,"="))
str_len=len/4*3-1;
else
str_len=len/4*3;
res=malloc(sizeof(unsigned char)*str_len+1);
res[str_len]='\0';
*codelen=str_len;
//以4个字符为一位进行解码
for(i=0,j=0;i < len-2;j+=3,i+=4)
{
res[j]=((unsigned char)table[code[i]])<<2 | (((unsigned char)table[code[i+1]])>>4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的后2位进行组合
res[j+1]=(((unsigned char)table[code[i+1]])<<4) | (((unsigned char)table[code[i+2]])>>2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应bas464表的十进制数的后4位进行组合
res[j+2]=(((unsigned char)table[code[i+2]])<<6) | ((unsigned char)table[code[i+3]]); //取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合
}
return res;
}
int main(int argc,char** argv)
{
char *ptr_en=NULL,*ptr_de=NULL;
char *ptr_enbase=NULL,*ptr_debase=NULL;
int len;
int decode_len;
char abyInStr[] = "this is my rsa test";
printf("Input String[%d]:\n%s\n",strlen(abyInStr), abyInStr);
//加密
len=rsa_pub_encrypt(abyInStr,PUBLICKEY,&ptr_en);
printf("rsa_pub_encrypt[%d]\n", len);
//64编码
ptr_enbase=base64_encode(ptr_en,len);
printf("base64_encode[%d]:\n%s\n",strlen(ptr_enbase), ptr_enbase);
//64解码
ptr_debase=base64_decode(ptr_enbase,&decode_len);
printf("base64_decode[%d]\n", decode_len);
//解密
rsa_prv_decrypt(ptr_debase,PRIVATEKEY,len,&ptr_de);
printf("Output String[%d]:\n%s\n",strlen(ptr_de), ptr_de==NULL?"NULL":ptr_de);
if(ptr_enbase!=NULL){
free(ptr_enbase);
}
if(ptr_debase!=NULL){
free(ptr_debase);
}
if(ptr_en!=NULL){
free(ptr_en);
}
if(ptr_de!=NULL){
free(ptr_de);
}
return 0;
}
以上代码在linux下编译运行正常,编译时指定链接库-lcrypto
gcc test.c -lcrypto -o test
运行效果如下
参考:
https://blog.csdn.net/yyxyong/article/details/77827870
https://blog.csdn.net/u011983700/article/details/108240200