Node中的crypto模塊詳解

轉自廖雪峯的博客。javascript

crypto模塊的目的是爲了提供通用的加密和哈希算法。用純JavaScript代碼實現這些功能不是不可能,但速度會很是慢。Nodejs用C/C++實現這些算法後,經過cypto這個模塊暴露爲JavaScript接口,這樣用起來方便,運行速度也快。java

MD5和SHA1

MD5是一種經常使用的哈希算法,用於給任意數據一個「簽名」。這個簽名一般用一個十六進制的字符串表示:node

const crypto = require('crypto');

const hash = crypto.createHash('md5');

// 可任意屢次調用update():
hash.update('Hello, world!');
hash.update('Hello, nodejs!');

console.log(hash.digest('hex')); // 7e1977739c748beac0c0fd14fd26a544

update()方法默認字符串編碼爲UTF-8,也能夠傳入Buffer。算法

若是要計算SHA1,只須要把'md5'改爲'sha1',就能夠獲得SHA1的結果1f32b9c9932c02227819a4151feed43e131aca40安全

還可使用更安全的sha256sha512服務器

Hmac

Hmac算法也是一種哈希算法,它能夠利用MD5或SHA1等哈希算法。不一樣的是,Hmac還須要一個密鑰:函數

const crypto = require('crypto');

const hmac = crypto.createHmac('sha256', 'secret-key');

hmac.update('Hello, world!');
hmac.update('Hello, nodejs!');

console.log(hmac.digest('hex')); // 80f7e22570...

只要密鑰發生了變化,那麼一樣的輸入數據也會獲得不一樣的簽名,所以,能夠把Hmac理解爲用隨機數「加強」的哈希算法。測試

AES

AES是一種經常使用的對稱加密算法,加解密都用同一個密鑰。crypto模塊提供了AES支持,可是須要本身封裝好函數,便於使用:ui

const crypto = require('crypto');

function aesEncrypt(data, key) {
    const cipher = crypto.createCipher('aes192', key);
    var crypted = cipher.update(data, 'utf8', 'hex');
    crypted += cipher.final('hex');
    return crypted;
}

function aesDecrypt(encrypted, key) {
    const decipher = crypto.createDecipher('aes192', key);
    var decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
}

var data = 'Hello, this is a secret message!';
var key = 'Password!';
var encrypted = aesEncrypt(data, key);
var decrypted = aesDecrypt(encrypted, key);

console.log('Plain text: ' + data);
console.log('Encrypted text: ' + encrypted);
console.log('Decrypted text: ' + decrypted);

運行結果以下:this

Plain text: Hello, this is a secret message!
Encrypted text: 8a944d97bdabc157a5b7a40cb180e7...
Decrypted text: Hello, this is a secret message!

能夠看出,加密後的字符串經過解密又獲得了原始內容。

注意到AES有不少不一樣的算法,如aes192aes-128-ecbaes-256-cbc等,AES除了密鑰外還能夠指定IV(Initial Vector),不一樣的系統只要IV不一樣,用相同的密鑰加密相同的數據獲得的加密結果也是不一樣的。加密結果一般有兩種表示方法:hex和base64,這些功能Nodejs所有都支持,可是在應用中要注意,若是加解密雙方一方用Nodejs,另外一方用Java、PHP等其它語言,須要仔細測試。若是沒法正確解密,要確認雙方是否遵循一樣的AES算法,字符串密鑰和IV是否相同,加密後的數據是否統一爲hex或base64格式。

Diffie-Hellman

DH算法是一種密鑰交換協議,它可讓雙方在不泄漏密鑰的狀況下協商出一個密鑰來。DH算法基於數學原理,好比小明和小紅想要協商一個密鑰,能夠這麼作:

  1. 小明先選一個素數和一個底數,例如,素數p=23,底數g=5(底數能夠任選),再選擇一個祕密整數a=6,計算A=g^a mod p=8,而後大聲告訴小紅:p=23,g=5,A=8

  2. 小紅收到小明發來的pgA後,也選一個祕密整數b=15,而後計算B=g^b mod p=19,並大聲告訴小明:B=19

  3. 小明本身計算出s=B^a mod p=2,小紅也本身計算出s=A^b mod p=2,所以,最終協商的密鑰s2

在這個過程當中,密鑰2並非小明告訴小紅的,也不是小紅告訴小明的,而是雙方協商計算出來的。第三方只能知道p=23g=5A=8B=19,因爲不知道雙方選的祕密整數a=6b=15,所以沒法計算出密鑰2

用crypto模塊實現DH算法以下:

const crypto = require('crypto');

// xiaoming's keys:
var ming = crypto.createDiffieHellman(512);
var ming_keys = ming.generateKeys();

var prime = ming.getPrime();
var generator = ming.getGenerator();

console.log('Prime: ' + prime.toString('hex'));
console.log('Generator: ' + generator.toString('hex'));

// xiaohong's keys:
var hong = crypto.createDiffieHellman(prime, generator);
var hong_keys = hong.generateKeys();

// exchange and generate secret:
var ming_secret = ming.computeSecret(hong_keys);
var hong_secret = hong.computeSecret(ming_keys);

// print secret:
console.log('Secret of Xiao Ming: ' + ming_secret.toString('hex'));
console.log('Secret of Xiao Hong: ' + hong_secret.toString('hex'));

運行後,能夠獲得以下輸出:

$ node dh.js 
Prime: a8224c...deead3
Generator: 02
Secret of Xiao Ming: 695308...d519be
Secret of Xiao Hong: 695308...d519be

注意每次輸出都不同,由於素數的選擇是隨機的。

證書

crypto模塊也能夠處理數字證書。數字證書一般用在SSL鏈接,也就是Web的https鏈接。通常狀況下,https鏈接只須要處理服務器端的單向認證,如無特殊需求(例如本身做爲Root給客戶發認證證書),建議用反向代理服務器如Nginx等Web服務器去處理證書。

相關文章
相關標籤/搜索