RSA算法是一种非对称加密算法,由三位数学家RivestShamirAdleman共同发明,以他们三人的名字首字母命名。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加解密算法的更多相关文章

  1. 调用OpenSSL实现RSA加解密和签名操作

    调用OpenSSL实现RSA加解密和签名操作 RSA公钥可以从证书和公钥文件,RSA私钥可以从私钥文件中提取.OpenSSL使用了一种BIO抽象IO机制读写所用文件,可以打开文件相关联的BIO,通过B ...

  2. C# 中使用 RSA加解密算法

    一.什么是RSA RSA公开密钥密码体制.所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制. 在公开密钥密码体制中,加密密钥(即 ...

  3. RSA加解密算法以及密钥格式

    RSA算法: 有个文章关于RSA原理讲的不错: https://blog.csdn.net/dbs1215/article/details/48953589 http://www.ruanyifeng ...

  4. RSA 加解密算法

    与DES不同,RSA算法中,每个通信主体都有两个钥匙,一个公钥一个私钥. 就是有2把钥匙1.使用publicKey可以对数据进行加密2.使用Key才能对数据进行解密单方向传输用公钥加密的数据,只有私钥 ...

  5. RSA 加解密算法详解

    RSA 为"非对称加密算法".也就是加密和解密用的密钥不同. (1)乙方生成两把密钥(公钥和私钥).公钥是公开的,任何人都可以获得,私钥则是保密的. (2)甲方获取乙方的公钥,然后 ...

  6. openssl进行RSA加解密(C++)

    密钥对根据RSA的加密机制(自行查找RSA工作原理),通常可以私钥加密-公钥解密(多用于签名),公钥加密-私钥解密(多用于数据传输加密),私钥可以生成公钥. 密钥对生成生成私钥,长度为2048,默认格 ...

  7. rsa加解密的内容超长的问题解决

    一. 现象:      有一段老代码用来加密的,但是在使用key A的时候,抛出了异常:javax.crypto.IllegalBlockSizeException: Data must not be ...

  8. java RSA加解密以及用途

    在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每 ...

  9. RSA加解密用途简介及java示例

    在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每 ...

  10. [转]RSA,DSA等加解密算法介绍

    From : http://blog.sina.com.cn/s/blog_a9303fd90101cgw4.html 1)      MD5/SHA MessageDigest是一个数据的数字指纹. ...

随机推荐

  1. docker 安装redis 6.0.8哨兵集群(一主两从三哨兵)

    准备三台主机并且安装了docker 192.168.31.132 192.168.31.134 192.168.31.144 linux 版redis6.0.8 下载 下载地址:https://dow ...

  2. Isito 入门(四):微服务可观测性

    本教程已加入 Istio 系列:https://istio.whuanle.cn 目录 可观测性 通过 Gateway 访问 Kiali 查看链路追踪数据 可能失败的原因 修复 Kiali Grafa ...

  3. 【阅读笔记】低照度图像增强-《An Integrated Neighborhood Dependent...

    本文介绍的是一种比较实用的低照度图像增强算法,选自2004年Tao的一篇论文,名称是<An Integrated Neighborhood Dependent Approach for Nonl ...

  4. Set_HashSet_TreeSet_小记

    Set接口:Set集合继承自Collection集合 Set:底层数据结构是一个哈希表,能保证元素是唯一的,元素不重复!它通过它的子实现了HashSet集合去实例化,HashSet集合底层是HashM ...

  5. 【技术积累】JavaScript中的基础语法【三】

    JavaScript的条件结构 JavaScript中的条件结构主要包括if语句.if-else语句.if-else if语句和switch语句.这些条件结构用于根据不同的条件执行不同的代码块. if ...

  6. js将数字金额转换成中文金额格式

    在开发中我们经常会遇到处理数字的问题,下面介绍一种处理数字金额转换为中文金额的方式: 我们通常使用三种书面数字系统:全球使用的阿拉伯数字系统和两种本地数字系统(繁体.简体).常规时我们使用阿拉伯数字( ...

  7. 2023-07-31:用r、e、d三种字符,拼出一个回文子串数量等于x的字符串。 1 <= x <= 10^5。 来自百度。

    2023-07-31:用r.e.d三种字符,拼出一个回文子串数量等于x的字符串. 1 <= x <= 10^5. 来自百度. 答案2023-07-31: 大体步骤如下: 1.初始化一个字符 ...

  8. Flutter系列文章-Flutter 插件开发

    在本篇文章中,我们将学习如何开发 Flutter 插件,实现 Flutter 与原生平台的交互.我们将详细介绍插件的开发过程,包括如何创建插件项目.实现方法通信.处理异步任务等.最后,我们还将演示如何 ...

  9. 三维模型OSGB格式轻量化压缩必要性分析

    三维模型OSGB格式轻量化压缩必要性分析 三维模型是计算机图形学和视觉效果等领域的重要应用之一.然而,由于三维模型通常包含大量的几何信息.纹理信息和其他元素,导致其占用的存储空间和计算资源非常巨大.为 ...

  10. Java 设计模式实战系列—单例模式

    本文首发公众号:小码A梦 单例模式是设计模式中最简单一个设计模式,该模式属于创建型模式,它提供了一种创建实例的最佳方式. 单例模式的定义也比较简单:一个类只能允许创建一个对象或者实例,那么这个类就是单 ...