openssl rsa非对称加密

背景:

为了实现java与C之间的通信数据rsa加密,研究了rsa的加密方式。

java端使用代码生成的公钥、私钥文件格式都是PKCS#8格式的,使用openssl上面的命令生成的公钥、私钥都是PKCS1格式的,哪怕转成pkcs8格式的,java那边也解不出来,不知道为什么。

所以,最后使用的公钥、私钥都是java那边生成的,C语言这边使用的openssl接口不区分是pkcs1、pkcs8格式,都是支持的。

 

补充说明:

1、java生成的公私钥格式为pkcs8,而openssl默认生成的公私钥格式为pkcs1,两者的密钥实际上是不能直接互用的。

2、java采用的rsa默认补齐方式是pkcs1,因此互用的时候需要将openssl中的补齐方式设置为RSA_PKCS1_PADDING。

3、rsa加密中,加密数据长度有限制,不能超过密钥长度-11字节(如1024位的密钥,数据长度最长为117字节);密文长度为密钥的字节数(1024位的密钥,加密后的密文长度就是128字节)。

 

RSA加密常用的填充方式有下面3种:

1.RSA_PKCS1_PADDING 填充模式,最常用的模式

要求:

输入:必须 比 RSA 钥模长(modulus) 短至少11个字节, 也就是 RSA_size(rsa) – 11

如果输入的明文过长,必须切割,然后填充

输出:和modulus一样长

 

根据这个要求,对于512bit的密钥, block length = 512/8 – 11 = 53 字节

 

2.RSA_PKCS1_OAEP_PADDING

输入:RSA_size(rsa) – 41

输出:和modulus一样长

 

3.for RSA_NO_PADDING  不填充

输入:可以和RSA钥模长一样长,如果输入的明文过长,必须切割, 然后填充

输出:和modulus一样长

 

第一步:先下载openssl压缩包,通过openssl官网下载之后的压缩包为openssl-1.1.1h.tar.gz。解压,编译,安装,最后需要的是openssl-1.1.1h中的include头文件以及libcrypto.so,libssl.so动态库。

 

openssl官网:

https://www.openssl.org/source/

 

 

第二步:编码

/*rsaEncDec.h*/
#ifndef _RSAENCDEC_H_
#define _RSAENCDEC_H_

#include <stdio.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>

#define MINLEN 128
#define MIDLEN 1024
#define MAXLEN 4096

/*java生成的公钥文件*/
const char PUBLIC_KEY_FILE[MINLEN] = "./publicKey.keystore";
/*java生成的私钥文件*/
const char PRIVATE_KEY_FILE[MINLEN] = "./privateKey.keystore";

void read_publickey_content(char* pubkey);
void PubKeyPEMFormat(char* pubkey);
void PublicEncrypt(char* in_plain, char* cipher);
void PrivKeyPEMFormat(char* privkey);
int Base64Encode(const char* encoded, int encodedLength, char* decoded);
int Base64Decode(const char* encoded, int encodedLength, char* decoded);

#endif // !_RSAENCDEC_H_
/*rsaEncDec.c*/
#include "rsaEncDec.h"

/****************************************************************
* function name 		: read_publickey_content
* functional description	: 读取公钥文件内容
* input parameter		: pubkey:存放读取公钥的内容
* output parameter	: None
* return value:  None
* history	:
*****************************************************************/
void read_publickey_content(char* pubkey)
{
	FILE* fp = fopen(PUBLIC_KEY_FILE, "rb");
	if (fp == NULL)
	{
		printf("open file error\n");
		return;
	}
	fread(pubkey, MIDLEN, 1, fp);
	fclose(fp);
}
/****************************************************************
* function name 		: read_privatekey_content
* functional description	: 读取私钥文件内容
* input parameter		: pubkey:存放读取公钥的内容
* output parameter	: None
* return value:  None
* history	:
*****************************************************************/
void read_privatekey_content(char* private_key)
{
	FILE* fp = fopen(PRIVATE_KEY_FILE, "rb");
	if (fp == NULL)
	{
		printf("open file error\n");
		return;
	}
	fread(private_key, MIDLEN, 1, fp);
	fclose(fp);
}
/****************************************************************
* function name 		: Base64Encode
* functional description	: base64编码
* input parameter		: encoded:存放编码后的数据;encodedLength:数据长度;decoded:原数据
* output parameter	: None
* return value:  None
* history	:
*****************************************************************/
int Base64Encode(const char* encoded, int encodedLength, char* decoded)
{
	return EVP_EncodeBlock((unsigned char*)decoded, (const unsigned char*)encoded, encodedLength);
}
/****************************************************************
* function name 		: Base64Decode
* functional description	: base64解码
* input parameter		: encoded:存放解码后的数据;encodedLength:数据长度;decoded:原数据
* output parameter	: None
* return value:  None
* history	:
*****************************************************************/
int Base64Decode(const char* encoded, int encodedLength, char* decoded)
{
	return EVP_DecodeBlock((unsigned char*)decoded, (const unsigned char*)encoded, encodedLength);
}
/****************************************************************
* function name 		: PubKeyPEMFormat
* functional description	: 对公钥内容进行PEM格式化;没有BEGIN、END的话,就分段加上
* input parameter		: pubkey:公钥数据
* output parameter	: None
* return value:  None
* history	:
*****************************************************************/
void PubKeyPEMFormat(char* pubkey)
{
	char format_pubkey[MAXLEN] = "";
	char pub_tem[MAXLEN] = "";
	
	char* pub_begin = "-----BEGIN PUBLIC KEY-----\n";
	char* pub_end = "-----END PUBLIC KEY-----\n";
	char* check = strstr(pubkey, pub_begin);
	if (check)
	{
		return;
	}
	else
	{
		int nPublicKeyLen = strlen(pubkey);
		int index = 0, publength = 0;
		memcpy(format_pubkey, pub_begin, 27);
		for (index = 0; index < nPublicKeyLen; index += 64)
		{
			memcpy(pub_tem, pubkey + index, 64);
			strcat(format_pubkey, pub_tem);
			publength = strlen(format_pubkey);
			format_pubkey[publength] = '\n';
			memset(pub_tem, 0, sizeof(pub_tem));
		}
		strcat(format_pubkey, pub_end);
		memcpy(pubkey, format_pubkey, strlen(format_pubkey));
	}
}
/****************************************************************
* function name 		: PublicEncrypt
* functional description	: 公钥加密数据
* input parameter		: in_plain:原文;cipher:加密数据
* output parameter	: None
* return value:  None
* history	:
*****************************************************************/
void PublicEncrypt(char* in_plain, char* cipher)
{
	/*公钥文件内容*/
	char pubkey[MIDLEN] = "";
	read_publickey_content(pubkey);
	if (strlen(pubkey) == 0)
	{
		printf("get pubkey file content error");
		return;
	}

	char plain[MAXLEN] = "";			/*存放分段后的每一段明文*/
	char encrypted[MAXLEN] = "";			/*存放每一段明文的解密结果*/
	char result[MAXLEN] = "";			/*存放拼接后的密文*/
	char plain_rest[MAXLEN] = "";		/*存放分段之后剩余部分的明文*/
	char encrypted_rest[MAXLEN] = "";		/*存放对剩余部分明文的解密结果*/

	/*对公钥进行PEM格式化*/
	PubKeyPEMFormat(pubkey);

	/*根据公钥长度进行相关的计算*/
	int pubKeyLen = strlen(pubkey);							/*计算公钥长度*/
	int CryLen = 1024;                                      /*密钥为1024位*/
	int maxPlain = CryLen / 8 - 11;							/*通过加密长度获取明文的最大加密长度*/
	int cipherLen = CryLen / 8;								/*通过加密长度获取密文的长度*/

	/*从字符串读取RSA公钥*/
	BIO* enc = NULL;
	if ((enc = BIO_new_mem_buf(pubkey, -1)) == NULL)
	{
		printf("BIO_new_mem_buf failed!\n");
		return;
	}

	/*解析公钥*/
	RSA* rsa_pub = RSA_new();
	rsa_pub = PEM_read_bio_RSA_PUBKEY(enc, NULL, NULL, NULL);
	if (rsa_pub == NULL)
	{
		printf("Unable to read public key!\n");
		return;
	}

	/*分端循环加密*/
	int label = 0, index = 0, index_rest = 0;
	int segment = strlen(in_plain) / maxPlain;   /*分段数*/
	int rest = strlen(in_plain) % maxPlain;      /*余数*/

	/*明文长度大于最大加密长度且非整数倍*/
	if (strlen(in_plain) > maxPlain && rest != 0)
	{
		for (label = 0; label < segment; label++)
		{
			memset(plain, '\0', maxPlain);
			memset(encrypted, '\0', cipherLen);
			memcpy(plain, in_plain + index, maxPlain);		/*对明文进行分段*/
			plain[maxPlain] = '\0';
			int EncryptedLen = RSA_public_encrypt(maxPlain, plain, encrypted, rsa_pub, RSA_PKCS1_PADDING);
			if (EncryptedLen == -1)
			{
				printf("Failed to encrypt!\n");
				return;
			}

			/*对每一段定长密文进行拼接*/
			memcpy(result + label * cipherLen, encrypted, cipherLen);

			index += maxPlain;
		}

		/*对剩余部分明文进行加密*/
		index_rest = segment * maxPlain;
		memset(plain_rest, '\0', rest);
		memcpy(plain_rest, in_plain + index_rest, rest);		/*获取剩余部分明文*/
		plain_rest[rest] = '\0';
		memset(encrypted_rest, '\0', cipherLen);
		int EncryptedLen = RSA_public_encrypt(rest, plain_rest, encrypted_rest, rsa_pub, RSA_PKCS1_PADDING);
		if (EncryptedLen == -1)
		{
			printf("Failed to encrypt!\n");
			return;
		}
		/*将剩余部分的密文拼接到整段密文中*/
		memcpy(result + label * cipherLen, encrypted_rest, cipherLen);

		/*对整段密文进行Base64编码*/
		Base64Encode(result, (label + 1) * cipherLen, cipher);
	}/*多段加密*/

	/*明文长度等于最大加密长度的整数倍*/
	else if (strlen(in_plain) >= maxPlain && rest == 0)
	{
		for (label = 0; label < segment; label++)
		{
			memset(plain, '\0', maxPlain);
			memset(encrypted, '\0', cipherLen);
			memcpy(plain, in_plain + index, maxPlain);		/*对明文进行分段*/
			plain[maxPlain] = '\0';
			int EncryptedLen = RSA_public_encrypt(maxPlain, plain, encrypted, rsa_pub, RSA_PKCS1_PADDING);
			if (EncryptedLen == -1)
			{
				printf("Failed to encrypt!\n");
				return;
			}
			/*拼接每段密文*/
			memcpy(result + label * cipherLen, encrypted, cipherLen);

			index += maxPlain;
		}
		/*对整段密文进行Base64编码*/
		Base64Encode(result, label * cipherLen, cipher);
	}/*多段整除加密*/

	/*明文长度小于最大加密长度*/
	else
	{
		int EncryptedLen = RSA_public_encrypt(strlen(in_plain), in_plain, encrypted, rsa_pub, RSA_PKCS1_PADDING);
		if (EncryptedLen == -1)
		{
			printf("Failed to encrypt!\n");
			return;
		}
		/*对密文进行Base64编码*/
		Base64Encode(encrypted, cipherLen, cipher);
	}

	/*释放BIO内存和RSA结构体*/
	BIO_free_all(enc);
	RSA_free(rsa_pub);

	return;
}
/****************************************************************
* function name 		: PrivKeyPEMFormat
* functional description	: 私钥格式化
* input parameter		: privkey:私钥数据内容
* output parameter	: None
* return value:  None
* history	:
*****************************************************************/
void PrivKeyPEMFormat(char* privkey)
{
	char format_privkey[MAXLEN] = "";
	char priv_tem[MAXLEN] = "";
	char* priv_begin = "-----BEGIN RSA PRIVATE KEY-----\n";
	char* priv_end = "-----END RSA PRIVATE KEY-----\n";
	char* check = strstr(privkey, priv_begin);
	if (check)
	{
		return;
	}
	else
	{
		int nPrivateKeyLen = strlen(privkey);
		int index = 0, privlength = 0;
		memcpy(format_privkey, priv_begin, 32);
		for (index = 0; index < nPrivateKeyLen; index += 64)
		{
			memcpy(priv_tem, privkey + index, 64);
			strcat(format_privkey, priv_tem);
			privlength = strlen(format_privkey);
			format_privkey[privlength] = '\n';
			memset(priv_tem, 0, sizeof(priv_tem));
		}
		strcat(format_privkey, priv_end);
		memcpy(privkey, format_privkey, strlen(format_privkey));
	}
}
/****************************************************************
* function name 		: PrivateDecrypt
* functional description	: 私钥解密数据
* input parameter		: cipher:加密数据;out_plain:解密数据
* output parameter	: None
* return value:  None
* history	:
*****************************************************************/
int PrivateDecrypt(char* cipher, char* out_plain)
{
	/*私钥文件内容*/
	char private_key[MIDLEN] = "";
	read_privatekey_content(private_key);
	if (strlen(private_key) == 0)
	{
		printf("get private key file content error\n");
		return;
	}

	char decode_data[MAXLEN] = "";			/*存放解码后的整段密文*/
	char encrypted_result[MAXLEN] = "";		/*存放分段后的每一段密文*/
	char decrypted[MAXLEN] = "";			/*存放每一段密文的解密结果*/

	/*对私钥进行PEM格式化*/
	PrivKeyPEMFormat(private_key);

	/*1024位私钥对应的密文长度为128字节*/
	int CipherRealLen = 128;	         
	int plainLen = CipherRealLen - 11;    /*每段明文的最大长度*/

	/*从字符串读取RSA私钥*/
	BIO* dec = NULL;
	if ((dec = BIO_new_mem_buf(private_key, -1)) == NULL)
	{
		printf("BIO_new_mem_buf failed!\n");
		return;
	}

	/*解析私钥*/
	RSA* rsa_pri = RSA_new();
	EVP_PKEY* pri = EVP_PKEY_new();
	pri = PEM_read_bio_PrivateKey(dec, NULL, NULL, NULL);
	if (pri == NULL)
	{
		printf("Unable to read private key!\n");
		return;
	}

	/*将EVP_PKEY结构体转换成RSA结构体*/
	rsa_pri = EVP_PKEY_get1_RSA(pri);

	/*分段循环解密*/
	int CipherLen = strlen(cipher);		/*Base64编码的密文长度*/
	int index = 0, label = 0, out_plainLen = 0;

	/*计算真实密文的段数,CipherLen * 3 / 4为密文长度 */
	int segment = CipherLen * 3 / 4 / CipherRealLen;

	//memset(out_plain, '\0', plainLen);

	/*对整段密文进行Base64解码*/
	Base64Decode(cipher, CipherLen, decode_data);

	/*将解码后的密文分段解密后合并*/
	while (label < segment)
	{
		memset(encrypted_result, '\0', CipherRealLen);
		memcpy(encrypted_result, decode_data + index, CipherRealLen);		/*对密文进行分段*/
		encrypted_result[CipherRealLen] = '\0';

		memset(decrypted, '\0', plainLen);
		int DecryptedLen = RSA_private_decrypt(CipherRealLen, encrypted_result, decrypted, rsa_pri, RSA_PKCS1_PADDING);
		if (DecryptedLen == -1)
		{
			printf("Failed to decrypt!\n");
			return;
		}
		decrypted[DecryptedLen] = '\0';
		strcat(out_plain, decrypted);		/*将每一段的解密结果拼接到整段输出明文中*/
		out_plainLen += DecryptedLen;
		out_plain[out_plainLen] = '\0';
		index += CipherRealLen;
		label++;
	}

	/*释放BIO内存以及RSA和EVP_PKEY结构体*/
	BIO_free_all(dec);
	RSA_free(rsa_pri);
	EVP_PKEY_free(pri);

	return 0;
}
int main()
{
	char input[MAXLEN] = "";
	printf("please input your data:\n");
	scanf("%s", input);

	/*加密数据*/
	char encrypt_data[MAXLEN] = "";
	PublicEncrypt(input, encrypt_data);
	printf("encrypt_data:%s\n", encrypt_data);

	/*解密数据*/
	char decrypt_data[MAXLEN] = "";
	PrivateDecrypt(encrypt_data, decrypt_data);
	printf("decrypt_data:%s\n", decrypt_data);

	return 0;
}

关注其中几个函数:

 

 

/*
*创建一个内存型的BIO,其数据为buf里面len的长度,如果参数len为-1,
*则取的是strlen(buf)的长度。它用于数据需要存储在一块静态内存并以BIO形式存在。
*所需要的数据是直接从内存种读取的,而不是先要执行拷贝操作。
*所以这块内存是只读的。
*/
BIO *BIO_new_mem_buf(void *buf, int len);

/*
*使用openssl库加载rsa的公钥时,使用的函数也不同。
*以字符串公钥为例,对PKCS#1格式的密钥加载使用PEM_read_bio_RSAPublicKey()函数,
*对PKCS#8格式公钥的加载使用PEM_read_bio_RSA_PUBKEY()函数。
*此处读取的是java生成的公钥,所以使用PEM_read_bio_RSA_PUBKEY
*/
RSA *PEM_read_bio_RSA_PUBKEY(BIO *bp, RSA **x,pem_password_cb *cb, void *u);

/*
*加密数据,
*参数1:被加密的数据长度
*参数2:被加密的数据
*参数3:存放加密后的数据
*参数4:密钥对
*参数5:填充方式
*/
int RSA_public_encrypt(int flen, const unsigned char *from,
                       unsigned char *to, RSA *rsa, int padding);
                       
/*
*进行base64编码,openssl的函数,
*参数1:编码后的数据
*参数2:要编码的数据
*参数3:数据长度
*/
int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen);  

/*
*进行base64解码,openssl的函数
*参数1:编码后的数据
*参数2:要解码的数据
*参数3:数据长度
*/
int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n); 

/*
*从BIO中获取私钥数据,存到EVP_PKEY格式变量中
*/
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, 
                                  pem_password_cb *cb, void *u);

/*
*解密数据
*参数1:解密密钥长度
*参数2:要解密的数据
*参数3:存放解密后的信息
*参数4:密钥RSA结构体
*参数5:填充模式
*/                                                                    
int RSA_private_decrypt(int flen, const unsigned char *from,
                        unsigned char *to, RSA *rsa, int padding);

openssl相关命令:

1、生成密钥:

openssl genrsa -out rsa_private_key.pem 1024
    -out 指定生成文件,此文件包含公钥和私钥两部分,所以即可以加密,也可以解密
    1024 生成密钥的长度

2、提取公钥

 

openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key_1024.pub
    -in 指定输入的密钥文件
    -out 指定提取生成公钥的文件(PEM公钥格式)

 3、私钥转换成pkcs8格式

openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt > rsa_private_key_pkcs8.pem

 参考链接:

利用openssl进行RSA加密解密

https://www.cnblogs.com/jukan/p/5526740.html

java与openssl的rsa算法互用

https://my.oschina.net/u/566591/blog/309771

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值