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 (!Hashes().includes(algorithm)) {
throw new Error("不⽀持此哈希函数");
}
return new Promise(resolve => {
const hash = ateHash(algorithm);
const rs = fs.createReadStream(file);
<("readable", () => {
const data = rs.read();
if (data) {
hash.update(data);
}
});
<("end", () => {
resolve(hash.digest("hex"));
});
});
}
// ⽤法:获取⽂件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 (!Hashes().includes(algorithm)) {
throw new Error("不⽀持此哈希函数");
}
const hmac = ateHmac(algorithm, key);
hmac.update(data);
return hmac.digest("hex");
}
// output: 30267bcf2a476abaa9b9a87dd39a1f8d6906d1180451abdcb8145b384b9f76a5
console.log(encryptData("root", "7(23y*&745^%I", "sha256"));
对称加密(AES)与⾮对称加密解密(RSA)
有很多数据需要加密存储,并且需要解密后进⾏使⽤。这和前⾯不可逆的哈希函数不同。此类算法⼀共分为两类:
对称加密(AES):加密和解密使⽤同⼀个密钥
⾮对称加密解密(RSA):公钥加密,私钥解密
对称加密(AES)
查看 nodejs ⽀持的所有加密算法:
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 = ateCipheriv(
"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 的错误。以 aes-256-cbc 算法为例,需要 256 bits = 32 bytes ⼤⼩的密钥。同样地,AES 的 IV 也是有要求的,需要128bits。(请参考“参考链接”部分)
使⽤ 32 个连续I作为密钥,⽤ aes-256-cbc 加密后的结果是 a061e67f5643d948418fdb150745f24d。下⾯是逆向解密的过程:
const secret = "I".repeat(32);
const decipher = ateDecipheriv(
"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.String("base64"));
js代码加密软件// 私钥解密
const decodeData = crypto.privateDecrypt(privateKey, encodeData);
console.String("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 = ateSign("sha256");
// 添加数据
sign.update(data, "utf8");
// 根据私钥,⽣成签名
const signature = sign.sign(privateKey, "hex");
// 第⼆步:借助公钥验证签名的准确性
const verify = ateVerify("sha256");
verify.update(data, "utf8");
assert.ok(verify.verify(publicKey, signature, "hex"));
从前⾯这段代码可以看到,利⽤私钥进⾏加密,得到签名值;最后利⽤公钥进⾏验证。
总结
之前⼀直是⼀知半解,⼀些概念很模糊,经常混淆散列算法和加密算法。整理完这篇笔记,我才理清楚了常见的加密算法的功能和⽤途。
除此之外,crypto 模块还提供了其他算法⼯具,例如 ECDH 在区块链中有应⽤。这篇⽂章没有再记录,感兴趣的同学可以去查阅相关资料。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论