当前位置: 首页 > 后端技术 > Node.js

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

时间:2023-04-03 18:56:47 Node.js

博客地址:《NodeJS模块研究 - crypto》Github:https://github.com/donghubxin/blognodejs中的crypto模块提供了各种加密算法的API。本文记录常用加密算法的种类、特点、用途及代码实现。涉及的算法很多,应用范围很广,每一种算法都有自己的适用场景。为了文笔流畅,罗列一下本文记录的几种常用算法:签名与验证算法哈希(Hash)算法哈希函数(英语:Hashfunction),又称散列算法、散列函数,是一种从任何一种数据中创建小型数字“指纹”的方法。基本原理是输入任意长度的数据,最后输出固定长度的结果。哈希算法具有以下特点:不能从哈希值中推导出原始数据。不同的输入会有不同的输出。好的哈希算法发生冲突的概率较低。由于哈希算法的这些特点,哈希算法主要用于:加密、数据检查、版本识别、负载均衡、分布式(一致性哈希)。下面实现一个获取文件标识符的函数:algorithm)){thrownewError("不支持这个哈希函数");}returnnewPromise(resolve=>{consthash=crypto.createHash(algorithm);constrs=fs.createReadStream(file);rs.on("readable",()=>{constdata=rs.read();if(data){hash.update(data);}});rs.on("end",()=>{resolve(hash.digest("hex"));});});}//用法:获取文件md5getFileHash("./db.json","md5").then(val=>{console.log(val);});HMac算法攻击者可以利用“彩虹表”来破解哈希表。彩虹表的处理方法是在密码上加一个盐值(salt),与pwd和salt一起计算hash值。其中salt是随机生成的,越长越好,需要存放在用户名和密码对应的数据表中。虽然哈希长度扩展是通过加盐实现的,但攻击者也可以通过提交密码和哈希值来破解攻击。服务器会将提交的密码和盐组成一个字符串,然后与提交的哈希值进行比较。如果系统无法提交哈希,则不会受到此类攻击。显然,没有绝对安全的方法。但是不推荐密码加盐,而是HMac算法。它可以使用任何哈希函数,例如md5=>HmacMD5,sha1=>HmacSHA1。以下是使用Hmac加密数据的函数:constcrypto=require("crypto");functionencryptData(data,key,algorithm){if(!crypto.getHashes().includes(algorithm)){thrownewError("不支持此哈希函数");}consthmac=crypto.createHmac(算法,密钥);hmac.更新(数据);returnhmac.digest("hex");}//输出:30267bcf2a476abaa9b9a87dd39a1f8d6906d1180451abdcb4confloga(Data"root","7(23y*&745^%I","sha256"));对称加密(AES)和非对称加密解密(RSA)有很多数据需要加密存储,需要解密才能使用。这与之前的不可逆哈希函数不同。此类算法分为两类:对称加密(AES):加密和解密使用相同的密钥非对称加密和解密(RSA):公钥加密,私钥解密对称加密(AES)查看nodejs支持的所有加密算法:crypto.getCiphers();Nodejs提供了Cipher类和Decipher类,分别用于加密和解密。两者都继承了TransfromStream,API使用方法和hash函数API使用方法类似。下面是用aes-256-cbc算法加密明文:constcrypto=require("crypto");constsecret=crypto.randomBytes(32);//keyconstcontent="helloworld!";//要求加密明文constcipher=crypto.createCipheriv("aes-256-cbc",secret,Buffer.alloc(16,0));cipher.update(content,"utf8");//加密结果:e2a927165757acc609a89c093d8e3af5console.日志(密码。最终(“十六进制”));注意:使用加密算法时,需要给定密钥长度,否则会显示this[kHandle].initiv(cipher,credential,iv,authTagLength);错误:密钥长度无效...错误。以aes-256-cbc算法为例,需要一个大小为256位=32字节的密钥。同样,AES的IV也是需要的,需要128位。(请参考“参考链接”部分)以32个连续的I's为密钥,用aes-256-cbc加密后的结果为a061e67f5643d948418fdb150745f24d。下面是反向解密过程:constsecret="I".repeat(32);constdecipher=crypto.createDecipheriv("aes-256-cbc",secret,Buffer.alloc(16,0));decipher.update("a061e67f5643d948418fdb150745f24d","hex");console.log(decipher.final("utf8"));//解密结果:helloworld!非对称加密解密(RSA)使用openssl生成私钥和公钥:#生成私钥opensslgenrsa-outprivatekey.pem1024#生成公钥opensslrsa-inprivatekey.pem-pubout-outpublickey.pem的代码加密和解密你好世界!如下:constcrypto=require("crypto");constfs=require("fs");constprivateKey=fs.readFileSync("./privatekey.pem");constpublicKey=fs.readFileSync("./publickey.pem");constcontent="helloworld!";//要加密的明文内容//公钥加密constencodeData=crypto.publicEncrypt(publicKey,Buffer.from(content));console.log(encodeData.toString("base64"));//私钥解密constdecodeData=crypto.privateDecrypt(privateKey,encodeData);console.log(decodeData.toString("utf8"));签名和验证算法除了不可逆哈希算法和数据加密算法外,还有专门的签名和验证算法。这里还需要使用openssl来生成公钥和私钥。代码演示如下:constcrypto=require("crypto");constfs=require("fs");constassert=require("assert");constprivateKey=fs.readFileSync("./privatekey.pem");constpublicKey=fs.readFileSync("./publickey.pem");constdata="transmitteddata";//第一步:使用私钥传输数据并生成相应的签名constsign=crypto.createSign("sha256");//添加数据sign.update(data,"utf8");sign.end();//根据私钥,生成签名constsignature=sign.sign(privateKey,"hex");//第二步:借助公钥验证签名的准确性constverify=crypto.createVerify("sha256");verify.update(data,"utf8");verify.end();assert.ok(verify.verify(publicKey,signature,"hex"));从前面的代码可以看出,使用私钥加密得到签名值;最后使用公钥进行验证。总结一下,之前一直都是一知半解,有些概念很模糊,哈希算法和加密算法经常混淆。整理了这篇笔记,搞清楚了常见的加密算法的作用和用途。此外,crypto模块还提供了其他算法工具,如ECDH在区块链??中有应用。本文不再记录,有兴趣的同学可以查看相关资料。参考链接NodeJS文档:Crypto推荐:Node.js加密算法库Crypto推荐:什么是哈希?-腾讯技术工程解答-知乎维基:哈希函数存储和验证哈希密码维基:彩虹表Nodejs6.10.2cryptoAESInvalidkeylengthEncryptioningusingAES-256,IcanIuse256bitsIV?Cryptoencryptionanddecryption?扫码关注“新坛”博客”,查看“前端图谱”&“算法方案”,坚持分享,共同成长?