欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

c语言 通过openssl进行rsa的加密和解密

程序员文章站 2022-07-12 23:02:19
...

参考资料

https://blog.csdn.net/enjoyinwind/article/details/23530303

https://blog.csdn.net/stormbjm/article/details/46898757

   

    最近项目中需要用到RSA加密,网上这方面的资料很多,研究了一番,发现直接用openssl的rsa接口非常方便,可以直接通过别人提供的公钥私钥进行加密解密,也可以通过openssl生成**对将公钥提供给别人使用。

    具体的RSA加密原理就不在这里赘述,直接上代码,代码参考上面两个链接。

    其中的重点记录一下哈:

    问题1,openssl提供了bio接口以支持各种形式的秘钥读取。在使用bio接口从内存中读取pem格式的公钥时,总是读取公钥失败,经不断查找资料,发现在我们得到base64编码的RSA公钥后,从内存中读取这个公钥时要注意以下几点:(1)公钥字符串开头要加上“-----BEGIN PUBLIC KEY-----\n”,结尾加上“\n-----END PUBLIC KEY-----\n”。否则会出现error:0906D06C:PEM routines:PEM_read_bio:no start line(2)公钥字符串每隔64个字符要加一个换行,否则会报秘钥格式错误。

    问题2,PEM_read_RSA_PUBKEY()函数和PEM_read_RSAPublicKEY()的疑惑。为什么读取私钥文件用的PEM_read_RSAPrivateKey(),针对上述openssl命令生成的公钥文件,在读取其内容时用对称的PEM_read_RSAPublicKEY()接口却会报错,必须要用PEM_read_RSA_PUBKEY()才可以。 原因是生成公钥时要把-pubout参数改成-RSAPublicKey_out

 

    目前支持两种模式获取公钥和私钥。第一种方式比较常用,直接通过文件获取公私钥。第二种方式通过内存获取,这种方式比较灵活,可以将**保存在数据库,文件,甚至直接写在代码里,只要使用的时候将其转成对应格式的字符串即可。

    另外,由于通过rsa加密以后的二进制密文有时候不太方便传输,所以一般会将其通过base64进行编码然后再进行传输。

    在进行代码开发前,首先需要安装openssl库,ubuntu下直接执行一下命令即可。

sudo apt-get install libssl-dev

    rsa.h

#ifndef _RSA_H
#define _RSA_H

#define PRIVATEKEY "key.pem"
#define PUBLICKEY "key_pub.pem"

int rsa_pub_encrypt(char *str,char *path_key,char** outstr);
int rsa_prv_decrypt(char *str,char *path_key,int inlen,char** outstr);

#endif

  rsa.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<openssl/rsa.h>
#include<openssl/pem.h>
#include<openssl/err.h>
#include "rsa.h"

#define RSAPUBKEY
#define KEYFORMFILE 1
#define KEYFORMMEM	2
#define KEYFORM	KEYFORMMEM


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;
}
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";

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;
}

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";

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;
}

base64.h

/*base64.h*/
#ifndef _BASE64_H
#define _BASE64_H

#include <stdlib.h>
#include <string.h>

unsigned char *base64_encode(unsigned char *str,int strlen);

unsigned char *base64_decode(unsigned char *code,int *codelen);

#endif

base64.c

/*base64.c*/
#include "base64.h"

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;

}

main.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "base64.h"
#include "rsa.h"
//#include "aes.h"

void ras_test()
{
    char *ptr_en=NULL,*ptr_de=NULL;
    char *ptr_enbase=NULL,*ptr_debase=NULL;
    int len;

    len=rsa_pub_encrypt("abcd1234",PUBLICKEY,&ptr_en);
    printf("pubkey encrypt=%d:\n",len);

    ptr_enbase=base64_encode(ptr_en,len);
    printf("base64_encode len=%d\n",strlen(ptr_enbase));
    printf("%s\n",ptr_enbase);

    int decode_len;
    ptr_debase=base64_decode("JqdnYAhiZbXNV+h7t3jSj6DcYRwQevRjyz9qg4H7m"
    		"JizgXnUAZ0saWIwrVf+5p+TTTlLzadfSVgM4NtMsqO1kRD/M15u3j/"
    		"009KoKXPa3PZQI3o+r8tkaVloG+LMGt4IndI2jZdZ5gFv8gFQUdkoZ"
    		"jiuXa3NWnX99909dN/l0c8LTyNVF+mKt8EP8nEo6ICq/9sMl0qI8v5"
    		"DiXHRurtJVewH/2+iofAACidXlvihvQsWgt+KDntCwl2+lo+F+Fmcx"
    		"dlntnsPZVibgIYS+Mjoged4782Agp6srMyNsCmarE+mSeyhA3ywK0T"
    		"srUEQoKm3qJVD6XPXVbAO5B6MCVFd0Q==",&decode_len);
    printf("decode_len=%d\n",decode_len);

    rsa_prv_decrypt(ptr_debase,PRIVATEKEY,len,&ptr_de);
    printf("prvkey decrypt:%s\n",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);
    }
}

int main(int argc,char** argv)
{
	ras_test();

    return 0;
}

 

相关标签: rsa c base64