当前位置: 首页 > news >正文

Rust: 加密算法库 ring 如何用于 RSA 数字签名?

本来用 rsa 库基本搞定,但文心一言建议改用 ring 库。原因是 rsa 库已经放弃维护,而 ring 库性能公认很好。但是如何进行 RSA 数字签名,网上几乎查不到这方面材料。仔细查看了 ring 库的源代码和代码注释,终于完成趟坑。总结一下供大家参考。

1. 生成密钥文件

用 RSA数字签名算法时,如何从磁盘文件加载密钥?这需要用 openssl 工具。这个工具如何下载安装不再赘述。

1.1 PEM 格式密钥文件

PEM(Privacy-Enhanced Mail)直译为“保密邮件”,但在此上下文中,它主要指的是一种用于存储加密密钥和证书的文件格式。PEM格式是一种基于ASCII编码的密钥和证书的存储格式,说白了就是文本文件,广泛用于安全领域,特别是在SSL/TLS协议中的证书和密钥管理。

以下是关于PEM格式密钥文件的详细解释:

  1. 文件内容

    • PEM文件可以包含公钥、私钥、证书等敏感信息。
    • 这些信息通常以Base64编码的形式存储,并且包含了起始标记和结束标记,以便于识别和区分不同类型的密钥和证书。
  2. 文件结构

    • PEM文件的内容通常以-----BEGIN <标签>-----开头,以-----END <标签>-----结束。
    • <标签>部分用于指示文件内容的类型,例如CERTIFICATE表示证书,PRIVATE KEY表示私钥,等等。
    • Base64编码的数据位于这两个标记之间,是实际的密钥或证书内容。
  3. 应用场景

    • PEM格式的文件在建立安全的网络连接(如HTTPS)时用于证明服务器的身份。
    • 它们也用于对数据进行加密和解密,或者进行数字签名。
    • PEM文件还可以用于构建完整的证书链,以验证服务器证书的有效性。
  4. 安全性

    • 由于PEM文件中包含了敏感的密钥和证书信息,因此需要采取一些措施来保护其安全性。
    • 可以通过严格限制访问权限、使用加密算法进行加密存储、以及采取安全通道和安全设备来传输和存储PEM文件,以防止中间人攻击和数据泄露。
  5. 与其他格式的转换

    • PEM格式与其他格式(如DER、PKCS#7、PKCS#12等)之间的转换是常见的需求。
    • 可以使用OpenSSL工具或其他相关工具来完成这些转换。

综上所述,PEM是一种重要的密钥和证书存储格式,在安全通信和数据保护方面发挥着关键作用。了解PEM格式的结构和应用场景,有助于更好地管理和保护敏感信息的安全性。

1.2 生成 PEM 格式的 RSA 密钥文件

下面 openssl 命令可以生成一个名为private_key.pem 的密钥文件。该文件可以用记事本打开查看结果。

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048

1.3 从 RSA 密钥文件导出 RSA 公钥文件

下面 openssl 命令可以从私钥文件 private_key.pem 中提取出公钥文件 public_key.pem

openssl rsa -pubout -in private_key.pem -out public_key.pem

1.4 PEM 密钥文件的使用

我曾用过 C++ 的 Crypto 库,这个库可以直接使用 PEM 密钥文件加载密钥。我以为 ring 库也是如此,结果非常失望。如果哪位朋友能用 ring 库直接加载,希望能告知,本人不胜感谢!

1.5 生成 PKCS#8 密钥

私钥文件用于签名。ring 库可以导入PKCS#8 规格的密钥,要求密钥文件按照 pk8 格式保存。ring 库的源代码注释提供了数字签名的方法。首先 ring 库需要的 PKCS#8 密钥证书的生成方法,代码如下:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048  -pkeyopt rsa_keygen_pubexp:65537 | openssl pkcs8 -topk8 -nocrypt -outform der > rsa-2048-private-key.pk8

1.6 导出公钥文件

公钥文件用于验证数字签名。ring 库可以读取 DER 格式的公钥文件。但 ring 的源代码等文档并没提供如何获得这份文件。经过反复尝试,发现从私钥文件抽取公钥文件分两步进行:首先生成 PEM 格式公钥文件,然后再转换成 DER 格式的公钥文件。命令如下:

openssl rsa -pubout -in rsa-2048-private-key.pk8 -inform DER -outform PEM -out rsa-2048-public-key.pem
openssl rsa -pubin -in rsa-2048-public-key.pem -inform PEM -RSAPublicKey_out -outform DER -out rsa-2048-public-key.der

1.7 关于 PEM、DER、PK8 格式的说明

PEM、DER、PK8(通常指的是PKCS#8私钥格式,但为简化讨论,这里将PK8视为PKCS#8的私钥部分的简称)是三种常见的密钥文件格式,它们各自有不同的特点和应用场景。以下是关于这三种密钥文件格式以及它们名字来历的详细说明:

1.7.1 PEM(Privacy-Enhanced Mail)
  • 来历
    • PEM格式最早由美国互联网工程任务组(IETF)在1987年的RFC 1421中定义。
    • 最初是为了解决电子邮件的加密和签名问题而设计的。
  • 特点
    • PEM格式是一种基于ASCII编码的密钥和证书的存储格式。
    • 文件通常以“.pem”为后缀名。
    • 可以包含公钥、私钥、证书等敏感信息。
    • 使用Base64编码,并且包含了起始标记和结束标记,以便于识别和区分不同类型的密钥和证书。
    • 具有良好的可读性和可编辑性。

1.7.2 DER(Distinguished Encoding Rules)

  • 来历
    • DER是一种二进制编码格式,常用于证书和密钥的存储和传输。
    • 它是ASN.1(Abstract Syntax Notation One)标准的一部分,由国际电信联盟(ITU-T)定义。
  • 特点
    • DER文件通常以“.der”或“.cer”(在某些上下文中,特别是Windows平台上,“.cer”可能用于表示DER编码的证书文件)为后缀名。
    • 与PEM格式相比,DER格式更加紧凑和高效,因为它使用二进制编码而不是Base64编码。
    • DER格式的文件不易于阅读和编辑,通常需要专业的工具才能查看和解析。

1.7.3 PKCS#8(Private-Key Cryptography Standards #8)

  • 来历
    • PKCS#8是由RSA实验室发布的一种标准,用于存储私钥信息。
    • 它是PKCS(Public-Key Cryptography Standards)系列标准的一部分。
  • 特点
    • PKCS#8定义了私钥的语法,包括如何对私钥进行编码和加密。
    • 提供了未加密和加密两种格式的私钥存储方式。
    • 未加密的私钥信息通常以明文形式存储(但编码为Base64或其他格式以方便存储和传输),而加密的私钥信息则使用密码短语或其他加密算法进行保护。
    • 常与OpenSSL等工具配合使用。
    • 在较新版本的OpenSSL中,生成的RSA私钥默认符合PKCS#8的PrivateKeyInfo结构。

需要注意的是,虽然PEM、DER和PKCS#8在密钥和证书的存储和管理中扮演着重要角色,但它们并不是互斥的。实际上,它们可以相互转换,并且可以在不同的应用场景中共同使用。例如,可以使用OpenSSL等工具将PEM格式的私钥转换为DER格式,或者将PKCS#8格式的私钥转换为PKCS#1格式的私钥(尽管PKCS#1主要用于公钥的存储)。

2. 实现签名与验证的源代码

下面直接贴 ring 提供的示例代码:
Cargo.toml 添加下面库:

ring = "0.17.8"

程序源代码:

use ring::{rand, rsa, signature};fn sign_and_verify_rsa(private_key_path: &std::path::Path,public_key_path: &std::path::Path)-> Result<(), MyError> {
// Create an RSA keypair from the DER-encoded bytes. This example uses
// a 2048-bit key, but larger keys are also supported.
let private_key_der = read_file(private_key_path)?;
let key_pair = rsa::KeyPair::from_der(&private_key_der).map_err(|_| MyError::BadPrivateKey)?;// Sign the message "hello, world", using PKCS#1 v1.5 padding and the
// SHA256 digest algorithm.
const MESSAGE: &'static [u8] = b"hello, world";
let rng = rand::SystemRandom::new();
let mut signature = vec![0; key_pair.public().modulus_len()];
key_pair.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE, &mut signature).map_err(|_| MyError::OOM)?;// Verify the signature.
let public_key =signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256,read_file(public_key_path)?);
public_key.verify(MESSAGE, &signature).map_err(|_| MyError::BadSignature)
}#[derive(Debug)]
enum MyError {IO(std::io::Error),BadPrivateKey,OOM,BadSignature,
}fn read_file(path: &std::path::Path) -> Result<Vec<u8>, MyError> {use std::io::Read;let mut file = std::fs::File::open(path).map_err(|e| MyError::IO(e))?;let mut contents: Vec<u8> = Vec::new();file.read_to_end(&mut contents).map_err(|e| MyError::IO(e))?;Ok(contents)
}

我加了一段测试程序供参考:

#[test]
fn test2() {let pkcs8 = read_file(std::path::Path::new("rsa-2048-private-key.pk8")).unwrap();let key_pair = rsa::KeyPair::from_pkcs8(&pkcs8).unwrap();const MESSAGE: &'static [u8] = b"hello, world";let rng = rand::SystemRandom::new();let mut signature = vec![0; key_pair.public().modulus_len()];key_pair.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE, &mut signature).map_err(|_| MyError::OOM).unwrap();println!("\nsignature:{:?}", signature);let public_key = signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256,read_file(std::path::Path::new("rsa-2048-public-key.der")).unwrap(),);println!("\npublic_key = {:?}", public_key);public_key.verify(MESSAGE, &signature).unwrap();
}

3. 心得体会

  • 阅读开源库的源代码可以解决文档不足的问题。
  • 希望多展开交流,加快学习进步!

相关文章:

Rust: 加密算法库 ring 如何用于 RSA 数字签名?

本来用 rsa 库基本搞定&#xff0c;但文心一言建议改用 ring 库。原因是 rsa 库已经放弃维护&#xff0c;而 ring 库性能公认很好。但是如何进行 RSA 数字签名&#xff0c;网上几乎查不到这方面材料。仔细查看了 ring 库的源代码和代码注释&#xff0c;终于完成趟坑。总结一下供…...

Matplotlib 网格线

Matplotlib 网格线 Matplotlib 是一个强大的 Python 绘图库&#xff0c;广泛用于数据可视化。在 Matplotlib 中&#xff0c;网格线是一种常用的辅助工具&#xff0c;用于增强图表的可读性和美观性。本文将详细介绍如何在 Matplotlib 中添加和使用网格线。 1. 简介 网格线是在…...

钉钉机器人禅道消息通知@指派人

钉钉、禅道怎么设置webhook&#xff1f; 点击查看&#xff1a;获取自定义机器人 Webhook 地址 在禅道上配置钉钉机器人webhook&#xff0c;使用管理员账号登录&#xff0c;找到通知设置 添加webhook 添加webhook所需要的数据即可 webhook设置&#xff0c;根据自己的实际…...

我的新书出版啦!和大家聊聊写书的酸甜苦辣

我的新书出版啦&#xff01;小伙伴们问是不是赚翻了&#xff1f; 大家好&#xff0c;我是码哥。我的新书《Redis 高手心法》出版后&#xff08;2024 年 8 月份出版&#xff09;&#xff0c;有一些小伙伴问了我一些问题&#xff1a; 写书是不是赚了很多钱&#xff1f;我也想写…...

【福建医科大学附属第一医院-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …...

第二届新生程序设计竞赛热身赛(C语言)

A:饥饿的XP XP迷失在X星球&#xff0c;他醒来时已经很久很久很久没有吃过东西了。他突然发现身边有一张地图&#xff0c;上面有X星球上每一个食物供给点的位置。太好了&#xff0c;XP跳了起来。他决定先把肚子填饱再去寻找其他伙伴。现在已知XP的位置(X, Y)&#xff0c;以及他的…...

WebSocket和HTTP请求的区别

1. 连接方式 HTTP请求&#xff1a;基于“请求-响应”模式。每次通信都要重新建立连接&#xff0c;客户端发送请求后服务器返回响应&#xff0c;连接就断开了。这种模式通常适合不频繁更新的数据&#xff0c;如静态页面的加载。WebSocket&#xff1a;支持长连接&#xff0c;连接…...

【Python · Pytorch】人工神经网络 ANN(中)

【Python Pytorch】人工神经网络 ANN&#xff08;中&#xff09; 6. 反向传播6.1 梯度下降法6.1.1 线搜索方法6.1.2 微分 & 导数6.1.3 偏导数6.1.4 Jacobian矩阵6.1.5 梯度 & 梯度下降法按维度介绍 6.1.6 面临挑战平原现象 & 振荡现象局部最小值鞍点梯度消失梯度爆…...

穷举vs暴搜vs深搜vs回溯vs剪枝 算法专题

一. 全排列 全排列 class Solution {List<List<Integer>> ret;List<Integer> path;boolean[] check;public List<List<Integer>> permute(int[] nums) {ret new ArrayList<>();//存放结果path new ArrayList<>();存放每个路径的…...

Uni-App-02

条件编译 条件编译概念 不同的运行平台终归有些专有的特性&#xff0c;无法实现跨平台完全兼容&#xff0c;例如&#xff1a;微信小程序导航栏右上角的关闭图标。 uni-app提供了一种“条件编译”机制&#xff0c;可以针对特定的平台编译执行特定的代码&#xff0c;否则不执行。…...

在做题中学习(72):最小栈

解法&#xff1a;pair<int,int>解决 思路&#xff1a;stack里存pair&#xff0c;push时&#xff0c;first存当前值&#xff0c;而每次push都要更新pair的second&#xff0c;使它成为更小值&#xff0c;最后的getmin&#xff0c;只用取top().second即可拿到最小值。 cla…...

详解软件设计中分库分表的几种实现以及应用示例

详解软件设计中分库分表的几种实现以及应用示例https://mp.weixin.qq.com/s?__bizMzkzMTY0Mjc0Ng&mid2247485108&idx1&sn8b3b803c120c163092c70fa65fe5541e&chksmc266aaa1f51123b7af4d7a3113fe7c25daa938a04ced949fb71a8b7773e861fb93d907435386#rd...

随着飞行汽车的亮相,在环保方面有什么保护措施吗

飞行汽车具备环保潜力&#xff0c;采用电动或混合动力系统减少污染&#xff0c;并拓展应用场景。多家企业布局&#xff0c;沃飞长空作为国内eVTOL(电动垂直起降航空器)研发的领先企业&#xff0c;在环保这一点做的非常到位&#xff0c;AE200采用纯电动力系统,零碳排放,静默飞行…...

docker安装、设置非sudo执行、卸载

安装 sudo snap install docker 设置docker非sudo执行 sudo groupadd docker sudo usermod -aG docker $USER newgrp docker sudo chown root:docker /var/run/docker.sock 卸载docker 1.删除docker及安装时自动安装的所有包 apt-get autoremove docker docker-ce docker-…...

WebSocket简单使用

1.WebSocket 简介 WebSocket 是一种网络通信协议&#xff0c;提供了在单个TCP连接上进行全双工通信的能力。这意味着客户端和服务器可以同时发送和接收数据&#xff0c;而不需要等待对方的回应。WebSocket 协议在2011年成为国际标准&#xff0c;并且被大多数现代浏览器所支持。…...

【FinalShell问题】FinalShell连接虚拟机超时问题

问题描述&#xff1a; 打开fianlshell连接之前设置好的SSH连接&#xff08;Linux&#xff09;&#xff0c;结果连接不上&#xff0c;并出现提示&#xff1a;java.net.ConnectException: Connection timed out: connect&#xff0c;说明虚拟机连接超时。 问题解决&#xff1a;…...

Matplotlib可视化——三维图与莫比乌斯带可视化

实验名称 Matplotlib中的三维图绘制:莫比乌斯带的可视化 实验目标 三维的点和线三维轮廓图线框图和曲面图曲面三角形 举例:莫比乌斯带的可视化实验主要使用的Python库 名称版本简介Numpy1.19.5数组运算Matplotlib3.3.4数据可视化实验适用的对象 学习对象:本科学生、研究生…...

【PyCharm配置Conda的虚拟环境】

conda create了一个新的虚拟环境&#xff0c;想在PyCharm里面使用这个环境&#xff0c;但是怎么都添加不上。 解决办法&#xff0c;把conda executable选择为conda安装目录下的condabin下的conda.bat文件&#xff0c;成功&#xff01;...

今日总结10.31

BIO、NIO 和 AIO 的区别 BIO&#xff08;Blocking I/O&#xff0c;同步阻塞I/O&#xff09;、NIO&#xff08;Non-blocking I/O&#xff0c;同步非阻塞I/O&#xff09;和AIO&#xff08;Asynchronous I/O&#xff0c;异步非阻塞I/O&#xff09;是Java中的三种不同的I/O模型&am…...

2024年【汽车修理工(高级)】考试题及汽车修理工(高级)最新解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【汽车修理工&#xff08;高级&#xff09;】考试题及汽车修理工&#xff08;高级&#xff09;最新解析&#xff0c;包含汽车修理工&#xff08;高级&#xff09;考试题答案和解析及汽车修理工&#xff08;高级…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...

Linux 下 DMA 内存映射浅析

序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存&#xff0c;但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程&#xff0c;可以参考这篇文章&#xff0c;我觉得写的非常…...