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

openssl rsa非对称加密

程序员文章站 2024-03-16 20:28:28
...

背景:

为了实现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

相关标签: C