20.2 OpenSSL 非对称RSA加解密算法

news2024/11/27 2:16:50

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;
}

这段代码输出效果如下图所示;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1146639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据交换技术

一、数据交换 数据交换是实现在大规模网络核心上进行数据传输的技术基础。 常见的数据交换技术包括 电路交换报文交换分组交换 基于不同交换技术构建的网络分别称之为电路交换网络、报文交换网络和分组交换网络。 发展演变图&#xff1a; a) 电路交换 电路交换是最早出现…

Linux(Centos7)操作记录

1、nginx -t #Nginx配置文件检查 上述截图代表检查没问题 上述截图检查配置文件配置错误&#xff0c;并提示错误文件位置 2、systemctl restart nginx #重启Nginx 重启Nginx失败 3、systemctl status nginx.service #查看Nginx服务状态 80端口被占导致服务启动失败 4、n…

Modbus协议详解5:Modbus数据模型、寄存器、功能码 (非常重要)

Modbus是应用层上的协议&#xff0c;还是一种主从的通信协议&#xff0c;通信过程按照一定的协议规则进行&#xff0c;数据的交互也是有固定的格式的。 总的来说&#xff0c;Modbus是有着明确且固定的数据模型的&#xff0c;并且通信过程中的数据交互识别是要按照功能码进行的。…

IOC课程整理-4 Spring Bean基础

1 什么是 BeanDefinition&#xff1f; • BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口&#xff0c;包含&#xff1a; • Bean 的类名 • Bean 行为配置元素&#xff0c;如作用域、自动绑定的模式&#xff0c;生命周期回调等• 其他 Bean 引用&#xff0…

H5游戏源码分享-色块选择游戏

H5游戏源码分享-色块选择游戏 玩到后面色块越来越小&#xff0c;越来越难找出 <!DOCTYPE html><html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><meta charset"UTF-8"><meta na…

基于Java的教室设备管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

c++设计模式二:原型模式

使用场景&#xff1a;当需要构建多个相同的类对象时&#xff0c;而且该类对象结构较为复杂&#xff0c;如果每个都重新组织构建会很麻烦。 其实&#xff0c;就是写一个拷贝构造函数&#xff0c;或者写一个拷贝每个成员变量的clone()方法。 举例说明&#xff1a;比如一个相亲网站…

通道洗牌的思想神了

大家好啊&#xff0c;我是董董灿。 昨天写了一篇关于分组卷积的文章&#xff1a;分组卷积的思想神了&#xff0c;然后有同学希望多了解下通道洗牌。 我个人感觉&#xff0c;通道洗牌这个算法&#xff0c;或者说这个思想&#xff0c;可以称之为小而精&#xff0c;并且是实际解…

【Tomcat】如何在idea上部署一个maven项目?

目录 1.创建项目 2.引入依赖 3.创建目录 4.编写代码 5.打包程序 6.部署项目 7.验证程序 什么是Tomcat和Servlet? 以idea2019为例&#xff1a; 1.创建项目 1.1 首先创建maven项目 1.2 项目名称 2.引入依赖 2.1 网址输入mvnrepository.com进入maven中央仓库->地址…

新一代AI技术,引领医疗智能革新共筑未来医疗生态

加快推进数字化转型&#xff0c;是我国抢抓新一轮科技革命和产业变革机遇的必然选择&#xff0c;数字化转型已不是“选择题”&#xff0c;而是关乎生存和长远发展的“必修课”。在此目标下&#xff0c;公共服务领域迎来深刻变革&#xff0c;医院也不例外&#xff0c;数字经济的…

微信小程序 - 页面继承(非完美解决方案)

微信小程序 - 面页继承&#xff08;非完美解决方案&#xff09; 废话思路首页 indexindex.jsindex.jsonindex.wxml 父页面 page-basepage-base.jspage-base.wxml 子页面 page-apage-a.jspage-a.wxml 子页面 page-bpage-b.jspage-b.wxml 其它app.jsapp.jsonapp.wxss 参考资料 废…

21.12 Python 实现网站服务器

Web服务器本质上是一个提供Web服务的应用程序&#xff0c;运行在服务器上&#xff0c;用于处理HTTP请求和响应。它接收来自客户端&#xff08;通常是浏览器&#xff09;的HTTP请求&#xff0c;根据请求的URL、参数等信息生成HTTP响应&#xff0c;并将响应返回给客户端&#xff…

海康工业相机的使用(草稿)

下载&#xff1a; 海康机器人-机器视觉-下载中心 (hikrobotics.com) Windows版本测试&#xff1a; 机器视觉工业相机客户端MVS V4.2.1&#xff08;Windows&#xff09; Ubuntu版本开发&#xff1a; 机器视觉工业相机客户端MVS V2.1.2 (Linux) 机器视觉工业相机SDK V4.1.2版…

一个脚本快速查看网站用到的技术

shigen坚持日更的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。坚持记录和分享从业两年以来的技术积累和思考&#xff0c;不断沉淀和成长。 今天给大家带来的技巧是&#xff1a;一个脚本快速的查看网站运用的技术和域名备案信息。 …

NVIDIA cuda安装时全部失败

查看了很多博客&#xff0c;有写的非常详细清楚的博客&#xff0c;csdn上真的是一个很好的学习平台&#xff0c;我在学习过程中遇到的好多bug&#xff0c;都能在这上面找到解决方法&#xff0c;就是一个老师的存在。 我安装NVIDIA cuda安装时失败了N次&#xff0c;数不清了&am…

san.js源码解读之模版解析(parseTemplate)篇——readAccessor函数

相关文章&#xff1a;san.js源码解读之模版解析(parseTemplate)篇——readIdent函数 一、源码分析 /*** 读取访问表达式** param {Walker} walker 源码读取对象* return {Object}*/ function readAccessor(walker) {var firstSeg readIdent(walker);switch (firstSeg) { // …

【论文复现:Active Learning via Local Structure Recontruction】

论文复现&#xff1a;Active Learning via Local Structure Reconstruction 目标函数优化过程公式(16)推到python代码链接如下&#xff1a; 目标函数 优化过程 公式(16)推到 原文中省略了上述推导过程 在这里我们自己推导一下&#xff0c;只要有一点数学基础就很简单&#xff…

【计算机网络】数据链路层——以太网

文章目录 前言什么是以太网以太网帧格式6位目的地址和源地址2位类型数据长度CRC 校验和 数据在数据链路层是如何转发的 前言 前面我们学习了关于应用层——自定义协议、传输层——UDP、TCP协议、网络层——IP协议&#xff0c;今天我将为大家分享关于数据链路层——以太网方面的…

基于蝙蝠算法的无人机航迹规划-附代码

基于蝙蝠算法的无人机航迹规划 文章目录 基于蝙蝠算法的无人机航迹规划1.蝙蝠搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用蝙蝠算法来优化无人机航迹规划。 1.蝙蝠搜索算法 …

MAYA教程之灯光与渲染

灯光介绍 MAYA中有六种光源环境光&#xff1a;模拟环境中的光源&#xff0c;光线是四面八方的平行光&#xff1a;模拟太阳光点光源&#xff1a;模拟蜡烛等光源聚光灯&#xff1a;模拟夜场那种光源区域光&#xff1a;模拟窗户照进室内的光源体积光&#xff1a;模拟激光在MAYA的…