20.2 OpenSSL 非对称RSA加解密算法
RSA算法是一种非对称加密算法,由三位数学家Rivest、Shamir和Adleman共同发明,以他们三人的名字首字母命名。RSA算法的安全性基于大数分解问题,即对于一个非常大的合数,将其分解为两个质数的乘积是非常困难的。
RSA算法是一种常用的非对称加密算法,与对称加密算法不同,RSA算法使用一对非对称密钥,分别为公钥和私钥,公钥和私钥是成对生成的,公钥可以公开,用于加密数据和验证数字签名,而私钥必须保密,用于解密数据和生成数字签名。因此,RSA算法的使用场景是公钥加密、私钥解密,或者私钥加密、公钥解密。
OpenSSL库中提供了针对此类算法的支持,但在使用时读者需要自行生成公钥与私钥文件,在开发工具包内有一个openssl.exe程序,该程序则是用于生成密钥对的工具,当我们需要使用非对称加密算法时,则可以使用如下命令生成公钥和私钥。
- 生成私钥: openssl genrsa -out rsa_private_key.pem 1024
- 生成公钥: openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
读者执行上述两条命令后即可得到rsa_private_key.pem私钥,以及rsa_public_key.pem公钥,如下图所示;

在使用非对称加密时,读者需要分别导入所需要的头文件,这其中就包括了rsa.h用于处理加密算法的库,以及pem.h用于处理私钥的库,这两个库是使用RSA时必须要导入的。
#include <iostream>
#include <string>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/crypto.h>
extern "C"
{
#include <openssl/applink.c>
}
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")
20.2.1 公钥加密私钥解密
RSA公钥用于加密数据和验证数字签名,私钥用于解密数据和生成数字签名,通常用于公钥加密、私钥解密的场景,具有较高的安全性,但加密和解密速度较慢,因此通常采用一种混合加密方式,即使用RSA算法加密对称加密算法中的密钥,再使用对称加密算法加密数据,以保证数据的机密性和加密解密的效率。
首先我们来实现公钥加密功能,如下Public_RsaEncrypt函数,该函数接受两个参数,分别是需要加密的字符串以及公钥文件,代码中首先通过fopen()打开一个公钥文件,并通过PEM_read_RSA_PUBKEY函数读入并初始化公钥文件,接着调用RSA_public_encrypt该函数主要用于实现公钥加密,当加密成功后返回加密后的文本内容,类型是字符串。
// 公钥加密
std::string Public_RsaEncrypt(const std::string& str, const std::string& path)
{
RSA* rsa = NULL;
FILE* file = NULL;
char* ciphertext = NULL;
int len = 0;
int ret = 0;
file = fopen(path.c_str(), "r");
if (file == NULL)
{
return std::string();
}
rsa = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL);
if (rsa == NULL)
{
ERR_print_errors_fp(stdout);
fclose(file);
return std::string();
}
len = RSA_size(rsa);
ciphertext = (char*)malloc(len + 1);
if (ciphertext == NULL)
{
RSA_free(rsa);
fclose(file);
return std::string();
}
memset(ciphertext, 0, len + 1);
ret = RSA_public_encrypt(str.length(), (unsigned char*)str.c_str(), (unsigned char*)ciphertext, rsa, RSA_PKCS1_PADDING);
if (ret < 0)
{
ERR_print_errors_fp(stdout);
free(ciphertext);
RSA_free(rsa);
fclose(file);
return std::string();
}
std::string s(ciphertext, ret);
free(ciphertext);
RSA_free(rsa);
fclose(file);
return s;
}
与公钥加密方法类似,Private_RsaDecrypt函数用于使用私钥进行解密,该函数接受两个参数,第一个参数是加密后的字符串数据,第二个参数则是私钥的具体路径,函数中通过PEM_read_RSAPrivateKey实现对私钥的初始化,并通过RSA_private_decrypt函数来实现对特定字符串的解密操作。
// 私钥解密
std::string Private_RsaDecrypt(const std::string& str, const std::string& path)
{
RSA* rsa = NULL;
FILE* file = NULL;
char* plaintext = NULL;
int len = 0;
int ret = 0;
file = fopen(path.c_str(), "r");
if (file == NULL)
{
return std::string();
}
rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
if (rsa == NULL)
{
ERR_print_errors_fp(stdout);
fclose(file);
return std::string();
}
len = RSA_size(rsa);
plaintext = (char*)malloc(len + 1);
if (plaintext == NULL)
{
RSA_free(rsa);
fclose(file);
return std::string();
}
memset(plaintext, 0, len + 1);
ret = RSA_private_decrypt(str.length(), (unsigned char*)str.c_str(), (unsigned char*)plaintext, rsa, RSA_PKCS1_PADDING);
if (ret < 0)
{
ERR_print_errors_fp(stdout);
free(plaintext);
RSA_free(rsa);
fclose(file);
return std::string();
}
std::string s(plaintext, ret);
free(plaintext);
RSA_free(rsa);
fclose(file);
return s;
}
这两段代码的调用也非常容易,如下代码片段则分别实现了对text字符串的加密与解密功能,使用公钥加密,使用私钥解密。
int main(int argc, char* argv[])
{
std::string text = "hello lyshark";
// 公钥加密
std::string public_path = "d://rsa_public_key.pem";
std::string encry = Public_RsaEncrypt(text, public_path);
// std::cout << "加密后文本: " << encry << std::endl;
// 私钥解密
std::string private_path = "d://rsa_private_key.pem";
std::string decry = Private_RsaDecrypt(encry, private_path);
std::cout << "解密后文本: " << decry << std::endl;
system("pause");
return 0;
}
这段代码输出效果如下图所示;

20.2.2 私钥加密公钥解密
在RSA算法中,私钥加密公钥解密并不是一种常见的使用方式,因为私钥是用于签名而不是加密的。通常的使用方式是,使用公钥加密,私钥解密,这样可以保证数据的机密性,只有拥有私钥的人才能解密数据,但在某些时候我们不得不将这个流程反过来,使用私钥加密并使用公钥解密。
私钥加密的封装代码如下所示,其中Private_RsaEncrypt用于实现私钥加密,该函数同样接受两个参数,分别是待加密字符串以及当前私钥路径,函数的核心部分是RSA_private_encrypt该函数可用于使用私钥对数据进行加密。
// 私钥加密
std::string Private_RsaEncrypt(const std::string& str, const std::string& path)
{
RSA* rsa = NULL;
FILE* file = NULL;
char* ciphertext = NULL;
int len = 0;
int ret = 0;
file = fopen(path.c_str(), "r");
if (file == NULL)
{
return std::string();
}
rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
if (rsa == NULL)
{
ERR_print_errors_fp(stdout);
fclose(file);
return std::string();
}
len = RSA_size(rsa);
ciphertext = (char*)malloc(len + 1);
if (ciphertext == NULL)
{
RSA_free(rsa);
fclose(file);
return std::string();
}
memset(ciphertext, 0, len + 1);
ret = RSA_private_encrypt(str.length(), (unsigned char*)str.c_str(), (unsigned char*)ciphertext, rsa, RSA_PKCS1_PADDING);
if (ret < 0)
{
ERR_print_errors_fp(stdout);
free(ciphertext);
RSA_free(rsa);
fclose(file);
return std::string();
}
std::string s(ciphertext, ret);
free(ciphertext);
RSA_free(rsa);
fclose(file);
return s;
}
公钥解密的实现方法与加密完全一致,代码中Public_RsaDecrypt函数用于实现公钥解密,其核心功能的实现依赖于RSA_public_decrypt这个关键函数。
// 公钥解密
std::string Public_RsaDecrypt(const std::string& str, const std::string& path)
{
RSA* rsa = NULL;
FILE* file = NULL;
char* plaintext = NULL;
int len = 0;
int ret = 0;
file = fopen(path.c_str(), "r");
if (file == NULL)
{
return std::string();
}
rsa = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL);
if (rsa == NULL)
{
ERR_print_errors_fp(stdout);
fclose(file);
return std::string();
}
len = RSA_size(rsa);
plaintext = (char*)malloc(len + 1);
if (plaintext == NULL)
{
RSA_free(rsa);
fclose(file);
return std::string();
}
memset(plaintext, 0, len + 1);
ret = RSA_public_decrypt(str.length(), (unsigned char*)str.c_str(), (unsigned char*)plaintext, rsa, RSA_PKCS1_PADDING);
if (ret < 0)
{
ERR_print_errors_fp(stdout);
free(plaintext);
RSA_free(rsa);
fclose(file);
return std::string();
}
std::string s(plaintext, ret);
free(plaintext);
RSA_free(rsa);
fclose(file);
return s;
}
有了上述方法,那么调用代码则变得很容易,如下所示,我们将text字符串使用私钥进行加密,并使用公钥进行解密。
int main(int argc, char* argv[])
{
std::string text = "hello lyshark";
// 私钥加密
std::string private_path = "d://rsa_private_key.pem";
std::string encry = Private_RsaEncrypt(text, private_path);
// std::cout << "加密后文本: " << encry << std::endl;
// 公钥解密
std::string public_path = "d://rsa_public_key.pem";
std::string decry = Public_RsaDecrypt(encry, public_path);
std::cout << "解密后文本:" << decry << std::endl;
system("pause");
return 0;
}
这段代码输出效果如下图所示;

20.2 OpenSSL 非对称RSA加解密算法的更多相关文章
- 调用OpenSSL实现RSA加解密和签名操作
调用OpenSSL实现RSA加解密和签名操作 RSA公钥可以从证书和公钥文件,RSA私钥可以从私钥文件中提取.OpenSSL使用了一种BIO抽象IO机制读写所用文件,可以打开文件相关联的BIO,通过B ...
- C# 中使用 RSA加解密算法
一.什么是RSA RSA公开密钥密码体制.所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制. 在公开密钥密码体制中,加密密钥(即 ...
- RSA加解密算法以及密钥格式
RSA算法: 有个文章关于RSA原理讲的不错: https://blog.csdn.net/dbs1215/article/details/48953589 http://www.ruanyifeng ...
- RSA 加解密算法
与DES不同,RSA算法中,每个通信主体都有两个钥匙,一个公钥一个私钥. 就是有2把钥匙1.使用publicKey可以对数据进行加密2.使用Key才能对数据进行解密单方向传输用公钥加密的数据,只有私钥 ...
- RSA 加解密算法详解
RSA 为"非对称加密算法".也就是加密和解密用的密钥不同. (1)乙方生成两把密钥(公钥和私钥).公钥是公开的,任何人都可以获得,私钥则是保密的. (2)甲方获取乙方的公钥,然后 ...
- openssl进行RSA加解密(C++)
密钥对根据RSA的加密机制(自行查找RSA工作原理),通常可以私钥加密-公钥解密(多用于签名),公钥加密-私钥解密(多用于数据传输加密),私钥可以生成公钥. 密钥对生成生成私钥,长度为2048,默认格 ...
- rsa加解密的内容超长的问题解决
一. 现象: 有一段老代码用来加密的,但是在使用key A的时候,抛出了异常:javax.crypto.IllegalBlockSizeException: Data must not be ...
- java RSA加解密以及用途
在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每 ...
- RSA加解密用途简介及java示例
在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每 ...
- [转]RSA,DSA等加解密算法介绍
From : http://blog.sina.com.cn/s/blog_a9303fd90101cgw4.html 1) MD5/SHA MessageDigest是一个数据的数字指纹. ...
随机推荐
- 【Docker】部署Redis
1.下载镜像 #下载最新版Redis镜像 (其实此命令就等同于 : docker pull redis:latest ) docker pull redis # 下载指定版本的Redis镜像 (xxx ...
- 树形DP + 换根DP
树形DP--基础 P1352 没有上司的舞会 设 \(f[i][0/1]\) 表示第 \(i\) 个人不去或者去. 如果第 \(i\) 个人没去,那么下属可去可不去,所以 \(f[i][0] = \s ...
- GitLab 无仓库 中了勒索病毒
坑爹的记录一下,并没有解决 Gitlab 昨天(2021-11-29)打开之后看不到项目了,下面这个吊样子 最后发现中病毒了,一堆的这个吊毛文件,复制一个打开看了一下 你别说这个黑客网页写的还不错,这 ...
- BugKu:文件包含+php伪协议
这道题一进去发现一个超连接点击后发现跳转到了如下页面url如下/index.php?file=show.php,觉得这道题应该是一个php伪协议的应用 1 php://filter php://fil ...
- IDEA:使用Test注解,控制台无法输入
解决方案 步骤一: 点击help ===> Edit Custom VM Options... 步骤二: 添加文件末尾添加如下内容 -Deditable.java.test.console=tr ...
- 深入理解Java虚拟机(JVM):原理、结构与性能优化
1. 介绍 Java虚拟机(JVM)是Java程序的核心执行引擎,负责将Java源代码编译成可执行的字节码,并在运行时负责解释执行字节码或将其编译成本地机器代码.本文将深入探讨JVM的原理.结构以及性 ...
- FJOI2022 游记
2022.3.28 省选延期,延到了4.16 2022.4.11 省选又延期,延到了5.2 FJOI 要回来了!! Day -7 开始停课了 QwQ Day -6 打摆 Day -5 打摆 不行,我不 ...
- C#程序的启动显示方案(无窗口进程发送消息) - 开源研究系列文章
今天继续研究C#的WinForm的实例显示效果. 我们上次介绍了Winform窗体的唯一实例运行代码(见博文:基于C#的应用程序单例唯一运行的完美解决方案 - 开源研究系列文章 ).这就有一个问题,程 ...
- JDK中动态库加载路径问题,一文讲清
前言 本周协助测试同事对一套测试环境进行扩容,我们扩容很原始,就是新申请一台机器,直接把jdk.resin容器(一款servlet容器).容器中web应用所在的目录,全拷贝到新机器上,servlet容 ...
- 美团面试拷打:ConcurrentHashMap 为何不能插入 null?HashMap 为何可以?
周末的时候,有一位小伙伴提了一些关于 ConcurrentHashMap 的问题,都是他最近面试遇到的.原提问如下: 整个提问看着非常复杂,其实归纳来说就是两个问题: ConcurrentHashMa ...