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. unity前后端通信

    1. 配置请求体中的Json字符串 1 request_data = new RequestBodyClass(); 2 request_data.a = "Json第一个字段"; ...

  2. 【SpringBoot】WebSocket在线聊天

    先看一下页面效果,有点简单粗暴!哈哈哈哈哈,别介意. 本文参考:SpringBoot2.0集成WebSocket,实现后台向前端推送信息 新建一个springboot项目 引入相关依赖 <dep ...

  3. 即构携手智能对讲机品牌Runbo,打造可视化对讲通信系统

    现代通信技术的发展,让信息的传递变得前所未有的便捷.作为双向移动通信工具,对讲机不需要网络支持就可以进行通话,且没有话费产生,尤其适合酒店.物业等使用区域固定.通话频繁的场景. 随着技术的不断迭代,对 ...

  4. CMOS信噪比与感光面积的关系

    前言 一般情况下,相同分辨率的sensor,如果感光面积越大,则其单位像素的感光面积也越大,成像质量也会越好.即相同分辨率品质相当的sensor,2/3"的传感器成像质量一般情况就要优于1/ ...

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

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

  6. 运维自动化工具--Ansible

    运维自动化工具Ansible 1. ansible安装 rocky安装 需要先安装 enel源 # yum install -y epel-release 然后再安装ansible # yum ins ...

  7. 今日ERROR

    树莓派插卡发烫严重 首先,我们要知道: 树莓派的指示灯可以告诉用户系统的工作状态,常见的指示灯有四个,分别是红色电源灯.绿色SD卡读写灯.黄色ACT指示灯和蓝色网络连接指示灯(仅适用于某些型号的树莓派 ...

  8. Avalonia项目在OpenKylin运行踩坑

    Avalonia项目在OpenKylin运行踩坑 本篇博客记录OpenKylin开源操作系统中运行Avalonia项目遇到的各种问题,会一直更新,最新的内容请点击文末的链接跳转到我的博客原文地址查看. ...

  9. Windows平台的JDK安装及IDEA配置JDK的过程

    1.下载安装包 jdk-8u201-windows-x64.exe,即jdk1.8.0_201 链接:https://pan.baidu.com/s/1WYaTlProtHkC_KyMHIUBxQ?p ...

  10. 服务端不回应客户端的syn握手,连接建立失败原因排查

    背景 测试环境有一个后台服务,部署在内网服务器A上(无外网地址),给app提供接口.app访问这个后台服务时,ip地址是公网地址,那这个请求是如何到达我们的内网服务器A呢,这块我咨询了网络同事,我画了 ...