Nodejs实战系列:数据加密与crypto模块

nodejs 中的 crypto 模块提供了各种各样加密算法的 API。这篇文章记录了常用加密算法的种类、特点、用途和代码实现。其中涉及算法较多,应用面较广,每类算法都有自己适用的场景。为了使行文流畅,列出了本文记录的几类常用算法:
内容摘要:散列(Hash)算法 内容摘要:HMac 算法 内容加解密:对称加密(AES)与非对称加密解密(RSA) 内容签名:签名和验证算法
散列(Hash)算法
散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。基本原理是将任意长度数据输入,最后输出固定长度的结果。
hash 算法具有以下特点:
不能从 hash 值倒推原数据 不同的输入,会有不同的输出 好的 hash 算法冲突概率更低
正因为 hash 算法的这些特点,因此 hash 算法主要用于:加密、数据检验、版本标识、负载均衡、分布式(一致性 hash)。
下面实现了一个获取文件标识的函数:
const crypto = require("crypto");
const fs = require("fs");
function getFileHash(file, algorithm) {
if (!crypto.getHashes().includes(algorithm)) {
throw new Error("不支持此哈希函数");
}
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">return</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">new</span> <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">Promise</span>(<span class="hljs-function" style="line-height: 26px;"><span class="hljs-params" style="line-height: 26px;">resolve</span> =></span> {
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> hash = crypto.createHash(algorithm);
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> rs = fs.createReadStream(file);
rs.on(<span class="hljs-string" style="color: #d14; line-height: 26px;">"readable"</span>, () => {
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> data = rs.read();
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">if</span> (data) {
hash.update(data);
}
});
rs.on(<span class="hljs-string" style="color: #d14; line-height: 26px;">"end"</span>, () => {
resolve(hash.digest(<span class="hljs-string" style="color: #d14; line-height: 26px;">"hex"</span>));
});
});
}
// 用法:获取文件md5
getFileHash("./db.json", "md5").then(val => {
console.log(val);
});
HMac 算法
攻击者可以借助“彩虹表”来破解哈希表。应对彩虹表的方法,是给密码加盐值(salt),将 pwd 和 salt 一起计算 hash 值。其中,salt 是随机生成的,越长越好,并且需要和用户名、密码对应保存在数据表中。
虽然通过加盐,实现了哈希长度扩展,但是攻击者通过提交密码和哈希值也可以破解攻击。服务器会把提交的密码和 salt 构成字符串,然后和提交的哈希值对比。如果系统不能提交哈希值,不会受到此类攻击。
显然,没有绝对安全的方法。但是不推荐使用密码加盐,而是 HMac 算法。它可以使用任意的 Hash 函数,例如 md5 => HmacMD5、sha1 => HmacSHA1。
下面是利用 Hmac 实现加密数据的函数:
const crypto = require("crypto");
function encryptData(data, key, algorithm) {
if (!crypto.getHashes().includes(algorithm)) {
throw new Error("不支持此哈希函数");
}
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> hmac = crypto.createHmac(algorithm, key);
hmac.update(data);
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">return</span> hmac.digest(<span class="hljs-string" style="color: #d14; line-height: 26px;">"hex"</span>);
}
// output: 30267bcf2a476abaa9b9a87dd39a1f8d6906d1180451abdcb8145b384b9f76a5
console.log(encryptData("root", "7(23y*&745^%I", "sha256"));
对称加密(AES)与非对称加密解密(RSA)
有很多数据需要加密存储,并且需要解密后进行使用。这和前面不可逆的哈希函数不同。此类算法一共分为两类:
对称加密(AES):加密和解密使用同一个密钥 非对称加密解密(RSA):公钥加密,私钥解密
对称加密(AES)
查看 nodejs 支持的所有加密算法:
crypto.getCiphers();
Nodejs 提供了 Cipher 类和 Decipher 类,分别用于加密和解密。两者都继承 Transfrom Stream,API 的使用方法和哈希函数的 API 使用方法类似。
下面是用 aes-256-cbc 算法对明文进行加密:
const crypto = require("crypto");
const secret = crypto.randomBytes(32); // 密钥
const content = "hello world!"; // 要加密的明文
const cipher = crypto.createCipheriv(
"aes-256-cbc",
secret,
Buffer.alloc(16, 0)
);
cipher.update(content, "utf8");
// 加密后的结果:e2a927165757acc609a89c093d8e3af5
console.log(cipher.final("hex"));
注意:在使用加密算法的时候,给定的密钥长度是有要求的,否则会爆出this[kHandle].initiv(cipher, credential, iv, authTagLength); Error: Invalid key length...的错误。以 aes-256-cbc 算法为例,需要 256 bits = 32 bytes 大小的密钥。同样地,AES 的 IV 也是有要求的,需要 128bits。(请参考“参考链接”部分)
使用 32 个连续I作为密钥,用 aes-256-cbc 加密后的结果是 a061e67f5643d948418fdb150745f24d。下面是逆向解密的过程:
const secret = "I".repeat(32);
const decipher = crypto.createDecipheriv(
"aes-256-cbc",
secret,
Buffer.alloc(16, 0)
);
decipher.update("a061e67f5643d948418fdb150745f24d", "hex");
console.log(decipher.final("utf8")); // 解密后的结果:hello world!
非对称加密解密(RSA)
借助 openssl 生成私钥和公钥:
# 生成私钥
openssl genrsa -out privatekey.pem 1024
# 生成公钥
openssl rsa -in privatekey.pem -pubout -out publickey.pem
对 hello world! 加密和解密的代码如下:
const crypto = require("crypto");
const fs = require("fs");
const privateKey = fs.readFileSync("./privatekey.pem");
const publicKey = fs.readFileSync("./publickey.pem");
const content = "hello world!"; // 待加密的明文内容
// 公钥加密
const encodeData = crypto.publicEncrypt(publicKey, Buffer.from(content));
console.log(encodeData.toString("base64"));
// 私钥解密
const decodeData = crypto.privateDecrypt(privateKey, encodeData);
console.log(decodeData.toString("utf8"));
签名和验证算法
除了不可逆的哈希算法、数据加密算法,还有专门用于签名和验证的算法。这里也需要用 openssl 生成公钥和私钥。
代码示范如下:
const crypto = require("crypto");
const fs = require("fs");
const assert = require("assert");
const privateKey = fs.readFileSync("./privatekey.pem");
const publicKey = fs.readFileSync("./publickey.pem");
const data = "传输的数据";
// 第一步:用私钥对传输的数据,生成对应的签名
const sign = crypto.createSign("sha256");
// 添加数据
sign.update(data, "utf8");
sign.end();
// 根据私钥,生成签名
const signature = sign.sign(privateKey, "hex");
// 第二步:借助公钥验证签名的准确性
const verify = crypto.createVerify("sha256");
verify.update(data, "utf8");
verify.end();
assert.ok(verify.verify(publicKey, signature, "hex"));
从前面这段代码可以看到,利用私钥进行加密,得到签名值;最后利用公钥进行验证。
总结
之前一直是一知半解,一些概念很模糊,经常混淆散列算法和加密算法。整理完这篇笔记,我才理清楚了常见的加密算法的功能和用途。
除此之外,crypto 模块还提供了其他算法工具,例如 ECDH 在区块链中有应用。这篇文章没有再记录,感兴趣的同学可以去查阅相关资料。
参考链接
NodeJS docs: crypto 推荐:Node.js 加密算法库 Crypto 推荐:什么是 hash? - 腾讯技术工程的回答 - 知乎 Wiki:散列函数 Store and validate hashed password Wiki: 彩虹表 Nodejs 6.10.2 crypto AES Invalid key length Encrypting using AES-256, can I use 256 bits IV? Crypto 加密与解密

Nodejs实战系列:数据加密与crypto模块的更多相关文章
- Java秒杀系统实战系列~构建SpringBoot多模块项目
摘要:本篇博文是“Java秒杀系统实战系列文章”的第二篇,主要分享介绍如何采用IDEA,基于SpringBoot+SpringMVC+Mybatis+分布式中间件构建一个多模块的项目,即“秒杀系统”! ...
- Nodejs进阶:MD5入门介绍及crypto模块的应用
本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 简介 MD5(Message-Digest Algorithm) ...
- Nodejs进阶:crypto模块中你需要掌握的安全基础
本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址. 一. 文章概述 互联网时代,网络上的数据量每天都在以惊人的速度增长.同时,各类网络安全问题层出不穷.在信 ...
- nodeJS之crypto模块md5和Hmac加密
nodeJS之crypto模块md5和Hmac加密 原文地址:https://www.cnblogs.com/tugenhua0707/p/9128690.html 在nodejs中,可以使用cryp ...
- nodeJS之crypto模块公钥加密及解密
nodeJS之crypto模块公钥加密及解密 NodeJS有以下4个与公钥加密相关的类.1. Cipher: 用于加密数据:2. Decipher: 用于解密数据:3. Sign: 用于生成签名:4. ...
- NodeJS学习笔记 进阶 (12)Nodejs进阶:crypto模块之理论篇
个人总结:读完这篇文章需要30分钟,这篇文章讲解了使用Node处理加密算法的基础. 摘选自网络 Nodejs进阶:crypto模块之理论篇 一. 文章概述 互联网时代,网络上的数据量每天都在以惊人的速 ...
- Nodejs:md5入门介绍及crypto模块的应用
简介 MD5(Message-Digest Algorithm)是计算机安全领域广泛使用的散列函数(又称哈希算法.摘要算法),主要用来确保消息的完整和一致性.常见的应用场景有密码保护.下载文件校验等. ...
- react实战系列 —— 起步(mockjs、第一个模块、docusaurus)
其他章节请看: react实战 系列 起步 本篇我们首先引入 mockjs ,然后进入 spug 系统,接着模仿"任务计划"模块实现一个类似的一级导航页面("My任务计划 ...
- 使用nodeJS的 crypto模块来为你的密码hash加盐
这篇文章将向你解释如何使用Node.js的Crypto模块对你的密码进行加盐hash.在这里,我们将不会对不懂的密码存储方式进行详细的比较.我们将要做的是知道在Node.js中使用加盐hash在进行密 ...
随机推荐
- requests + bs4 爬取豌豆荚所有应用的信息
1.分析豌豆荚的接口的规律 - 获取所有app的接口url 2.往每一个接口发送请求,获取json数据 解析并提取想要的数据 app_data: 1.图标 app_img_url 2.名字 app_n ...
- python实现上传文件到linux指定目录
今天接到一个小需求,就是想在windows环境下,上传压缩文件到linux指定的目录位置并且解压出来,然后我想了一下,这个可以用python试试写下. 环境:1.linux操作系统一台2.window ...
- QT信号和槽函数学习笔记
//connect 函数有4个参数 分别是 发送者 信号.接受者 ,槽 //connect(sender,signal,receiver,slot) /* * 信号和槽 * 信号 就是一个普通的函数 ...
- shell点名脚本不重复人名
效果如图: 代码如下: #!/bin/bash #Author:GaoHongYu #QQ: #Time:-- :: #Name:dm.sh #Version:V1. stu=(刘一 陈二 张三 李四 ...
- Python for Data Analysis 学习心得(二) - pandas介绍
一.pandas介绍 本篇程序上篇内容,在numpy下面继续介绍pandas,本书的作者是pandas的作者之一.pandas是非常好用的数据预处理工具,pandas下面有两个数据结构,分别为Seri ...
- C++简单项目--推箱子
在处理移动的时候有太多种情况了: 1.有空位 2.在推箱子,推到了空地 3.推箱子推到了目标, 4.推目标位的箱子推到另一个目标 5.推目标位的箱子推到空地 首先记录目标位置,在每次推动之后会再绘画中 ...
- HashMap中的位运算
二进制基础回顾 以下操作相对正整数的二进制而言,对非整数不太适用. 二进制转十进制 在二进制中,位权是2的幂,所以每一位所代表的权值从右到左分别为2^(1-1) .2^(2-1) .... . 2 ...
- 迷你PS小程序-集成的开放式画报、油墨电子签名、图片拖拽可单独食用
米娜桑,哦哈哟~ 个人制作,该文章主要讲解最近基于uni-app框架编写的集图文拖拽等多方位编辑.油墨电子签名.开放式海报于一体的小程序的制作思路和实现代码. 目录 1.完整源码链接 2.实现思路 3 ...
- GXOI&GZOI
T1 与或和 2s&&512MB 简明题意:求一个矩阵的所有子序列的 \(and\)和 和\(or\)和: 子矩阵的\(and\)和就是所有值\(and\)起来:\(or\)类 ...
- C#调用Matlab生成的Dll
问题描述:最近开发需要调用matlab生成的DLL,在New MWNumericArray 对象的时候报错,提示未将对象引用到对象的实例. 问题分析:因为MWArray.dll是Matlab提供的DL ...