阅读原文加密介绍加密就是将原有的信息数据用一定的算法进行改变,这样即使未经授权的用户获得了加密后的信息,也无法知道信息的真正含义,因为他们不知道不知道解密方式这样就提高了网络数据传输的安全性。常见的加密算法有散列算法、HMAC算法、签名、对称加密算法和非对称加密算法。加密算法也分为可逆和不可逆。比如md5是不可逆加密,只能暴力破解(碰撞库)。我们直接在NodeJS开发中使用这些加密算法。crypto模块提供加密功能,包括hash、HMAC、OpenSSL的加密、解密、签名和验证功能。整个包,核心模块,使用时无需安装。哈希算法哈希算法也称为哈希算法,用于将任意长度的输入转换为固定长度的输出。常见的有md5、sha1等,这类算法实现原始数据的转换过程能不能称为加密是有争议的。为了后面的描述方便,先称之为加密。//查看hash加密算法类型constcrypto=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加密后返回的结果完全相同,所以连续3次以上md5加密就很难被破解。所以md5一般是多次使用。加密。//md5加密-返回Bufferconstcrytpo=require("crytpo");letmd5=crytpo.createHash("md5");//创建md5letmd5Sum=md5.update("hello");//更新加密letresult=md5Sum.digest();//获取加密结果console.log(result);//digest方法参数用于指定加密返回值的格式。如果不传参数,默认返回加密后的Buffer。常用的参数有hex和Base64。Hex代表十六进制,加密长度为32,Base64结果长度为24,以==结尾。//md5加密-返回十六进制constcrypto=require("crypto");letmd5=crypto.createHash("md5");letmd5Sum=md5.update("hello");letresult=md5Sum.摘要(“十六进制”);console.log(结果);//5d41402abc4b2a76b9719d911017c592//md5加密-返回Base64constcrypto=require("crypto");letmd5=crypto.createHash("md5");letmd5Sum=md5.update("hello");letresult=md5Sum.digest("Base64");console.log(结果);//XUFAKrxLKna5cZ2REBfFkg==update方法的返回值是this,也就是当前实例,所以支持链式调用。较长的信息也可以通过多次调用update方法进行加密,调用digest方法也会返回整个加密后的值。//链调用和分段加密constcrypto=require("crypto");letresult=crypto.createHash("md5").update("he").update("llo").digest("hex");控制台日志(结果);//5d41402abc4b2a76b9719d911017c592由于update可以进行分段加密,所以可以结合流使用。其实crypto的本质就是创建Transform类型的转换流,可以将可读流转换为可写流。//对可读流读取的数据进行md5加密constcrypto=require("crypto");letfs=require("fs");letmd5=crypto.createHash("md5");letrs=fs.createReadSteam("./readme.txt",{highWaterMark:3});//读取数据并加密rs.on("data",data=>md5.update(data));rs.on("end",()=>{letresult=md5.digest("hex");console.log(result);});使用场景一:常用于数据校验,如服务器间通信接收端接收到数据后,将明文摘要按照相同的md5算法加密后与密文摘要进行比对校验,以防劫持和篡改数据传输。场景二:在浏览器缓存策略中,静态资源的信息汇总可以使用md5加密,加密后的密钥每次都发送给服务器进行比对,而不是比对整个文件内容。缺点:由于规定使用md5哈希算法进行加密,其他人可以使用相同的算法伪造信息,安全性不高。Hmac算法1.Hmac算法的使用Hmac算法,又称salt算法,将散列算法与密钥相结合,以防止破坏签名的完整性。它还具有md5加密的几个特点。//用盐算法加密constcrytpo=require("crytpo");lethmac=crytpo.createHmac("sha1","panda");letresult=hmac.update("hello").digest("Base64");控制台日志(结果);//7spMLxN8WJdcEtQ8Hm/LR9pUE3YsIGag9Dcai7lwioo=crytpo.createHmac第一个参数同crytpo.createHash,是加密算法,常用sha1和sha256,第二个参数是key。digest方法生成的加密结果长度大于md5,hex生成的结果长度为64,Base64生成的结果长度为44,以=结尾。安全性高于md5,通过密钥加密,不知道密钥无法破解。缺点是密钥传输过程容易被劫持,可以通过一些生成随机密钥的方法来避免。2、创建密钥的方法可以安装openSSH客户端,通过命令行生成存储密钥的文件,命令如下。opensslgenrsa-outrsa_private.key1024opensslgenrsa代表生成的key,-out代表输出文件,rsa_private.key代表文件名,1024代表输出key的大小。//直接读取key文件,用salt算法加密constfs=require("fs");constcrytpo=require("crytpo");constpath=require("path");letkey=fs.readFileSync(path.join(__dirname,"/rsa_private.key"));lethmac=crytpo.createHmac("sha256",key);letresult=hmac.update("hello").digest("Base64");控制台.日志(结果);//bmi2N+6kwgwt5b+U+zSgjL/NFs+GsUnZmcieqLKBy4M=对称加密对称加密发送数据时使用一个密钥和加密算法进行加密,接收数据时需要使用相同的密钥和加密算法逆算法(解密算法)对于解密,也就是说对称加密的过程是可逆的,crytpo使用的算法是blowfish。//对称加密constfs=require("fs");constcrypto=require("crypto");constpath=require("path");letkey=fs.readFileSync(path.join(__dirname,"/rsa_private.key"));//加密letcipher=crypto.createCipher("blowfish",key);cipher.update("hello");//final方法不能链接letresult=cipher.final("hex");console.log(result);//3eb9943113c7aa1e//解密letdecipher=crypto.createDecipher("blowfish",key);decipher.update(result,"hex");letdata=decipher.final("utf8");console.log(data);//hello使用crypto.createCipher方法进行加密,使用crypto.createDecipher方法进行解密,但是使用的算法和密钥必须相同。需要注意的是,在解密过程中,update需要在第二个参数中指定加密格式,如hex,并在final恢复数据时指定加密字符的编码格式,如utf8。注意:使用对称加密的字符串长度是有限制的,不能超过7个字符。否则,虽然可以加密成功,但无法解密。缺点:密钥在传输过程中容易被截获,存在安全隐患。非对称加密非对称加密阶段也是可逆的,比对称加密更安全。消息发送方和接收方都会在本地创建一对密钥,公钥和私钥,并将自己的公钥发送给对方。给对方,用对方的公钥加密每条消息,对方收到消息后用自己的私钥解密,这样即使在公钥传输过程中被截获也无法解密,因为公钥加密的消息只有配对的私钥才能解密。接下来,我们使用openSSH为之前生成的私钥rsa_private.key生成对应的公钥,命令如下。opensslrsa-inrsa_private.key-pubout-outrsa_public.key上面的命令意思是根据一个私钥生成对应的公钥,-pubout-out代表公钥的输出,rsa_public.key是文件名的公钥。//非对称加密constfs=require("fs");constcrypto=require("加密");constpath=require("path");//获取公钥和私钥letpublicKey=fs.readFileSync(path.join(__dirname,"/rsa_public.key"));letprivateKey=fs.readFileSync(path.join(__dirname,"/rsa_private.key"));//加密letsecret=crytpo.publicEncrypt(publicKey,Buffer.from("hello"));//解密letresult=crytpo.provateDecrypt(privateKey,secret);控制台日志(结果);//hello使用crytpo.publicEncrypt,第一个参数是公钥,第二个参数是加密后的信息(必须是Buffer),使用私钥解密的方法是crytpo.provateDecrypt,第一个参数是私钥,第二个参数是解密后的信息。SignatureSignature与非对称加密非常相似。它还有一个公钥和一个私钥。不同的是,使用私钥进行加密,对方使用公钥进行解密和验证,确保这条数据是私钥所有者发送的原始数据。,并且在网络传输过程中没有被修改。我们同样使用rsa_public.key和rsa_private.key作为公钥和私钥,加密实现签名代码如下。//签名constfs=require("fs");constcrypto=require("加密");constpath=require("path");//获取公钥和私钥letpublicKey=fs.readFileSync(path.join(__dirname,"rsa_public.key"),"ascii");letprivateKey=fs.readFileSync(path.join(__dirname,"rsa_private.key"),"ascii");//生成签名letsign=crypto.createSign("RSA-SHA256");sign.update("panda");letsigned=sign.sign(privateKey,"hex");//验证签名letverify=crypto.createVerify("RSA-SHA256");verify.update("panda");让verifyResult=verify.verify(publicKey,signed,"hex");console.log(verifyResult);//true生成签名的sign方法有两个参数,第一个参数为私钥,第二个参数为生成签名的格式,最后返回的signed为生成的签名(字符串)。验证签名的verify方法有三个参数,第一个参数是公钥,第二个参数是要验证的签名,第三个参数是签名生成时的格式,返回值为布尔值,即验证是否通过。使用场景:常用于将cookie签名返回给浏览器,然后在浏览器访问同域服务器带上cookie时进行校验,防止cookie被篡改和CSRF跨站请求伪造.总结一下,各种项目在数据传输过程中,根据信息的敏感性和目的,采用了不同的加密算法和加密方式。在NodeJS中,cryptoAPI完全可以满足我们的加密需求,而且还可以结合使用上述加密方案,实现更复杂的加密方案。