NodeJS 加密 —— crypto 模块
原文出自:https://www.pandashen.com
加密简介
加密是以某种算法改变原有的信息数据,使得未授权用户即使获得了已加密信息,因不知解密的方法,无法得知信息真正的含义,通过这种方式提高网络数据传输的安全性,加密算法常见的有哈希算法、HMAC 算法、签名、对称性加密算法和非对称性加密算法,加密算法也分为可逆和不可逆,比如 md5
就是不可逆加密,只能暴力破解(撞库),我们在 NodeJS 开发中就是直接使用这些加密算法,crypto
模块提供了加密功能,包含对 OpenSSL
的哈希、HMAC、加密、解密、签名以及验证功能的一整套封装,核心模块,使用时不需安装。
哈希算法
哈希算法也叫散列算法,用来把任意长度的输入变换成固定长度的输出,常见的有 md5
、sha1
等,这类算法实现对原数据的转化过程是否能被称为加密备受争议,为了后面叙述方便我们姑且先叫做加密。
// 查看哈希加密算法的种类
const crypto = require("crypto");// getHashes 方法用于查看支持的加密算法
console.log(crypto.getHashes());// [ 'DSA', 'DSA-SHA', 'DSA-SHA1', 'DSA-cSHA1-old',
// 'RSA-MD4', 'RSA-MD5', 'RSA-MDC2', 'RSA-RIPEMD160',
// 'RSA-SHA', 'RSA-SHA1', 'RSA-SHA1-2', 'RSA-SHA224',
// 'RSA-SHA256', 'RSA-SHA384', 'RSA-SHA512',
// 'dsaEncryption', 'dsaWithSHA', 'dsaWithSHA1', 'dss1',
// 'ecdsa-with-SHA1', 'md4', 'md4WithRSAEncryption',
// 'md5', 'md5WithRSAEncryption', 'mdc2', 'mdc2WithRSA',
// 'ripemd', 'ripemd160', 'ripemd160WithRSA', 'rmd160',
// 'sha', 'sha1', 'sha1WithRSAEncryption', 'sha224',
// 'sha224WithRSAEncryption', 'sha256',
// 'sha256WithRSAEncryption', 'sha384',
// 'sha384WithRSAEncryption', 'sha512',
// 'sha512WithRSAEncryption', 'shaWithRSAEncryption',
// 'ssl2-md5', 'ssl3-md5', 'ssl3-sha1', 'whirlpool' ]
md5
是开发中经常使用的算法之一,官方称为摘要算法,具有以下几个特点:
- 不可逆;
- 不管加密的内容多长,最后输出的结果长度都是相等的;
- 内容不同输出的结果完全不同,内容相同输出的结果完全相同。
由于相同的输入经过 md5
加密后返回的结果完全相同,所以破解时通过 “撞库” 进行暴力破解,当连续被 md5
加密 3
次以上时就很难被破解了,所以使用 md5
一般会进行多次加密。
// md5 加密 —— 返回 Buffer
const crytpo = require("crytpo");let md5 = crytpo.createHash("md5"); // 创建 md5
let md5Sum = md5.update("hello"); // update 加密
let result = md5Sum.digest(); // 获取加密后结果console.log(result); // <Buffer 5d 41 40 2a bc 4b 2a 76 b9 71 9d 91 10 17 c5 92>
digest
方法参数用于指定加密后的返回值的格式,不传参默认返回加密后的 Buffer,常用的参数有 hex
和 Base64
,hex
代表十六进制,加密后长度为 32
,Base64
的结果长度为 24
,以 ==
结尾。
// md5 加密 —— 返回十六进制
const crypto = require("crypto");let md5 = crypto.createHash("md5");
let md5Sum = md5.update("hello");
let result = md5Sum.digest("hex");console.log(result); // 5d41402abc4b2a76b9719d911017c592
// md5 加密 —— 返回 Base64
const crypto = require("crypto");let md5 = crypto.createHash("md5");
let md5Sum = md5.update("hello");
let result = md5Sum.digest("Base64");console.log(result); // XUFAKrxLKna5cZ2REBfFkg==
update
方法的返回值就是 this
,即当前实例,所以支持链式调用,较长的信息也可以多次调用 update
方法进行分段加密,调用 digest
方法同样会返回整个加密后的值。
// 链式调用和分段加密
const crypto = require("crypto");let result = crypto.createHash("md5").update("he").update("llo").digest("hex");console.log(result); // 5d41402abc4b2a76b9719d911017c592
由于可以使用 update
进行分段加密,就可以结合流来使用,其实 crypto
的本质是创建 Transform
类型的转化流,可以将可读流转化成可写流。
// 对可读流读取的数据进行 md5 加密
const crypto = require("crypto");
let fs = require("fs");let md5 = crypto.createHash("md5");
let rs = fs.createReadSteam("./readme.txt", {highWaterMark: 3
});// 读取数据并加密
rs.on("data", data => md5.update(data));rs.on("end", () => {let result = md5.digest("hex");console.log(result);
});
使用场景 1:经常被使用在数据的校验,比如服务器与服务器之间进行通信发送的明文摘要加 md5
加密摘要后的暗文,接收端拿到数据以后将明文摘要按照相同的 md5
算法加密后与暗文摘要对比验证,目的是防止数据传输过程中被劫持并篡改。
使用场景 2:在浏览器缓存策略中,可以通过对静态资源的信息摘要使用 md5
加密,每次向服务器发送加密后的密钥进行比对就可以了,不至于对整个文件内容进行比较。
缺点:由于规定使用 md5
的哈希算法加密,别人可以使用同样的算法对信息进行伪造,安全性不高。
Hmac 算法
1、Hmac 算法的使用
Hmac 算法又称加盐算法,是将哈希算法与一个密钥结合在一起,用来阻止对签名完整性的破坏,同样具备 md5
加密的几个特点。
// 使用加盐算法加密
const crytpo = require("crytpo");let hmac = crytpo.createHmac("sha1", "panda");
let result = hmac.update("hello").digest("Base64");console.log(result); // 7spMLxN8WJdcEtQ8Hm/LR9pUE3YsIGag9Dcai7lwioo=
crytpo.createHmac
第一个参数同 crytpo.createHash
,为加密的算法,常用 sha1
和 sha256
,第二个参数为密钥。
digest
方法生成的加密结果长度要大于 md5
,hex
生成的结果长度为 64
,Base64
生成的结果长度为 44
,以 =
结尾。
安全性高于 md5
,通过密钥来加密,不知道密钥无法破解,缺点是密钥传输的过程容易被劫持,可以通过一些生成随机密钥的方式避免。
2、创建密钥的方法
可以安装 openSSH
客户端,并通过命令行生成存储密钥的文件,命令如下。
openssl genrsa -out rsa_private.key 1024
openssl genrsa
代表生成密钥,-out
代表输出文件,rsa_private.key
代表文件名,1024
代表输出密钥的大小。
// 直接读取密钥文件配合加盐算法加密
const fs = require("fs");
const crytpo = require("crytpo");
const path = require("path");let key = fs.readFileSync(path.join(__dirname, "/rsa_private.key"));
let hmac = crytpo.createHmac("sha256", key);let result = hmac.update("hello").digest("Base64");console.log(result); // bmi2N+6kwgwt5b+U+zSgjL/NFs+GsUnZmcieqLKBy4M=
对称性加密
对称性加密是发送数据时使用密钥和加密算法进行加密,接收数据时需要使用相同的密钥和加密算法的逆算法(解密算法)进行解密,也就是说对称性加密的过程是可逆的,crytpo
中使用的算法为 blowfish
。
// 对称性加密
const fs = require("fs");
const crypto = require("crypto");
const path = require("path");let key = fs.readFileSync(path.join(__dirname, "/rsa_private.key"));// 加密
let cipher = crypto.createCipher("blowfish", key);
cipher.update("hello");// final 方法不能链式调用
let result = cipher.final("hex");
console.log(result); // 3eb9943113c7aa1e// 解密
let decipher = crypto.createDecipher("blowfish", key);
decipher.update(result, "hex");let data = decipher.final("utf8");
console.log(data); // hello
加密使用 crypto.createCipher
方法,解密使用 crypto.createDecipher
方法,但是使用的算法和密钥必须相同,需要注意的是解密过程中 update
中需要在第二个参数中指定加密时的格式,如 hex
,在 final
还原数据时需要指定加密字符的编码格式,如 utf8
。
注意:使用对称性加密的字符串有长度限制,不得超过 7
个字符,否则虽然可以加密成功,但是无法解密。
缺点:密钥在传输过程中容易被截获,存在安全风险。
非对称性加密
非对称性加密相也是可逆的,较于对称性加密要更安全,消息传输方和接收方都会在本地创建一对密钥,公钥和私钥,互相将自己的公钥发送给对方,每次消息传递时使用对方的公钥加密,对方接收消息后使用他的的私钥解密,这样在公钥传递的过程中被截获也无法解密,因为公钥加密的消息只有配对的私钥可以解密。
接下来我们使用 openSSH
对之前生成的私钥 rsa_private.key
产生一个对应的公钥,命令如下。
openssl rsa -in rsa_private.key -pubout -out rsa_public.key
上面的命令意思根据一个私钥生成对应的公钥,-pubout -out
代表公钥输出,rsa_public.key
为公钥的文件名。
// 非对称性加密
const fs = require("fs");
const crypto = require("crypto");
const path = require("path");// 获取公钥和私钥
let publicKey = fs.readFileSync(path.join(__dirname, "/rsa_public.key"));
let privateKey = fs.readFileSync(path.join(__dirname, "/rsa_private.key"));// 加密
let secret = crytpo.publicEncrypt(publicKey, Buffer.from("hello"));// 解密
let result = crytpo.provateDecrypt(privateKey, secret);console.log(result); // hello
使用公钥加密的方法是 crytpo.publicEncrypt
,第一个参数为公钥,第二个参数为加密信息(必须是 Buffer),使用私钥解密的方法是 crytpo.provateDecrypt
,第一个参数为私钥,第二个参数为解密的信息。
签名
签名与非对称性加密非常类似,同样有公钥和私钥,不同的是使用私钥加密,对方使用公钥进行解密验证,以确保这段数据是私钥的拥有者所发出的原始数据,且在网络中的传输过程中未被修改。
我们还使用 rsa_public.key
和 rsa_private.key
作为公钥和私钥,crypto
实现签名代码如下。
// 签名
const fs = require("fs");
const crypto = require("crypto");
const path = require("path");// 获取公钥和私钥
let publicKey = fs.readFileSync(path.join(__dirname, "rsa_public.key"), "ascii");
let privateKey = fs.readFileSync(path.join(__dirname, "rsa_private.key"), "ascii");// 生成签名
let sign = crypto.createSign("RSA-SHA256");
sign.update("panda");
let signed = sign.sign(privateKey, "hex");// 验证签名
let verify = crypto.createVerify("RSA-SHA256");
verify.update("panda");
let verifyResult = verify.verify(publicKey, signed, "hex");console.log(verifyResult); // true
生成签名的 sign
方法有两个参数,第一个参数为私钥,第二个参数为生成签名的格式,最后返回的 signed
为生成的签名(字符串)。
验证签名的 verify
方法有三个参数,第一个参数为公钥,第二个参数为被验证的签名,第三个参数为生成签名时的格式,返回为布尔值,即是否通过验证。
使用场景:经常用于对 cookie 签名返回浏览器,当浏览器访问同域服务器将 cookie 带过来时再进行验证,防止 cookie 被篡改和 CSRF 跨站请求伪造。
总结
各种项目在数据传输时根据信息的敏感度以及用途进行不同的加密算法和加密方式,在 NodeJS 中,crypto
的 API 完全可以实现我们的加密需求,也可以将上面的加密方案组合使用实现更复杂的加密方案。
NodeJS 加密 —— crypto 模块相关推荐
- nodeJS之crypto加密
加密模块提供了 HTTP 或 HTTPS 连接过程中封装安全凭证的方法.也提供了 OpenSSL 的哈希,hmac, 加密(cipher), 解密(decipher), 签名(sign) 和 验证(v ...
- node 加密解密模块_跨语言(java vs python vs nodejs)的RSA加解密问题探讨
多次被问到这样的问题: java服务端的rsa加密操作已经完成,返回一个16进制的字符串给python平台,但是在python进行私钥解密的时候发现行不通.... 前端python加密,后端用java ...
- node 加密解密模块_NodeJS之crypto模块公钥加密及解密
NodeJS有以下4个与公钥加密相关的类. Cipher: 用于加密数据: Decipher: 用于解密数据: Sign: 用于生成签名: Verify: 用于验证签名: 在使用公钥加密技术时,需要使 ...
- 使用crypto模块实现md5加密功能(解决中文加密前后端不一致的问题)
使用crypto模块实现md5加密功能(解决中文加密前后端不一致的问题) 参考文章: (1)使用crypto模块实现md5加密功能(解决中文加密前后端不一致的问题) (2)https://www.cn ...
- Python crypto模块实现RSA和AES加密解密
Python crypto模块实现RSA和AES加密解密 Python的crypto是用于RSA加密解密,AES加密解密的. 一.RSA和AES简介 RSA加密算法是一种非对称加密算法.RSA 是19 ...
- node 加密解密模块_聊聊Node加密模块crypto加密原理的那些事
crypto是node.js中实现加密和解密的模块 在node.js中,使用OpenSSL类库作为内部实现加密解密的手段 OpenSSL是一个经过严格测试的可靠的加密与解密算法的实现工具. 散列(哈希 ...
- 使用 crypto 模块进行加密和解密
crypto 1 哈希算法 hash 2 对称加密 AES crypto模块的主要功能有 哈希算法.对称加密以及非对称加密. 1 哈希算法 hash hash 通常给数据签名,它是一种不可逆的加密算法 ...
- python crypto模块详解_crypto
crypto模块的目的是为了提供通用的加密和哈希算法.用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢.Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaS ...
- python3 安装模块_python3 Crypto模块的安装与使用
前言 安装Cryto模块用pip3 install pycrypto老是会报错.搞了半天,最终决定在linux下面去做. 以下流程限于linux系统: Crypto不是自带的模块,需要下载. 我下载了 ...
最新文章
- PNAS:多年多点5千样本鉴定玉米根际可遗传微生物
- SAP MIGO + 311将库存从IM管理库存地转入WM管理库存地,物料凭证号里不显示WM 选项卡
- java List集合总结
- Path does not chain with any of the trust anchors
- .NET与鲲鹏共展翅,昇腾九万里(一)
- AcWing 3195. 有趣的数
- spring-bean版本_如何模拟Spring bean(版本2)
- Spark踩坑记——数据库(Hbase+Mysql)转
- 我用Python把抖音上的美女图片转字符画,期望的AI目标更进一步【机器学习算法实战小项目,k聚类算法图片转化字符画】
- java编程的逻辑 京东,从阿里,京东等大厂面试题中提炼出25道最频繁出现的并发编程难题(附答案)...
- 第五章:物理网络层概述
- KEIL下载程序失败系列问题
- java实现行政区域划分_java解析中国行政区域并在页面显示实现动态逐级筛选
- 计算机网络6版,计算机网络教程(第6版)
- 静态淘宝热卖界面(纯CSS)
- 微信好友大揭秘,使用Python抓取朋友圈数据,通过人脸识别全面分析好友,一起看透你的“朋友圈”
- 编译安装httpd服务
- internet时间同步服务器地址(中国国家授时中心)
- latex大括号 多行公式_怎样在word中快速输入复杂的公式(在线识别数学、物理或化学公式)?...
- 那款降噪耳机好用?平价党降噪耳机推荐
热门文章
- matlab中的 complete,Complete-collection-of-algorithm
- php 增加数组下标_PHP数组排序更改下标KEY方法
- mongodb获取数组中只符合条件的元素
- 数字ab写成c语言表达式,《c语言程序设计》复习题.pdf
- matlab三次多样式对函数拟合,Matlab regress函数拟合多个变量分析
- mysql的槽_Mysql槽点 - MySQL及其它开源数据库 - ITPUB论坛-中国专业的IT技术社区...
- 生成jacoco报告_测开技能之如何利用ant jacoco 合并覆盖率报告
- uinput 用法 android 上层使用uinput 的用法来模拟 input 事件
- VB判断指定名字的进程是否存在函数
- Visual Basic编程常见问题及解答(3)