簡介
這節(jié)我們來一塊研究一下NodeJS提供的關(guān)于秘鑰(加密和解密)的相關(guān)算法API。根據(jù)平時常用的加解密算法我歸納了如下四種類別:(算法不止這些這里只是拋磚引玉)
1.內(nèi)容編解碼類(Base64)
2.內(nèi)容摘要類(MD5、SHA1践剂、SHA256森爽、SHA512)
3.內(nèi)容加密解密類 又分為:對稱加密解密(AES)测暗,非對稱加密解密(RSA)
4.內(nèi)容簽名類(RSA+SHA1 或 RSA+SHA256 或 RSA+MD5等等)
NodeJS中處理秘鑰相關(guān)的模塊是 crypto 馁害,需要首先引入
/*crypto加密解密*/
let crypto;
try {
crypto = require('crypto');//如果不支持 crypto模塊則會拋出異常
......//進行編解碼操作
}catch (err) {
console.log('不支持 crypto!');
}
1.內(nèi)容編解碼類
- Base64編解碼
Base64編解碼其實算不上是加密解密算法,頂多算是一種編解碼算法脱货,因為Base64算法首先是可逆的,而且是非常容易被破譯的律姨,所以我們一般用Base64都是去編碼信息內(nèi)容振峻,基本不用它去加密,即使加了也和沒加一樣择份,呵呵扣孟。。荣赶。接下來曬出nodejs進行Base64編解碼示例:
//BASE64編解碼
//編碼
var bc = new Buffer("Base64編解碼內(nèi)容");
var bec = bc.toString("base64");
console.log("Base64編碼后結(jié)果: %s",bec);
//log打印:Base64編碼后結(jié)果: QmFzZTY057yW6Kej56CB5YaF5a65
//解碼
var bdc = new Buffer(bec, "base64");
var bdcs = bdc.toString();
console.log("Base64解碼后結(jié)果: %s",bdcs);
//log打印:Base64解碼后結(jié)果: Base64編解碼內(nèi)容
2.內(nèi)容摘要類(MD5凤价、SHA1、SHA256拔创、SHA512)
摘要算法又稱哈希/散列算法利诺。它通過一個函數(shù),把任意長度的數(shù)據(jù)轉(zhuǎn)換為一個長度固定的數(shù)據(jù)串(通常用16進制的字符串表示)伏蚊。算法不可逆立轧。
摘要一般用作驗證內(nèi)容的完整性,真實性(比如我們上傳一個壓縮文件使用MD5進行加密躏吊,得到一個摘要串氛改,下載我們這個壓縮文件的一方只需要同樣使用MD5算法進行加密后,得到摘要串和我們上傳時得到的摘要串做對比比伏,一致則說明下載的文件是完整的可信的胜卤,可以放心使用!_)
接下來我列舉幾個NodeJS的摘要算法:
- MD5加密摘要算法使用
//MD5-產(chǎn)生128位的加密結(jié)果【不可逆】
var hash_md5=crypto.createHash("md5");
hash_md5.update("加密內(nèi)容ABCD1234");
var md5c=hash_md5.digest("hex");
console.log("MD5加密后結(jié)果: %s",md5c);
log輸出:MD5加密后結(jié)果: 84111fcac08f3a3e30c5df95cf6585a4
這里標記一下update()這個方法赁项,它可以追加內(nèi)容字符串葛躏,追加后得到的摘要結(jié)果和上面得到的結(jié)果是一樣的:
//md5-update追加字符串(不可逆)
hash_md5=crypto.createHash("md5");
hash_md5.update("加密內(nèi)容");
hash_md5.update("ABCD");
hash_md5.update("1234");
md5c=hash_md5.digest("hex");
console.log("MD5update追加:%s",md5c);
log輸出:MD5update追加:84111fcac08f3a3e30c5df95cf6585a4
- SHA1加密摘要算法使用
//SHA1-產(chǎn)生160位的加密結(jié)果【不可逆】
var hash_sha1=crypto.createHash("sha1");
hash_sha1.update("加密內(nèi)容ABCD1234");
var sha1c=hash_sha1.digest("hex");//顯示為16進制
console.log("SHA1加密后結(jié)果:%s",sha1c);
log輸出:SHA1加密后結(jié)果:f4c1ec92573c29e0220b82f81cb33f304116391d
- SHA256加密摘要算法使用
//SHA256-產(chǎn)生256位的加密結(jié)果【不可逆】
var hash_sha256=crypto.createHash("sha256");
hash_sha256.update("加密內(nèi)容ABCD1234");
var sha256c=hash_sha256.digest("hex");//顯示為16進制
console.log("SHA256加密后結(jié)果:%s",sha256c);
log輸出:SHA256加密后結(jié)果:e7c9f5967b1d9e5a997aeb18d8555d5de7a284a9c7e6deb296b90492bc48dd79
-
SHA256加密(Hmac方式)
HMAC是密鑰相關(guān)的哈希運算消息認證碼,HMAC運算利用哈希算法悠菜,以一個密鑰和一個消息為輸入舰攒,生成一個消息摘要作為輸出。
HMAC這種方式(需要額外key)要比傳統(tǒng)摘要方式(不需要額外key)更加保密悔醋,不易破解摩窃!
除了支持SHA256還支持其它HMAC方式的摘要算法,比如SHA1、SHA512猾愿、MD5等鹦聪。
//sha256加密(Hmac方式)擁有一個加密Key,這樣更安全一些
const secret="AK41abud";//秘鑰
var hmac=crypto.createHmac("sha256",secret);
var content=hmac.update("加密內(nèi)容ABCD1234");
var cryptoContent=content.digest("hex");
console.log("sha256(Hmac方式)加密后結(jié)果:%s",cryptoContent);
log輸出:sha256(Hmac方式)加密后結(jié)果:b4e164a61eb1d0dd532988fe5448d47d65f1ee4d6caf6132200727d1d81dddc4
3.內(nèi)容加密解密類又分為: 對稱加密解密(AES)蒂秘,非對稱加密解密(RSA)
對信息進行加密解密泽本,有很多種算法,當然不只是AES和RSA這兩種姻僧,這兩種只是我們平時比較常用的规丽。
加密解密算法,大致又分為對稱加密和非對稱加密兩大類段化,當然這些加密算法都是可逆的嘁捷,如果像上面介紹的MD5、SHA1是不可逆的显熏,那我們把內(nèi)容加完秘后解不開了雄嚣,不就悲劇了。喘蟆。缓升。呵呵
-
AES對稱加密
對稱加密大概可以理解為,加密和解密蕴轨,使用的是同一個秘鑰key港谊。
//AES對稱加密
var secretkey="passwd";//唯一(公共)秘鑰
var content="需要加密的內(nèi)容ABC";
var cipher=crypto.createCipher('aes192', secretkey);//使用aes192加密
var enc=cipher.update(content,"utf8","hex");//編碼方式從utf-8轉(zhuǎn)為hex;
enc+=cipher.final('hex');//編碼方式轉(zhuǎn)為hex;
//
//AES對稱解密
var decipher=crypto.createDecipher('aes192', secretkey);
var dec=decipher.update(enc,"hex", "utf8");
dec+=decipher.final("utf8");
console.log("AES對稱解密結(jié)果:"+dec);
log輸出:AES對稱解密結(jié)果:需要加密的內(nèi)容ABC
-
RSA非對稱加密
非對稱加密大致可以這樣理解:加密和解密,使用的是不同的秘鑰橙弱,通常我們使用算法會得到一對秘鑰(一個叫做私鑰歧寺,另一個叫做公鑰),公鑰一般用來進行加密棘脐,而私鑰一般用來進行解密斜筐,當然你也可以顛倒過來使用,私鑰加密公鑰解密都是可以的(只是一般不這么使用)蛀缝。
接下來我介紹一下在nodejs中如何使用RSA進行加密和解密:
- 首先我們需要得到公鑰和私鑰:
使用OpenSSL算法可以得到RSA公鑰和私鑰(如果沒安裝OpenSSL顷链,可以百度一下先安裝一下)
安裝好OpenSSL后cmd生成RSA私鑰:
openssl genrsa -out privatekey.pem 1024
cmd再生成公鑰:
openssl rsa -in privatekey.pem -pubout -out publickey.pem
這樣在當前目錄中就會生成 ‘privatekey.pem’(私鑰) 和 ‘publickey.pem’ (公鑰)這兩個文件,之后我們就使用這兩個文件進行RSA非對稱加密和解密屈梁。
//RSA非對稱加密解密
const fs=require("fs");
const privatepem2=fs.readFileSync("./privatekey.pem");//私有key【需要 pem 編碼的key】server.pem
const publicpem2=fs.readFileSync("./publickey.pem");//公有key【需要 pem 編碼的key】cert.pem
const prikey2=privatepem2.toString();
const pubkey2=publicpem2.toString();
// 加密方法
var encrypt = (data, key) => {
// 注意嗤练,第二個參數(shù)是Buffer類型
return crypto.publicEncrypt(key, Buffer.from(data));
};
// 解密方法
var decrypt = (encrypted, key) => {
// 注意,encrypted是Buffer類型
return crypto.privateDecrypt(key, encrypted);
};
const plainText = "我是RSA非對稱加密字符串內(nèi)容";
const crypted = encrypt(plainText, pubkey2); // 加密
const decrypted = decrypt(crypted, prikey2); // 解密
console.log("RSA非對稱解密結(jié)果:%s",decrypted.toString());
log輸出:RSA非對稱解密結(jié)果:我是RSA非對稱加密字符串內(nèi)容
4.內(nèi)容簽名類(RSA+SHA1 或 RSA+SHA256 或 RSA+MD5等等)
“信息內(nèi)容簽名”其實和我們?nèi)粘V袑堎|(zhì)文件進行簽名是一個道理在讶。又稱為“數(shù)字簽名”煞抬,包括報文摘要。報文摘要和非對稱加密一起构哺,提供數(shù)字簽名的方法此疹。
數(shù)字簽名主要是保證信息的完整和提供信息發(fā)送者的身份認證和不可抵賴性,這其中,“完整性”主要就是由報文摘要提供的蝗碎,報文摘要就是用來防止發(fā)送的報文被篡改。
使用流程:
- 使用RSA私鑰進行簽名(對信息報文生成的摘要進行私鑰簽名)生成簽名串旗扑,一般是16進制字符串
- 使用RSA公鑰進行簽名校驗(驗明正身)
其實很好理解蹦骑,你可以想象成我們手簽的名字,通過獨一無二的書寫字體去驗證是否是出自于你的筆記臀防。眠菇。。
//非對稱簽名校驗
const privatepem=fs.readFileSync("./privatekey.pem");//私有key【需要 pem 編碼的key】server.pem
const publicpem=fs.readFileSync("./publickey.pem");//公有key【需要 pem 編碼的key】cert.pem
const otherkeys=require("./otherkeys.js");//其它公鑰和私鑰(測試用袱衷,如果用其它的公鑰進行校驗簽名肯定是無法通過的)
const prikey=privatepem.toString();
const pubkey=publicpem.toString();
var data = "我是信息內(nèi)容摘要"
var sign = crypto.createSign('RSA-SHA256');//創(chuàng)建簽名算法
sign.update(data);
var sig = sign.sign(prikey, 'hex');//得到簽名
var verify = crypto.createVerify('RSA-SHA256');
verify.update(data);
var t=verify.verify(pubkey, sig, 'hex');
// var t=verify.verify(otherkeys.pubKey, sig, 'hex');//用其它公鑰校驗無法通過捎废!
console.log("非對稱簽名校驗結(jié)果結(jié)果:"+t);
log輸出:非對稱簽名校驗結(jié)果結(jié)果:true
這里我把其它的公鑰和秘鑰對也貼出來,otherkeys.js內(nèi)容:
//其它私鑰和公鑰
exports.privKey = `-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDFWnl8fChyKI/Tgo1ILB+IlGr8ZECKnnO8XRDwttBbf5EmG0qV
8gs0aGkh649rb75I+tMu2JSNuVj61CncL/7Ct2kAZ6CZZo1vYgtzhlFnxd4V7Ra+
aIwLZaXT/h3eE+/cFsL4VAJI5wXh4Mq4Vtu7uEjeogAOgXACaIqiFyrk3wIDAQAB
AoGBAKdrunYlqfY2fNUVAqAAdnvaVOxqa+psw4g/d3iNzjJhBRTLwDl2TZUXImEZ
QeEFueqVhoROTa/xVg/r3tshiD/QC71EfmPVBjBQJJIvJUbjtZJ/O+L2WxqzSvqe
wzYaTm6Te3kZeG/cULNMIL+xU7XsUmslbGPAurYmHA1jNKFpAkEA48aUogSv8VFn
R2QuYmilz20LkCzffK2aq2+9iSz1ZjCvo+iuFt71Y3+etWomzcZCuJ5sn0w7lcSx
nqyzCFDspQJBAN3O2VdQF3gua0Q5VHmK9AvsoXLmCfRa1RiKuFOtrtC609RfX4DC
FxDxH09UVu/8Hmdau8t6OFExcBriIYJQwDMCQQCZLjFDDHfuiFo2js8K62mnJ6SB
H0xlIrND2+/RUuTuBov4ZUC+rM7GTUtEodDazhyM4C4Yq0HfJNp25Zm5XALpAkBG
atLpO04YI3R+dkzxQUH1PyyKU6m5X9TjM7cNKcikD4wMkjK5p+S2xjYQc1AeZEYq
vc187dJPRIi4oC3PN1+tAkBuW51/5vBj+zmd73mVcTt28OmSKOX6kU29F0lvEh8I
oHiLOo285vG5ZtmXiY58tAiPVQXa7eU8hPQHTHWa9qp6
-----END RSA PRIVATE KEY-----
`;
exports.pubKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFWnl8fChyKI/Tgo1ILB+IlGr8
ZECKnnO8XRDwttBbf5EmG0qV8gs0aGkh649rb75I+tMu2JSNuVj61CncL/7Ct2kA
Z6CZZo1vYgtzhlFnxd4V7Ra+aIwLZaXT/h3eE+/cFsL4VAJI5wXh4Mq4Vtu7uEje
ogAOgXACaIqiFyrk3wIDAQAB
-----END PUBLIC KEY-----
`;
這里只給出一種簽名算法致燥,其實NodeJS為我們還提供了很多其它的簽名算法登疗,具體可以查看官方API文檔。
簽名算法嫌蚤,我們在平時用的還是很多的辐益,比如 微信支付、支付寶支付等等脱吱,使用簽名需要去驗明信息來源身份的有效性智政,這樣使我們的信息傳遞交互更安全可靠!箱蝠!
謝謝大家续捂!共勉!