### crypto模塊概述
在Node.js中,使用OpenSSL類庫(kù)作為其內(nèi)部實(shí)現(xiàn)加密與解密處理的基礎(chǔ)手段,這是因?yàn)槟壳癘penSSL已經(jīng)成為了一個(gè)經(jīng)過(guò)嚴(yán)格測(cè)試的可靠的加密與解密算法的實(shí)現(xiàn)工具。
在Node.js中,OpenSSL類庫(kù)被封裝在crypto模塊中,因此開(kāi)發(fā)者可以使用crypto模塊來(lái)實(shí)現(xiàn)各種不同的加密與解密處理。例如,crypto模塊中包含了類似MD5或SHA-1之類的散列算法。開(kāi)發(fā)者也可以通過(guò)crypto模塊來(lái)實(shí)現(xiàn)HMAC運(yùn)算 [1]。在crypto模塊中,提供了一些加密方法來(lái)實(shí)現(xiàn)數(shù)據(jù)的可靠加密。另外,在crypto模塊中,也提供了一些利用HMAC運(yùn)算來(lái)實(shí)現(xiàn)數(shù)字簽名以及對(duì)數(shù)字簽名進(jìn)行驗(yàn)證的方
法。
### 查看Node.js中能夠使用的所有加密算法
在crypto模塊中,為每一種加密算法定義了一個(gè)類??梢允褂胓etCiphers方法
來(lái)查看Node.js中能夠使用的所有加密算法。
```
crypto.getCiphers()
```
### 查看Node.js中能夠使用的所有散列算法
可以使用getHashes方法來(lái)查看在Node.js中能夠使用的所有散列算法。
```
crypto.getHashes()
```
### 散列算法
散列(哈希)算法用來(lái)實(shí)現(xiàn)一些重要處理,例如,在允許對(duì)一段數(shù)據(jù)進(jìn)行驗(yàn)證的前提下,將數(shù)據(jù)進(jìn)行模糊化,或者為一大段數(shù)據(jù)提供一個(gè)驗(yàn)證碼
在node中,為了使用散列算法,首先應(yīng)該使用createHash方法創(chuàng)建一個(gè)hash對(duì)象。
```
let hash=crypto.createHash(algorithm)
```
- algorithm:參數(shù)值為一個(gè)在Node.js中可以使用的算法,如'sha1'、'md5'、'sha256'、'sha512'和'ripemd160'等,用于指定需要使用的散列算法,該方法返回被創(chuàng)建的hash對(duì)象
在創(chuàng)建一個(gè)hash對(duì)象后可以通過(guò)使用該對(duì)象的update方法創(chuàng)建一個(gè)摘要。該方法的使用方式如下所示
```
hash.update(data,[input_encoding])
```
- data:參數(shù)值為一個(gè)Buffer對(duì)象或一個(gè)字符串,用于指定摘要內(nèi)容
- input_encoding:用于指定摘要內(nèi)容所需使用的編碼格式,可指定參數(shù)值為“utf8”、“ascii”或“binary”。如果不使用input_encoding參數(shù),則data參數(shù)值必須為一個(gè)Buffer對(duì)象。可以在摘要被輸出前使用多次update方法來(lái)添加摘要內(nèi)容。
#### 輸出摘要內(nèi)容
可以使用hash對(duì)象的digest方法來(lái)輸出摘要內(nèi)容。在使用了hash對(duì)象的digest方法后,不能再向hash對(duì)象中追加摘要內(nèi)容。
```
hash.digest([encoding])
```
在hash對(duì)象的digest方法中,使用一個(gè)可選參數(shù),參數(shù)值為一個(gè)字符串,用于指定輸出摘要的編碼格式,可指定參數(shù)值為“hex”、“binary”及“base64”。如果使用了該參數(shù),那么digest方法返回字符串格式的摘要內(nèi)容,如果不使用該參數(shù),那么digest方法返回一個(gè)Buffer對(duì)象。在hash對(duì)象的digest方法被調(diào)用之后,該對(duì)象不能再被使用。
#### 散列算法完整使用示例
```
var crypto = require('crypto');
var fs = require('fs');
var shasum = crypto.createHash('sha1');
var s = fs.ReadStream('./app.js');
s.on('data', function(d) {
? ? shasum.update(d);
});
s.on('end', function() {
? ? var d = shasum.digest('hex');
? ? console.log(d);
});
```
### HMAC算法
HMAC算法將散列算法與一個(gè)密鑰結(jié)合在一起,以阻止對(duì)簽名完整性的破壞。在Node.js中,為了使用HMAC算法,首先應(yīng)該使用createHmac方法創(chuàng)建一個(gè)hmac對(duì)象。
```
crypto.createHmac(algorithm,key)
```
- algorithm:為一個(gè)在Node.js中可以使用的算法,例如'sha1'、'md5'、'sha256'、'sha512'和'ripemd160'等,用于指定我們所需要使用的散列算法。該方法返回被創(chuàng)建的hmac對(duì)象。
- key:參數(shù)值為一個(gè)字符串,用于指定一個(gè)PEM格式的密鑰。
#### 創(chuàng)建一個(gè)摘要
在hmac對(duì)象的update方法中,使用一個(gè)參數(shù),其參數(shù)值為一個(gè)Buffer對(duì)象或一個(gè)字符串,用于指定摘要內(nèi)容??梢栽谡惠敵銮笆褂枚啻蝩pdate方法來(lái)添加摘要內(nèi)容。
```
hmac.update(data)
```
#### 輸出摘要
可以使用hmac對(duì)象的digest方法輸出摘要內(nèi)容。在使用了hmac對(duì)象的digest方法后,不能再向hmac對(duì)象中追加摘要內(nèi)容。
```
hmac.digest([encoding])
```
#### HMAC算法的使用示例
```
var crypto = require('crypto');
var fs = require('fs');
var pem = fs.readFileSync('key.pem');
var key = pem.toString('ascii');
var shasum = crypto.createHmac('sha1',key);
var s = fs.ReadStream('./app.js');
s.on('data', function(d) {
? ? shasum.update(d);
});
s.on('end', function() {
? ? var d = shasum.digest('hex');
? ? console.log(d);
});
```
### 公鑰加密
#### 加密數(shù)據(jù)
在crypto模塊中,Cipher類用于對(duì)數(shù)據(jù)進(jìn)行加密操作。在加密數(shù)據(jù)之前,首先需要?jiǎng)?chuàng)建一個(gè)cipher對(duì)象??梢酝ㄟ^(guò)如下所示的兩種方法創(chuàng)建cipher對(duì)象。
1.createCipher方法:該方法使用指定的算法與密碼來(lái)創(chuàng)建cipher對(duì)象。
```
crypto.createCipher(algorithm,password)
```
- algorithm:用于指定在加密數(shù)據(jù)時(shí)所使用的算法,例如“blowfish'”、“aes-256-cbc”等。
- password:用于指定加密時(shí)所使用的密碼,參數(shù)值必須為一個(gè)二進(jìn)制格式的字符串或一個(gè)Buffer對(duì)象。
2.createCipheriv方法:該方法使用指定的算法、密碼與初始向量(Initialization Vector,IV)來(lái)創(chuàng)建cipher對(duì)象。該方法的使用方式如下:
```
crypto.createCipheriv(algorithm,password,iv)
```
- algorithm:用于指定在加密數(shù)據(jù)時(shí)所使用的算法,例如“blowfish'”、“aes-256-cbc”等。
- password:用于指定加密時(shí)所使用的密碼,參數(shù)值必須為一個(gè)二進(jìn)制格式的字符串或一個(gè)Buffer對(duì)象。
- iv:用于指定加密時(shí)所使用的初始向量,參數(shù)值必須為一個(gè)二進(jìn)制格式的字符串或一個(gè)Buffer對(duì)象。
#### 指定需要被加密的數(shù)據(jù)。
在創(chuàng)建了一個(gè)cipher對(duì)象后,可以通過(guò)使用該對(duì)象的update方法來(lái)指定需要被加密的數(shù)據(jù)。
```
cipher.update(data,[input_encoding],[output_encoding])
```
- data:為必須使用的參數(shù),為一個(gè)Buffer對(duì)象或一個(gè)字符串,用于指定需要加密的數(shù)據(jù)
- input_encoding:用于指定被加密的數(shù)據(jù)所需使用的編碼格式,可指定參數(shù)值為“utf8”、“ascii”及“binary”。
- output_encoding:用于指定輸出加密數(shù)據(jù)時(shí)使用的編碼格式,可指定參數(shù)值為“hex”、“binary”或“base64”。
#### 返回加密數(shù)據(jù)。
可以使用cipher對(duì)象的final方法來(lái)返回加密數(shù)據(jù)。當(dāng)該方法被調(diào)用時(shí),任何cipher對(duì)象中所緩存的數(shù)據(jù)都將被加密,如果加密數(shù)據(jù)的字節(jié)數(shù)不足以創(chuàng)建一個(gè)塊,將使用PKCS填充方式來(lái)填充這個(gè)塊。在使用了cipher對(duì)象的final方法后,不能再向cipher對(duì)象中追加加密數(shù)據(jù)。
```
cipher.final([output_encoding])
```
- output_encoding:參數(shù)值為一個(gè)字符串,用于指定在輸出加密數(shù)據(jù)的編碼格式,可指定參數(shù)值為“hex”、“binary”及“base64”。如果使用了該參數(shù),那么final方法返回字符串格式的加密數(shù)據(jù),如果不使用該參數(shù),那么final方法返回一個(gè)Buffer對(duì)象。當(dāng)cipher對(duì)象的final方法被調(diào)用之后,該對(duì)象不能再被使用。
#### 使用cipher對(duì)象加密數(shù)據(jù)
```
var crypto = require('crypto');
var fs = require('fs');
var pem = fs.readFileSync('key.pem');
var key = pem.toString('ascii');
var cipher = crypto.createCipher('blowfish', key);
var text = "test";
cipher.update(text,'binary','hex');
var crypted=cipher.final('hex')
console.log(crypted);
```
### 解密數(shù)據(jù)
在crypto模塊中,Decipher類用于對(duì)加密后的數(shù)據(jù)進(jìn)行解密操作。在解密數(shù)據(jù)之前,首先需要?jiǎng)?chuàng)建一個(gè)decipher對(duì)象。可以通過(guò)如下所示的兩種方法創(chuàng)建decipher對(duì)象。
1.createDecipher方法:該方法使用指定的算法與密碼來(lái)創(chuàng)建decipher對(duì)象。
```
crypto.createDecipher(algorithm,password)
```
- algorithm:用于指定在解密數(shù)據(jù)時(shí)所使用的算法,例如“blowfish”、“aes-256-cbc”等,該算法必須與加密該數(shù)據(jù)時(shí)所使用的算法保持一致。
- password:用于指定解密時(shí)所使用的密碼,其參數(shù)值必須為一個(gè)二進(jìn)制格式的字符串或一個(gè)Buffer對(duì)象,該密碼必須與加
密該數(shù)據(jù)時(shí)所使用的密碼保持一致。
2.createDecipheriv方法:該方法使用指定的算法、密碼與初始向量來(lái)創(chuàng)建decipher對(duì)象。
```
crypto.createDecipheriv(algorithm,password,iv)
```
- algorithm:用于指定在解密數(shù)據(jù)時(shí)所使用的算法,例如“blowfish”、“aes-256-cbc”等,該算法必須與加密該數(shù)據(jù)時(shí)所使用的算法保持一致。
- password:用于指定解密時(shí)所使用的密碼,其參數(shù)值必須為一個(gè)二進(jìn)制格式的字符串或一個(gè)Buffer對(duì)象,該密碼必須與加
密該數(shù)據(jù)時(shí)所使用的密碼保持一致。
- iv:用于指定解密時(shí)所使用的初始向量,參數(shù)值必須為一個(gè)二進(jìn)制格式的字符串或一個(gè)Buffer對(duì)象,該初始向量必須與加密該數(shù)據(jù)時(shí)所使用的初始向量保持一致。
createDecipheriv方法返回一個(gè)被創(chuàng)建的decipher對(duì)象。
#### 數(shù)據(jù)解密
在創(chuàng)建了一個(gè)decipher對(duì)象之后,可以通過(guò)使用該對(duì)象的update方法來(lái)指定需要被解密的數(shù)據(jù)。
```
decipher.update(data,[input_encoding],[output_encoding])
```
#### 返回經(jīng)過(guò)解密之后的原始數(shù)據(jù)
```
decipher.final([output_encoding])
```
### 創(chuàng)建簽名
在網(wǎng)絡(luò)中,私鑰的擁有者可以在一段數(shù)據(jù)被發(fā)送之前先對(duì)該數(shù)據(jù)進(jìn)行簽名操作,在簽名的過(guò)程中,將對(duì)這段數(shù)據(jù)執(zhí)行加密處理。在經(jīng)過(guò)加密后的數(shù)據(jù)發(fā)送之后,數(shù)據(jù)的接收者可以通過(guò)公鑰的使用來(lái)對(duì)該簽名進(jìn)行解密及驗(yàn)證操作,以確保這段數(shù)據(jù)是私鑰的擁有者所發(fā)出的原始數(shù)據(jù),且在網(wǎng)絡(luò)的傳輸過(guò)程中未被修改。
在Node.js中,在進(jìn)行簽名操作之前,首先需要使用createSign方法創(chuàng)建一個(gè)sign對(duì)象
```
crypto.createSign(algorithm)
```
- algorithm:指定加密算法
createSign方法返回被創(chuàng)建的sign對(duì)象。
#### 指定加密數(shù)據(jù)
在創(chuàng)建了一個(gè)sign對(duì)象后,可以通過(guò)使用該對(duì)象的update方法來(lái)指定需要被加密的數(shù)據(jù)。
```
sign.update(data)
```
在sign對(duì)象的update方法中,使用一個(gè)參數(shù),其參數(shù)值為一個(gè)Buffer對(duì)象或一個(gè)字符串,用于指定需要被加密的數(shù)據(jù)??梢栽趯?duì)數(shù)據(jù)進(jìn)行簽名前使用多次update方法來(lái)添加數(shù)據(jù)。
#### 對(duì)數(shù)據(jù)進(jìn)行簽名
可以使用sign對(duì)象的sign方法對(duì)數(shù)據(jù)進(jìn)行簽名。在使用了sign對(duì)象的sign方法之后,不能再使用sign對(duì)象的update方法追加數(shù)據(jù)。
```
sign.sign(private_key,[output_format])
```
- private_key:為一個(gè)字符串,用于指定PEM格式的私鑰。
- output_format:用于指定簽名輸出時(shí)所使用的編碼格式,可指定參數(shù)值為“hex”、“binary”或“base64”。
### 簽名驗(yàn)證
在crypto模塊中,Verify類用于對(duì)簽名進(jìn)行驗(yàn)證操作。在對(duì)簽名進(jìn)行驗(yàn)證之前,首先需要?jiǎng)?chuàng)建一個(gè)verify對(duì)象,可以通過(guò)createVerify方法創(chuàng)建verify對(duì)象
```
crypto.createVerify(algorithm)
```
- algorithm:用于指定在驗(yàn)證簽名數(shù)據(jù)時(shí)所使用的算法
createVerify方法返回一個(gè)被創(chuàng)建的verify對(duì)象。
#### 指定需要被驗(yàn)證的數(shù)據(jù)
```
verify.update(data)
```
可以使用verify對(duì)象的verify方法來(lái)對(duì)簽名進(jìn)行驗(yàn)證。
```
verify.verify(object,signature,[signature_format])
```
- object:用于指定驗(yàn)證時(shí)所使用的對(duì)象,參數(shù)值為一個(gè)字符串,該字符串值可以為一個(gè)RSA公鑰、一個(gè)DSA公鑰或一個(gè)X.509證書(shū)。
- signature:必須為sign對(duì)象,用于指定被驗(yàn)證的簽名。
- signature_format:用于指定在生成該簽名時(shí)所使用的編碼格式,可指定參數(shù)值為“hex”、“binary”及“base64”。
#### 使用verify對(duì)象對(duì)簽名進(jìn)行驗(yàn)證
```
var crypto = require('crypto');
var fs = require('fs');
var privatePem = fs.readFileSync('key.pem');
var publicPem = fs.readFileSync('cert.pem');
var key = privatePem.toString();
var pubkey = publicPem.toString();
var data = "test"
var sign = crypto.createSign('RSA-SHA256');
sign.update(data);
var sig = sign.sign(key, 'hex');
var verify = crypto.createVerify('RSA-SHA256');
verify.update(data);
console.log(verify.verify(pubkey, sig, 'hex'));
```
### 壓縮與解壓縮處理
在Node.js中,可以使用zlib模塊進(jìn)行壓縮及解壓縮處理,在該模塊內(nèi)部使用zlib類庫(kù)實(shí)現(xiàn)這些處理。具體不做描述,可見(jiàn)node官方文檔