javascript
nodeJS之crypto加密
加密模塊提供了 HTTP 或 HTTPS 連接過程中封裝安全憑證的方法。也提供了 OpenSSL 的哈希,hmac, 加密(cipher), 解密(decipher), 簽名(sign) 和 驗證(verify) 方法的封裝。本文將詳細介紹加密crypto
?
crypto
【crypto.setEngine(engine[, flags])】
為某些/所有 OpenSSL 函數加載并設置引擎(根據參數 flags 來設置)。
engine 可能是 id,或者是指向引擎共享庫的路徑。
flags是可選參數,默認值是ENGINE_METHOD_ALL ,可以是以下一個或多個參數的組合(在constants里定義)
ENGINE_METHOD_RSA ENGINE_METHOD_DSA ENGINE_METHOD_DH ENGINE_METHOD_RAND ENGINE_METHOD_ECDH ENGINE_METHOD_ECDSA ENGINE_METHOD_CIPHERS ENGINE_METHOD_DIGESTS ENGINE_METHOD_STORE ENGINE_METHOD_PKEY_METH ENGINE_METHOD_PKEY_ASN1_METH ENGINE_METHOD_ALL ENGINE_METHOD_NONE
【crypto.getCiphers()】
返回支持的加密算法名數組
?crypto?=?require('crypto'
【crypto.getCiphers()】
返回支持的哈希算法名數組。
var?crypto?=?require('crypto'); console.log(crypto.getHashes());//[?'DSA',??'DSA-SHA',??'DSA-SHA1',??'DSA-SHA1-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'?]
【crypto.getCurves()】
返回支持的橢圓曲線名數組。
var?crypto?=?require('crypto'); console.log(crypto.getCurves());//[?'Oakley-EC2N-3',??'Oakley-EC2N-4',??'brainpoolP160r1',??'brainpoolP160t1',??'brainpoolP192r1',??'brainpoolP192t1',??'brainpoolP224r1',??'brainpoolP224t1',??'brainpoolP256r1',??'brainpoolP256t1',??'brainpoolP320r1',??'brainpoolP320t1',??'brainpoolP384r1',??'brainpoolP384t1',??'brainpoolP512r1',??'brainpoolP512t1',??'c2pnb163v1',??'c2pnb163v2',??'c2pnb163v3',??'c2pnb176v1',??'c2pnb208w1',??'c2pnb272w1',??'c2pnb304w1',??'c2pnb368w1',??'c2tnb191v1',??'c2tnb191v2',??'c2tnb191v3',??'c2tnb239v1',??'c2tnb239v2',??'c2tnb239v3',??'c2tnb359v1',??'c2tnb431r1',??'prime192v1',??'prime192v2',??'prime192v3',??'prime239v1',??'prime239v2',??'prime239v3',??'prime256v1',??'secp112r1',??'secp112r2',??'secp128r1',??'secp128r2',??'secp160k1',??'secp160r1',??'secp160r2',??'secp192k1',??'secp224k1',??'secp224r1',??'secp256k1',??'secp384r1',??'secp521r1',??'sect113r1',??'sect113r2',??'sect131r1',??'sect131r2',??'sect163k1',??'sect163r1',??'sect163r2',??'sect193r1',??'sect193r2',??'sect233k1',??'sect233r1',??'sect239k1',??'sect283k1',??'sect283r1',??'sect409k1',??'sect409r1',??'sect571k1',??'sect571r1',??'wap-wsg-idm-ecid-wtls1',??'wap-wsg-idm-ecid-wtls10',??'wap-wsg-idm-ecid-wtls11',??'wap-wsg-idm-ecid-wtls12',??'wap-wsg-idm-ecid-wtls3',??'wap-wsg-idm-ecid-wtls4',??'wap-wsg-idm-ecid-wtls5',??'wap-wsg-idm-ecid-wtls6',??'wap-wsg-idm-ecid-wtls7',??'wap-wsg-idm-ecid-wtls8',??'wap-wsg-idm-ecid-wtls9'?]
?
MD5
MD5是一種常用的哈希算法,用于給任意數據一個“簽名”。這個簽名通常用一個十六進制的字符串表示:
【crypto.createHash(algorithm)】
創建并返回一個哈希對象,使用指定的算法來生成哈希摘要。
參數 algorithm 取決于平臺上 OpenSSL 版本所支持的算法。例如,'sha1', 'md5', 'sha256', 'sha512' 等等
【hash.update(data[, input_encoding])】
根據 data 來更新哈希內容,編碼方式根據 input_encoding 來定,有 'utf8', 'ascii' 或 'binary'。如果沒有傳入值,默認編碼方式是'utf8'。如果 data 是 Buffer, input_encoding 將會被忽略。
因為它是流式數據,所以可以使用不同的數據調用很多次。
【hash.digest([encoding])】
計算傳入的數據的哈希摘要。encoding 可以是 'hex', 'binary' 或 'base64',如果沒有指定encoding ,將返回 buffer。
[注意]調用 digest() 后不能再用 hash 對象。
var?crypto?=?require('crypto');var?hash?=?crypto.createHash('md5');//?可任意多次調用update():hash.update('Hello,?world!'); hash.update('Hello,?nodejs!');console.log(hash.digest('hex'));?//?7e1977739c748beac0c0fd14fd26a544
?
Hmac
Hmac算法也是一種哈希算法,它可以利用MD5或SHA1等哈希算法。不同的是,Hmac還需要一個密鑰:
【crypto.createHmac(algorithm, key)】
創建并返回一個 hmac 對象,用指定的算法和秘鑰生成 hmac 圖譜。
它是可讀寫的流 stream 。寫入的數據來用計算 hmac。當寫入流結束后,使用 read() 方法來獲取計算后的值。也支持老的 update 和 digest 方法。
參數 algorithm 取決于平臺上 OpenSSL 版本所支持的算法,參見前面的 createHash。key是 hmac 算法中用的 key
【hmac.update(data)】
根據 data 更新 hmac 對象。因為它是流式數據,所以可以使用新數據調用多次。
【hmac.digest([encoding])】
計算傳入數據的 hmac 值。encoding可以是 'hex', 'binary' 或 'base64',如果沒有指定encoding ,將返回 buffer。
[注意]調用 digest() 后不能再用 hmac 對象
var?crypto?=?require('crypto');var?hmac?=?crypto.createHmac('sha256',?'match');hmac.update('Hello,?world!'); hmac.update('Hello,?nodejs!');//e82a58066cae2fae4f44e58be1d589b66a5d102c2e8846d796607f02a88c1649console.log(hmac.digest('hex'));
?
AES
AES是一種常用的對稱加密算法,加解密都用同一個密鑰。crypto模塊提供了AES支持,但是需要自己封裝好函數,便于使用:
【crypto.createCipher(algorithm, password)】
使用傳入的算法和秘鑰來生成并返回加密對象。
algorithm 取決于 OpenSSL,例如'aes192'等。password 用來派生 key 和 IV,它必須是一個'binary' 編碼的字符串或者一個buffer。
它是可讀寫的流 stream 。寫入的數據來用計算 hmac。當寫入流結束后,使用 read() 方法來獲取計算后的值。也支持老的update 和 digest 方法。
【cipher.update(data[, input_encoding][, output_encoding])】
根據 data 來更新哈希內容,編碼方式根據 input_encoding 來定,有 'utf8', 'ascii' or 'binary'。如果沒有傳入值,默認編碼方式是'binary'。如果data 是 Buffer,input_encoding 將會被忽略。
output_encoding 指定了輸出的加密數據的編碼格式,它可用是 'binary', 'base64' 或 'hex'。如果沒有提供編碼,將返回 buffer 。
返回加密后的內容,因為它是流式數據,所以可以使用不同的數據調用很多次。
【cipher.final([output_encoding])】
返回加密后的內容,編碼方式是由 output_encoding 指定,可以是 'binary', 'base64' 或 'hex'。如果沒有傳入值,將返回 buffer。
[注意]cipher 對象不能在 final() 方法之后調用。
var?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; }var?data?=?'Hello,?this?is?a?secret?message!';var?key?=?'Password!';var?encrypted?=?aesEncrypt(data,?key);//8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0cconsole.log(encrypted);
【crypto.createDecipher(algorithm, password)】
根據傳入的算法和密鑰,創建并返回一個解密對象。這是 createCipher() 的鏡像
【decipher.update(data[, input_encoding][, output_encoding])】
使用參數 data 更新需要解密的內容,其編碼方式是 'binary','base64' 或 'hex'。如果沒有指定編碼方式,則把 data 當成 buffer 對象。
如果 data 是 Buffer,則忽略 input_encoding 參數。
參數 output_decoding 指定返回文本的格式,是 'binary', 'ascii' 或 'utf8' 之一。如果沒有提供編碼格式,則返回 buffer。
【decipher.final([output_encoding])】
返回剩余的解密過的內容,參數 output_encoding 是 'binary', 'ascii' 或 'utf8',如果沒有指定編碼方式,返回 buffer。
[注意]decipher對象不能在 final() 方法之后使用。
var?crypto?=?require('crypto');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?=?'8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0c';var?decrypted?=?aesDecrypt(encrypted,?key); console.log(decrypted);//Hello,?this?is?a?secret?message!
可以看出,加密后的字符串通過解密又得到了原始內容。
注意到AES有很多不同的算法,如aes192,aes-128-ecb,aes-256-cbc等,AES除了密鑰外還可以指定IV(Initial Vector),不同的系統只要IV不同,用相同的密鑰加密相同的數據得到的加密結果也是不同的。加密結果通常有兩種表示方法:hex和base64,這些功能Nodejs全部都支持,但是在應用中要注意,如果加解密雙方一方用Nodejs,另一方用Java、PHP等其它語言,需要仔細測試。如果無法正確解密,要確認雙方是否遵循同樣的AES算法,字符串密鑰和IV是否相同,加密后的數據是否統一為hex或base64格式
【crypto.createCipheriv(algorithm, key, iv)】
創建并返回一個加密對象,用指定的算法,key 和 iv。
algorithm 參數和 createCipher() 一致。key 在算法中用到.iv 是一個initialization vector.
key 和 iv 必須是 'binary' 的編碼字符串或buffers.
【crypto.createDecipheriv(algorithm, key, iv)】
根據傳入的算法,密鑰和 iv,創建并返回一個解密對象。這是 createCipheriv() 的鏡像。
const?crypto?=?require('crypto');function?aesEncryptiv(data,?key,iv)?{const?cipher?=?crypto.createCipher('aes192',?key,?iv);????var?crypted?=?cipher.update(data,?'utf8',?'hex');crypted?+=?cipher.final('hex');????return?crypted; }function?aesDecryptiv(encrypted,?key,iv)?{const?decipher?=?crypto.createDecipher('aes192',?key,?iv);????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?iv?=?'match';var?encrypted?=?aesEncryptiv(data,?key,?iv);var?decrypted?=?aesDecryptiv(encrypted,?key,?iv);//Hello,?this?is?a?secret?message!console.log(data);//8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0cconsole.log(encrypted);//Hello,?this?is?a?secret?message!console.log(decrypted);
?
Diffie-Hellman
【crypto.createDiffieHellman(prime[, prime_encoding][, generator][, generator_encoding])】
使用傳入的 prime 和 generator 創建 Diffie-Hellman 秘鑰交互對象。
generator 可以是數字,字符串或Buffer。如果沒有指定 generator,使用 2
prime_encoding 和 generator_encoding 可以是 'binary', 'hex', 或 'base64'。
如果沒有指定 prime_encoding, 則 Buffer 為 prime。如果沒有指定 generator_encoding ,則 Buffer 為 generator。
【diffieHellman.generateKeys([encoding])】
生成秘鑰和公鑰,并返回指定格式的公鑰。這個值必須傳給其他部分。編碼方式: 'binary', 'hex', 或 'base64'。如果沒有指定編碼方式,將返回 buffer。
【diffieHellman.getPrime([encoding])】
用參數 encoding 指明的編碼方式返回 Diffie-Hellman 質數,編碼方式為: 'binary', 'hex', 或 'base64'。 如果沒有指定編碼方式,將返回 buffer。
【diffieHellman.getGenerator([encoding])】
用參數 encoding 指明的編碼方式返回 Diffie-Hellman 生成器,編碼方式為: 'binary', 'hex', 或 'base64'. 如果沒有指定編碼方式 ,將返回 buffer。
【diffieHellman.computeSecret(other_public_key[, input_encoding][, output_encoding])】
使用 other_public_key 作為第三方公鑰來計算并返回共享秘密(shared secret)。秘鑰用input_encoding 編碼。編碼方式為:'binary', 'hex', 或 'base64'。如果沒有指定編碼方式 ,默認為 buffer。
如果沒有指定返回編碼方式,將返回 buffer。
DH算法
DH算法是一種密鑰交換協議,它可以讓雙方在不泄漏密鑰的情況下協商出一個密鑰來。DH算法基于數學原理,比如小明和小紅想要協商一個密鑰,可以這么做:
1、小明先選一個素數和一個底數,例如,素數p=23,底數g=5(底數可以任選),再選擇一個秘密整數a=6,計算A=g^a mod p=8,然后大聲告訴小紅:p=23,g=5,A=8;
2、小紅收到小明發來的p,g,A后,也選一個秘密整數b=15,然后計算B=g^b mod p=19,并大聲告訴小明:B=19;
3、小明自己計算出s=B^a mod p=2,小紅也自己計算出s=A^b mod p=2,因此,最終協商的密鑰s為2。
在這個過程中,密鑰2并不是小明告訴小紅的,也不是小紅告訴小明的,而是雙方協商計算出來的。第三方只能知道p=23,g=5,A=8,B=19,由于不知道雙方選的秘密整數a=6和b=15,因此無法計算出密鑰2。
用crypto模塊實現DH算法如下:
var?crypto?=?require('crypto');//?xiaoming's?keys:var?ming?=?crypto.createDiffieHellman(512);var?ming_keys?=?ming.generateKeys();var?prime?=?ming.getPrime();var?generator?=?ming.getGenerator();//Prime:?8df777257625c66821af697652f28e93af05b9f779af919111b89816faa11c36fcf9df04c76811471a6099800213c4fe8e3fbec8d2f90bd00795e4b7fd241603console.log('Prime:?'?+?prime.toString('hex'));//Generator:?02console.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);//Secret?of?Xiao?Ming:?4237157ab4c9211f78ffdb67d127d749cec91780d594b81a7e75f1fb591fecb84f33ae6591e1edda4bc9685b503010fe8f9928c6ed69e4ff9fdb44adb9ba1539console.log('Secret?of?Xiao?Ming:?'?+?ming_secret.toString('hex'));//Secret?of?Xiao?Hong:?4237157ab4c9211f78ffdb67d127d749cec91780d594b81a7e75f1fb591fecb84f33ae6591e1edda4bc9685b503010fe8f9928c6ed69e4ff9fdb44adb9ba1539console.log('Secret?of?Xiao?Hong:?'?+?hong_secret.toString('hex'))
? [注意]每次輸出都不一樣,因為素數的選擇是隨機的。
轉載于:https://blog.51cto.com/13013666/1943021
總結
以上是生活随笔為你收集整理的nodeJS之crypto加密的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开发者需要了解的WebKit
- 下一篇: css03层次选择器