利用openssl实现RSA加密

RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密,RSA加密明文长度受到秘钥长度和加密填充方式的约束,RSA密钥长度随着保密级别提高,增加很快。
RSA秘钥位数主要有1024位和2048位两种长度,秘钥有两种格式:PKCS#1和PKCS#8

1、 PKCS#1和PKCS#8两种格式区别

PKCS#1:
定义了RSA公钥函数的基本格式标准,特别是数字签名。它定义了数字签名如何计算,包括待签名数据和签名本身的格式;它也定义了PSA公/私钥的语法。
PKCS#8:
私钥信息语法标准。PKCS#8定义了私钥信息语法和加密私钥语法,其中私钥加密使用了PKCS#5标准。生成RSA密钥对。现在一般都用PKCS#8 格式证书较多,PKCS#1格式证书转换为PKCS#8 可以通过工具进行转化。
公钥都是以“-----BEGIN PUBLIC KEY-----”开头,“-----END PUBLIC KEY-----”结尾,
格式如下:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCBpdpJ2YK4iYoB69iwZwgWHErh
X15RyXRtpTMnN2jAtsbLed+Px64htxmxqSac7u2PGWQWUEyNcU0e2HOER96xz4r5
TqbGS5FZUqr6dem5zZuNLdWNiNqCXnv4OaP/e6Y6OphYnaNrcmNIULihPdRSwVn4
7At0YxJMMTDxGUJoCQIDAQAB
-----END PUBLIC KEY-----

pkcs#1的私钥以“-----BEGIN RSA PRIVATE KEY----- “开头,”-----END RSA PRIVATE KEY-----”结尾,格式如下:

-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCBpdpJ2YK4iYoB69iwZwgWHErhX15RyXRtpTMnN2jAtsbLed+P
x64htxmxqSac7u2PGWQWUEyNcU0e2HOER96xz4r5TqbGS5FZUqr6dem5zZuNLdWN
iNqCXnv4OaP/e6Y6OphYnaNrcmNIULihPdRSwVn47At0YxJMMTDxGUJoCQIDAQAB
AoGAGU5++AhZoFzUkABx6SkLZol6QljDx/IrZFWpUP/bVja3QjOVZHLlNhaQEOJE
M8DdpR+fLk3ZS4iwtZMppUoEGWVIAjgNQ0FzhJJE5kIwzTuaU2fQzvrFsP1Xcmtq
gQYfaiGe8kTc+iLTyftfoJlifVLZxmSk1J21Af6OslLLbasCQQCDcQaNjWPqxYp8
372z63tiPY08OnGMeBNMzZX4eE8mp9zS0DMiGBVutIxD+wb8g0kUGrgFTHmtxEYG
phSmHidvAkEA/IGy9KjkaPcnJCFgk7RunpslO5hP0IufbT8A2alah3lzsBAH3noy
KtO1xdjPHan0qunrLDjlQ9DYwh4PTLvsBwJARYtgrzZ2/jmki2uKII7gSltMxega
OfsyIvnHdp6ZKle4g6X61/gsJtXKPRGtYZ9I5CU65jrPSnxFnLD0zeu4awJAT5Lb
/4gd+wowNo2iLsoEtkz0LdSxCmqFwlrBfNaG5fybPZe/sxfVKXPwa7oIgzOlHBt9
dkEz1uxA8uOgNLFgDwJAWNs4MrcTkn93Mio5+eekLOAfU04vbxJ5vCX6rwxk2ezE
Shuxfmg98cmD4TJc+xs3HJeS+m5ALu/96OZ/hudTqg==
-----END RSA PRIVATE KEY-----

pkcs#8的私钥以“-----BEGIN PRIVATE KEY----- “开头,”-----END PRIVATE KEY-----”结尾,而且和pkcs#1长度不一致格式如下:

-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL4xczstzX6AcnuP
m4jUAXT3CBdhHFaPlAwTlyouHk1RtijcYI+HBIm58pf0q5c1noIVj1Rb50VIit+Q
HNY7AQV1bVl/S4/oRh6rQAygbflbyCEDNtLsISpvhziyVAFiXBikW5H7p7EwUH85
P44mx+0qux7L7zCCv45apNN/FQXbAgMBAAECgYEAoYMQ3gKJbZHapn9Pj6SqEA/w
ORponEGVcaP5TQKZDQQE8zIidgAspGDaWJyYUvJfxwxUCUl6XmW6ORwCwRKeS/L6
An7HD3nRrQm1I8svVa6UFTqV+WNyXFBCX1kds385lrk1FVPIFnLISAGVsBiscFIW
RvTTYRRvxydlQA8ttMECQQDqQU3QqpfqDwyClJMfHygr3WUctSxvPz8LmIdlzJ/3
AJcuuZVmwwxWxanRId12mm8NqYX6ObxIMDMw48F6vBPRAkEAz9kVzrEYOYeLw2ht
9T8ZneaAxVhfFRoTV4AdL6fFFaqdOHSl6EN0eUhTS8Xq1nuX70dyep0cr23TORQ6
nP/F6wJAUiD9KDh3NG98QlfW0OV6jw57AbqfTo2NDAK5Db7VIqNJXe9g6vtdWxrH
8/N8krWIU/DocRdG5MRJXk2rqt0/0QJAARGbtBljB4Cz7khOMHGnnxE9XkZrDr+4
k72b6M/TCp56+nxXEg+uvKTrkLsuzvWJvXg/lXPTXu+Qo32AI6iJCwJALBdfYxMk
VB1owZQPP5B4uaN9tacq06r1J4T+8gD5ANHSDQP99r9hY/MSYwYuUC4mK0YUYjBE
tyRPS6vsoFUZFA==
-----END PRIVATE KEY-----

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

(1)RSA_PKCS1_PADDING 填充模式,最常用的模式
要求:输入必须比RSA秘钥模长(modulus) 短至少11个字节, 也就是RSA_size(rsa) – 11。如果输入的明文过长,必须分片加密,密文输出和modulus一样长,根据这个要求,对于1024bit的密钥,block length = 1024/8 – 11 = 117字节。如果明文不够117字节加密的时候会在你的明文中随机填充一些数据,所以会导致对同样的明文每次加密后的结果都不一样。对加密后的密文,服务器使用相同的填充方式都能解密。解密后的明文也就是之前加密的明文。
(2)RSA_PKCS1_OAEP_PADDING 安全性是最高的
输入:RSA_size(rsa) – 41
输出:和modulus一样长
(3)RSA_NO_PADDING 不填充
输入:可以和RSA钥模长一样长,如果输入的明文过长,必须切割,然后填充,如果明文不够128字节加密的时候会在你的明文前面,前向的填充零。解密后的明文也会包括前面填充的零,这是服务器需要注意把解密后的字段前向填充的零去掉,才是真正之前加密的明文
输出:和modulus一样长

3.利用openssl库的rsa进行加解密代码

这里的秘钥直接从内存读取,和从文件读取加解密方式有点不一样。
公钥加密

std::string ChiCryption::rsaPubEncrypt(const std::string &clearText, const std::string &pubKey)
	{
		RSA *rsa = NULL;
		BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), static_cast(pubKey.length()));

		rsa = PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL);
		if (NULL == rsa) {
			printf("read key file fail!");
		}
		else{

		}

		int len = RSA_size(rsa);

		std::string strEncryptText;
		strEncryptText.resize(len);

		// 加密函数
		int ret = RSA_public_encrypt(static_cast(clearText.length()), (const unsigned char*)clearText.c_str(), (unsigned char*)(&strEncryptText[0]), rsa, RSA_PKCS1_PADDING);
		if (ret < 0)
		{
			strEncryptText.clear();
		}

		BIO_free_all(keybio);
		RSA_free(rsa);

		return strEncryptText;
	}

私钥解密:

std::string ChiCryption::rsaPriDecrypt(const std::string &cipherText, const std::string &priKey)
	{
		BIO *keybio;
		keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), static_cast(priKey.length()));

		RSA *rsa = PEM_read_bio_RSAPrivateKey(keybio, NULL, NULL, NULL);
		if (NULL == rsa) {
			printf("read key file fail!");
		}
		else{
			printf("read success!\n");  
		}
		int len = RSA_size(rsa);

		std::string strRet;
		strRet.resize(len);

		// 解密函数  
		int ret = RSA_private_decrypt(static_cast(cipherText.length()), (const unsigned char*)cipherText.c_str(),
			(unsigned char*)&strRet[0], rsa, RSA_PKCS1_PADDING);
		if (ret < 0)
		{
			strRet.clear();
		}
		else
		{
			strRet.resize(ret);
		}

		// 释放内存  
		BIO_free_all(keybio);
		RSA_free(rsa);

		return strRet;
	}

你可能感兴趣的:(加解密方式)