Node.js 中的 RSA 加密、解密、签名与验证详解

news2025/2/22 17:05:14

引言

在现代的网络通信中,数据安全显得尤为重要。RSA加密算法因其非对称的特性,广泛应用于数据的加密、解密、签名和验证等安全领域。本文将详细介绍RSA算法的基本原理,并结合Node.js环境,展示如何使用内置的crypto模块和第三方库node-rsa来实现RSA的加密、解密、签名和验证。

RSA算法原理

RSA算法是一种非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出。它的安全性基于大数分解的困难性。RSA算法涉及到三个关键的概念:密钥对生成、加密和解密。

密钥对生成

  1. 选择两个大的质数pq
  2. 计算n = p * qn用于构成公钥和私钥。
  3. 计算φ(n) = (p-1) * (q-1)φ(n)用于选择公钥指数e和私钥指数d
  4. 选择一个小于φ(n)的整数e,通常取65537(2^16 + 1),因为其具有良好的数学性质。
  5. 计算d,使得(e * d) % φ(n) = 1
  6. 公钥为(n, e),私钥为(n, d)

加密和解密

  • 加密:假设明文为M,密文C计算公式为C ≡ M^e (mod n)
  • 解密:密文C解密回明文M计算公式为M ≡ C^d (mod n)

签名和验证

  • 签名:发送方使用私钥对消息M进行签名,生成签名S ≡ M^d (mod n)
  • 验证:接收方使用发送方的公钥验证签名S,如果S^e (mod n) == M,则签名有效。

Node.js 使用 RSA 的图解框架

  1. 客户端生成密钥对:客户端使用Node.js的crypto模块生成RSA密钥对,包括一个私钥和一个公钥。
  2. 服务器发送公钥:服务器将其公钥发送给客户端。这可以通过HTTP请求、文件传输或其他通信方式完成。
  3. 客户端接收公钥:客户端接收到服务器的公钥,并将其存储起来,以便用于加密要发送给服务器的数据。
  4. 服务器接收加密数据:客户端使用服务器的公钥对数据进行加密,并将加密后的数据发送给服务器。服务器接收到加密数据。
  5. 服务器使用私钥解密数据:服务器使用其私钥对收到的加密数据进行解密,得到原始数据,并进行处理。处理完成后,服务器可以对响应数据进行加密,并将其发送回客户端。

注意:这个图解是一个简化的表示,实际应用中可能包含更多的步骤和安全措施,例如签名验证、密钥管理和存储等。

使用Node.js实现RSA

环境准备

在Node.js中,我们可以使用内置的crypto模块或第三方库node-rsa来实现RSA的功能。

使用内置crypto模块

Node.js的crypto模块提供了丰富的加密功能,包括RSA的加密和解密。

const crypto = require('crypto');

// 生成RSA密钥对
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
  modulusLength: 2048,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem'
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-256-cbc',
    passphrase: 'your-secret-passphrase'
  }
});

// 加密数据
const data = 'Hello RSA!';
const encrypted = crypto.publicEncrypt({
  key: publicKey,
  padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
  oaepHash: 'sha256'
}, Buffer.from(data));

// 解密数据
const decrypted = crypto.privateDecrypt({
  key: privateKey,
  padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
  oaepHash: 'sha256'
}, encrypted);

// RSA签名
const sign = crypto.createSign('SHA256');
sign.update(data);
const signature = sign.sign(privateKey, 'base64');

// RSA签名验证
const verify = crypto.createVerify('SHA256');
verify.update(data);
const result = verify.verify(publicKey, signature, 'base64');
使用node-rsa

node-rsa是一个纯JavaScript实现的RSA加密库,不需要依赖于任何外部的加密库。

const NodeRSA = require('node-rsa');

// 创建NodeRSA实例
const nodeRSA = new NodeRSA({ b: 2048 }); // b是密钥长度

// 生成密钥对
const keyPair = nodeRSA.generateKeyPair();

// 加密数据
const encrypted = nodeRSA.encrypt(data, 'base64', 'public');

// 解密数据
const decrypted = nodeRSA.decrypt(encrypted, 'utf8', 'private');

// RSA签名
const signature = nodeRSA.sign('SHA256', data, 'base64', 'private');

// RSA签名验证
const verifyResult = nodeRSA.verify('SHA256', data, signature, 'public');

如何使用 Node.js 进行 RSA 密钥的管理和存储?

在Node.js中进行RSA密钥的管理和存储是一个重要的安全实践。正确的管理存储机制可以确保私钥的安全性和公钥的可用性。以下是一些关于如何使用Node.js进行RSA密钥管理和存储的建议和方法:

1. 生成密钥对

首先,你需要生成RSA密钥对。在Node.js中,你可以使用crypto模块来生成密钥对。

const crypto = require('crypto');

const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
  modulusLength: 2048,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem',
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-256-cbc',
    passphrase: 'your-secret-passphrase'
  },
});

2. 存储密钥

生成密钥对后,你需要将它们安全地存储起来。以下是一些存储方法:

2.1 文件系统

将密钥存储在文件系统中是一种常见的做法。你可以将公钥和私钥写入不同的文件,并确保这些文件的权限设置得当,以防止未授权访问。

const fs = require('fs');

// 将私钥写入文件
fs.writeFileSync('private_key.pem', privateKey);

// 将公钥写入文件
fs.writeFileSync('public_key.pem', publicKey);

确保只有运行Node.js应用的用户(通常是web服务器用户)有权限访问这些文件。

2.2 环境变量

对于私钥,你可以将其存储在环境变量中,这样可以避免将其硬编码在代码中或存储在文件系统中。

process.env.PRIVATE_KEY = privateKey;

然后,你可以使用process.env.PRIVATE_KEY来访问私钥。

2.3 密钥管理服务

对于生产环境,建议使用专门的密钥管理服务(如AWS KMS、Google Cloud KMS或HashiCorp Vault)来存储和管理密钥。这些服务提供了额外的安全措施,如硬件安全模块(HSM)保护、访问控制和审计日志。

3. 加载密钥

当你需要使用密钥时,你可以从存储位置加载它们。

3.1 从文件加载

如果你将密钥存储在文件中,可以使用fs模块来加载它们。

const fs = require('fs');

// 从文件加载私钥
const privateKey = fs.readFileSync('private_key.pem', 'utf8');

// 从文件加载公钥
const publicKey = fs.readFileSync('public_key.pem', 'utf8');

3.2 从环境变量加载

如果你将密钥存储在环境变量中,可以直接使用process.env来访问它们。

const privateKey = process.env.PRIVATE_KEY;
const publicKey = process.env.PUBLIC_KEY;

3.3 从密钥管理服务加载

如果你使用密钥管理服务,通常会有相应的SDK或API来从服务中检索密钥。

4. 安全考虑

  • 保护私钥:确保私钥不会被泄露。使用强密码短语保护私钥,并限制对私钥文件的访问权限。
  • 定期轮换密钥:定期更换密钥可以减少因密钥泄露带来的风险。
  • 备份密钥:对密钥进行安全备份,以防原始密钥丢失或损坏。
  • 使用最新算法:使用最新的加密算法和足够长的密钥长度来抵御计算力的增长。

通过遵循这些最佳实践,你可以确保在Node.js应用中安全地管理和存储RSA密钥。

使用 Node.js 和 RSA 加密进行安全通信的实战案例

例子:模拟一个简单的客户端和服务器之间的安全通信过程,其中服务器使用RSA加密来保护传输的数据。这个例子将展示如何生成RSA密钥对、加密数据、发送加密数据以及服务器端解密数据的过程。

步骤 1: 生成RSA密钥对

首先,我们需要生成一对RSA密钥。在这个例子中,我们将使用Node.js的crypto模块来生成密钥对。

const crypto = require('crypto');

// 生成RSA密钥对
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
  modulusLength: 2048,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem',
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
  },
});

console.log('Public Key:', publicKey);
console.log('Private Key:', privateKey);

步骤 2: 客户端加密数据

客户端将使用服务器的公钥来加密要发送的数据。这里我们假设数据是一个简单的文本消息。

// 客户端代码
const crypto = require('crypto');

// 服务器的公钥
const publicKey = '...'; // 从步骤1中获取的公钥

// 要发送的数据
const data = 'Secret Message';

// 使用公钥加密数据
const encryptedData = crypto.publicEncrypt({
  key: publicKey,
  padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
  oaepHash: 'sha256',
}, Buffer.from(data)).toString('base64');

console.log('Encrypted Data:', encryptedData);

步骤 3: 服务器端接收并解密数据

服务器端接收到加密数据后,将使用自己的私钥来解密数据。

// 服务器端代码
const crypto = require('crypto');

// 服务器的私钥
const privateKey = '...'; // 从步骤1中获取的私钥

// 客户端发送的加密数据
const encryptedData = '...'; // 从客户端接收到的加密数据

// 使用私钥解密数据
const decryptedData = crypto.privateDecrypt({
  key: privateKey,
  padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
  oaepHash: 'sha256',
}, Buffer.from(encryptedData, 'base64')).toString('utf8');

console.log('Decrypted Data:', decryptedData);

步骤 4: 确保数据的完整性和认证

为了确保数据的完整性和认证,我们可以使用RSA签名来验证数据是否被篡改,并且确实是由预期的发送方发送的。

// 客户端签名数据
const sign = crypto.createSign('SHA256');
sign.update(data);
const signature = sign.sign(privateKey, 'base64');

// 客户端发送数据和签名给服务器

// 服务器端验证签名
const verify = crypto.createVerify('SHA256');
verify.update(data);
const isValidSignature = verify.verify(publicKey, signature, 'base64');

if (isValidSignature) {
  console.log('Signature is valid, data is authentic.');
} else {
  console.log('Signature is invalid, data may have been tampered.');
}

通过这个实战案例,我们展示了如何在Node.js中使用RSA加密来保护客户端和服务器之间的通信。我们生成了RSA密钥对,客户端使用服务器的公钥加密数据,然后服务器使用自己的私钥解密数据。此外,我们还使用了RSA签名来确保数据的完整性和认证。这种方法可以有效地防止数据在传输过程中被窃听或篡改,从而提高通信的安全性。 

总结

RSA算法作为一种非对称加密技术,在保障数据传输安全方面发挥着重要作用。Node.js提供了内置的crypto模块和第三方库node-rsa,使得在Node.js环境中实现RSA加密、解密、签名和验证变得简单易行。开发者可以根据项目需求和环境选择合适的工具进行数据加密和安全保护。

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

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

相关文章

【python】python抓取古诗文内容保存(源码)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

下载了恶意软件怎么办,用这个软件可以解决 Mac电脑卸载软件 MacBook查杀病毒

随着苹果电脑在全球市场的普及,它们也日益成为恶意软件制作者的目标。这种趋势打破了许多人认为Mac系统不易受到病毒或恶意软件影响的传统观念。事实上,苹果电脑面临的恶意软件和安全威胁正在不断增多,这要求用户采取更加积极的措施来保护自己…

activiti初次学习

源代码地址:https://gitee.com/ZSXYX/activiti.git​ 1、安装插件 首先安装下图所示activiti,不确定是哪个插件有用的,有时间可排除下 在resources下创建一个文件夹:processes,右键,新建 生成: 选中act.bpmn20.xm…

TCHouse-C

一.概括 1.地域(Region) 地域(Region)指腾讯云数据仓库 TCHouse-C 物理服务器所在的地理区域。腾讯云不同地域之间网络完全隔离,购买后不能更换。(地域一旦选定,购买后无法更改。)…

L3 【哈工大_操作系统】操作系统启动

本节要点: 1、理解 OS 启动过程发生了什么,理解 OS 与 硬件 与 应用 之间的关系 2、本节讲解了 setup 模块 和 system 模块实现的功能 1、计算机上电时,操作系统在硬盘(磁盘)上,为了“取指执行”&#xff0…

IO流基本流

目录 什么是IO流 IO流的体系 字节流 FileOutputStream FileInputStream 字符集 字符流 FileReader FileWriter 字节流和字符流的使用场景 什么是IO流 内存不能永久化存储,程序停止,数据丢失,所以要添加一个存档功能,存储到硬盘的文件,我们要知道文件在哪里和如何传…

Jmeter配置服务器监控插件

1.安装插件管理器 插件官网地址:JMeter Plugins :: JMeter-Plugins.org 点击 Plugins Manager,如上图所示, ,点击jar file下载“plugins-manager.jar”,下载后放到“jmeter\lib\ext”目录下,重启jmeter。 2.安装资源…

静电场中的导体与介质

静电场可能分布于填充了各种媒质的区域。虽然媒质宏观上保持电中性,但其内部的各种微观带电系统不可避免地会与静电场相互作用。 一般而言,媒质可分为三类:导体、介质(绝缘体)和半导体。在静电场中半导体特性与导体类似,因此仅就…

C# Window form 自定义控件的结构和设计(三)

C# Window form 自定义控件的结构和设计(三) 一、前面介绍了如何来创建第一个自定义的控件,以及一个测试程序。下面我们来看下如何在自定义控件中添加属性。 C#和其他.NET语言支持属性作为语言的第一类成员。把属性作为语言的基础属性有两点主要的有点&#xff1a…

Node.js 并发控制

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它使得 JavaScript 可以脱离浏览器在服务器端运行。由于 Node.js 采用单线程异步非阻塞 I/O 模型,它的并发处理能力也是非常强大的。本文将详细介绍 Node.js 的并发原理、概念、图解、解决方案…

洛谷-P2089 烤鸡

P2089 烤鸡 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<bits/stdc.h> using namespace std; const int N30; //const int M1e3*310; const int Mpow(3,10); int n; int arr[N]; //存临时方案 int res; //存方案数 int ans[M][N]; //存所有方案//x表示当前到…

k8s:kubectl 命令设置简写启用自动补全功能

k8s&#xff1a;kubectl 命令设置简写&启用自动补全功能 1、设置kubectl命令简写2、启用kubectl自动补全功能 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Kubernetes&#xff08;K8s&#xff09;是一个强大的容器编排平台&#xff0…

LangChain安装

安装步骤 1 安装Python环境 这里不介绍Python环境的配置&#xff0c;默认大家是已经安装并配置好Python运行环境的。 2 安装LangChain bash 复制代码 pip install langchain执行以上命令安装LangChain会默认安装LangChain的最新版本 3 测试安装结果 3.1 打印langchain版本…

如何获得easyrecovery软件密钥?2024最新学习步骤教程

如何获得easy recovery密钥&#xff1f;EasyRecovery是一款老牌的数据恢复软件&#xff0c;如果需要使用它来恢复数据&#xff0c;则需要购买密钥激活。然而&#xff0c;如果您只需要使用它一两次而不想花钱购买密钥&#xff0c;那么您可以使用免费的EasyRecovery密钥。请注意&…

贝乐虎儿歌v6.8.0解锁高级版亲子学习儿歌

软件介绍 贝乐虎儿歌免费版app&#xff0c;出自乐擎网络的创意工坊&#xff0c;专为孩子们雕琢了一系列富含创意的动画儿歌内容。这款app通过贝乐虎兄弟的可爱形象&#xff0c;让孩子们在愉快的观看中接触到各种儿歌和故事。不仅如此&#xff0c;app还巧妙地将古诗、英语等学习…

Java代码基础算法练习-求奇数和-2024.04.14

任务描述&#xff1a; 输入n个整数&#xff08;n从键盘输入&#xff0c;n>0&#xff0c;整数取值范围&#xff1a;0~1000&#xff09;&#xff0c;输出它们的奇数和。 任务要求&#xff1a; 代码示例&#xff1a; package April_2024;import java.util.Scanner;// 输入n个…

【Leetcode】1702. 修改后的最大二进制字符串

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个二进制字符串 b i n a r y binary binary &#xff0c;它仅有 0 0 0 或者 1 1 1 组成。你可以使用下面的操作任意次对它进行修改&#xff1a; 操作 1 &#xff1a;如果…

Nacos 入门篇---服务端如何处理客户端的服务注册请求?(三)

一、引言 ok呀&#xff0c;上个章节我们讲了Nacos客户端的服务自动注册&#xff0c;今天我们来看看服务端接收到了客户端的服务注册请求&#xff0c;服务端都做了哪些事情&#xff5e; 二、目录 目录 一、引言 二、目录 三、回顾上节内容&#xff1a; 四、Nacos 服务代码入…

Linux 网络排查命令

端口相关服务检查 netstat -ntpl|grep [$Port]说明&#xff1a;[$Port]为相应的端口号。 0.0.0.0代表本机上可用的任意地址。比如&#xff0c;0.0.0.0:80表示本机上所有地址的80端口。 tcp 0.0.0.0:80表示在所有的可用接口上监听TCP的80端口 如果返回结果为空&#xff0c;说明…

Java 入门教程||Java 关键字

Java 关键字 Java教程 - Java关键字 Java中的关键字完整列表 关键词是其含义由编程语言定义的词。 Java关键字和保留字&#xff1a; abstract class extends implements null strictfp true assert const false import package super try …