nodejs的crypto模塊基礎知識普及篇

前言

加密這方面nodejs自帶原生的crypto模塊,在網關開發中或多或少會牽涉到這塊,大部分集中在des-ecbaes的加密上,所以咱們封裝了這麼一個工具庫用來平時的加密和解密使用,傳送門html

在使用這些api以前,咱們來熟悉熟悉一下crypto模塊,以及瞭解加密和解密的一些基本知識。node

一、nodejs的crypto模塊(v11.10.0)

nodejs提供了衆多和加密解密相關的封裝器,好比OpenSSL的hash、HMAC(哈希信息驗證碼)、cipher(加密)、decipher(解密)、sign(簽名)和校驗函數。如今咱們簡單地學習一下這些對應的概念。git

1.一、Certificate

所謂的SPKAC是由網景公司原始實現的一種CSR(Certificate Signing Request/證書註冊請求)機制。crypto模塊提供Certificate類來處理SPKAC數據。Nodejs內部使用的是OpenSSL's SPKAC實現方式。github

1.二、Cipher

Cipher類實例用來加密數據。使用方式以下兩種,任選其一便可:算法

  1. 做爲一個可讀可寫的stream,這樣能夠將原生未加密的數據寫入並在可讀側生成加密的數據
  2. 使用cipher.updatecipher.final方法來產生加密的數據

所謂的Cipher是加密的意思,天然就有加密的算法了,自己密碼學就是一門複雜的學科,這裏咱們只會挑選幾個比較經常使用的加密算法來簡單解釋。typescript

首先咱們能夠查看nodejs支持的加密算法有哪些?由於nodejs內部是有使用到openssl,因此也能夠經過電腦自帶的openssl命令openssl list-cipher-algorithms獲取,也可使用下面的方式獲取:api

const crypto = require('crypto')
crypto.getCiphers()
複製代碼

獲得一個比較大的數組,都列舉不完了:數組

[ 'aes-128-cbc',
  'aes-128-cbc-hmac-sha1',
  'aes-128-cbc-hmac-sha256',
  'aes-128-ccm',
  'aes-128-cfb',
  'aes-128-cfb1',
  'aes-128-cfb8',
  'aes-128-ctr',
  'aes-128-ecb',
  'aes-128-gcm',
  'aes-128-ocb',
  'aes-128-ofb',
  'aes-128-xts',
  'aes-192-cbc',
  'aes-192-ccm',
  'aes-192-cfb',
  'aes-192-cfb1',
  'aes-192-cfb8',
  'aes-192-ctr',
  'aes-192-ecb',
  'aes-192-gcm',
  'aes-192-ocb',
  'aes-192-ofb',
  'aes-256-cbc',
  'aes-256-cbc-hmac-sha1',
  'aes-256-cbc-hmac-sha256',
  'aes-256-ccm',
  'aes-256-cfb',
  'aes-256-cfb1',
  'aes-256-cfb8',
  'aes-256-ctr',
  'aes-256-ecb',
  'aes-256-gcm',
  'aes-256-ocb',
  'aes-256-ofb',
  'aes-256-xts',
  'aes128',
  'aes128-wrap',
  'aes192',
  'aes192-wrap',
  'aes256',
  'aes256-wrap',
  'bf',
  'bf-cbc',
  'bf-cfb',
  'bf-ecb',
  'bf-ofb',
  'blowfish',
  ...
  'des',
  'des-cbc',
  'des-cfb',
  'des-cfb1',
  'des-cfb8',
  'des-ecb',
  ...
  'des3',
  ... 39 more items ]
複製代碼

咱們挑選AES加密算法和DES加密算法來講說幾個基本的加密概念安全

1.2.一、AES加密

高級加密標準(英語:Advanced Encryption Standard,縮寫:AES),在密碼學中又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣爲全世界所使用。通過五年的甄選流程,高級加密標準由美國國家標準與技術研究院(NIST)於2001年11月26日發佈於FIPS PUB 197,並在2002年5月26日成爲有效的標準。2006年,高級加密標準已然成爲對稱密鑰加密中最流行的算法之一。bash

AES使用的祕鑰長度能夠128位、192位或256位,因此你看到的加密算法:aes-128/196/256,表示的都是祕鑰的位數。而最後的一段是AES的工做模式,最經常使用的工做模式是ECB、CBC、CFB和OFB四種。

  • ECB(電子密碼本模式:Electronic codebook)是最簡單的塊密碼加密模式,加密前根據加密塊大小(如AES爲128位)分紅若干塊,以後將每塊使用相同的密鑰單獨加密,解密同理。ECB模式因爲每塊數據的加密是獨立的所以加密和解密均可以並行計算,ECB模式最大的缺點是相同的明文塊會被加密成相同的密文塊,這種方法在某些環境下不能提供嚴格的數據保密性。
  • CBC模式對於每一個待加密的密碼塊在加密前會先與前一個密碼塊的密文異或而後再用加密器加密。第一個明文塊與一個叫初始化向量的數據塊異或。CBC模式相比ECB有更高的保密性,但因爲對每一個數據塊的加密依賴與前一個數據塊的加密因此加密沒法並行。與ECB同樣在加密前須要對數據進行填充,不是很適合對流數據進行加密。
  • 與ECB和CBC模式只可以加密塊數據不一樣,CFB(密文反饋:Cipher feedback)可以將塊密文(Block Cipher)轉換爲流密文(Stream Cipher)。
  • OFB(輸出反饋:Output feedback)是先用塊加密器生成密鑰流(Keystream),而後再將密鑰流與明文流異或獲得密文流,解密是先用塊加密器生成密鑰流,再將密鑰流與密文流異或獲得明文,因爲異或操做的對稱性因此加密和解密的流程是徹底同樣的。

1.2.二、DES加密

des對稱加密,是一種比較傳統的加密方式,其加密運算、解密運算使用的是一樣的密鑰,信息的發送者和信息的接收者在進行信息的傳輸與處理時,必須共同持有該密碼(稱爲對稱密碼),是一種對稱加密算法。

DES使用一個56位的密鑰以及附加的8位奇偶校驗位,產生最大64位的分組大小。因此正常咱們給DES加密的時候都是傳遞56位祕鑰便可。一樣DES也有幾種工做模式:DES、ECB、CBC,工做模式基本和上面的一致。

1.2.三、nodejs的cipher的使用

nodejs使用crypto.createCipheriv()來建立加密實例,該函數的接受三個參數:algorithm、key、initialization vector(iv)。

那麼問題來了,什麼是初始化向量?何時須要使用到?

根據wiki的解釋:

在密碼學中,初始化向量(IV)或者起始變量(SV)是一段固定大小的到密碼原語的輸入,該原語一般要求是隨機或僞隨機的。隨機化對於加密方案實現語義安全性相當重要,這種特性使得在相同密鑰下重複使用該方案不容許攻擊者推斷加密消息片斷之間的關係。對於分組密碼,IV的使用由操做模式來描述。其餘原語也須要隨機化,例如通用哈希函數和基於此的消息身份驗證代碼。
複製代碼

一句話歸納就是:爲了保證每條消息的惟一性,須要使用初始化向量IV。

在上述的四種工做模式中,除了ECB不須要用到初始化向量,其餘三種都須要用到IV。咱們可使用該方法生成IV: Crypto.randomBytes(16)

建立加密實例後,有可能會用到這個方法:setAutoPadding,那麼爲何咱們會須要padding呢?

首先咱們先了解該方法的做用:當使用塊加密算法的時候,Cipher類會自動地添加padding到輸入塊中達到合適的塊大小。當咱們調用該函數禁用掉這個的時候,整個輸入塊的長度必須爲cipher塊尺寸的整數倍,不然調用cipher.final的時候是會報錯的。

接着回答剛纔的問題:

因爲被加密數據分組時,有可能不會正好爲128bit的整數倍,因此須要padding(填充補齊),填充的模式有如下幾種:

  1. None //不填充。
  2. PKCS7 //填充字符串由一個字節序列組成,每一個字節填充該字節序列的長度。
  3. Zeros //填充字符串由設置爲零的字節組成。
  4. ANSIX923 //ANSIX923 填充字符串由一個字節序列組成,此字節序列的最後一個字節填充字節序列的長度,其他字節均填充數字零。
  5. ISO10126 //ISO10126 填充字符串由一個字節序列組成,此字節序列的最後一個字節填充字節序列的長度,其他字節填充隨機數據。

這裏還有一個問題是:Nodejs如何決定咱們的padding使用的是哪一種呢?這個問題待解!

另一個問題是,調用完cipher.update以後還得調用一個cipher.final,這是爲啥呢?由於final的做用是收尾,由於update以後會有一些剩餘沒有加密的數據,只有調用了這個纔算是對整個數據源進行加密,所以咱們看到代碼都是兩者的結果的一個拼接。

1.三、Decipher

Decipher類的實例用於解密數據。和Cipher同樣的使用方法。就再也不贅述了

1.四、DiffieHellman

DiffieHellman類是一個用來建立Diffie-Hellman鍵交換的工具。什麼叫作Diffie-Hellman?Diffie-Hellman算法是第一個公開密鑰算法,早在 1976 年就發現了。其安全性源於在有限域上計算離散對數,比計算指數更爲困難。該算法可使兩個用戶之間安全地交換一個密鑰,但不能用於加密或解密信息。具體實現原理不贅述。

1.五、ECDH

ECDH類是建立橢圓曲線Diffie-Hellman(Elliptic Curve Diffie-Hellman (ECDH))鍵交換的實用工具。ECDH是基於ECC(Elliptic Curve Cryptosystems,橢圓曲線密碼體制,參看ECC)的DH( Diffie-Hellman)密鑰交換算法。交換雙方能夠在不共享任何祕密的狀況下協商出一個密鑰。

ECC是創建在基於橢圓曲線的離散對數問題上的密碼體制,給定橢圓曲線上的一個點P,一個整數k,求解Q=kP很容易;給定一個點P、Q,知道Q=kP,求整數k確是一個難題。ECDH即創建在此數學難題之上。

1.六、Hash

Hash類是用於建立數據哈希值的工具類。使用方式以下兩種,任選其一便可:

  1. 做爲一個可讀可寫的stream,這樣能夠將原始數據寫入並在可讀側生成Hash摘要
  2. 使用hash.updatehash.final方法來產生加密的數據

1.七、Hmac

Hmac類是用於建立加密Hmac摘要的工具。HMAC是密鑰相關的哈希運算消息認證碼(Hash-based Message Authentication Code),HMAC運算利用哈希算法,以一個密鑰和一個消息爲輸入,生成一個消息摘要做爲輸出。

1.八、Sign

Sign類是用於生成簽名的實用工具。使用方式以下兩種,任選其一便可:

  1. 做爲一個可讀可寫流,這樣能夠將須要簽名的數據寫入,而後sign.sign()方法用來生成並返回簽名
  2. 使用sign.updatesign.sign方法來產生加密的數據

1.九、Verify

Verify類是驗證簽名的工具。使用方式以下兩種,任選其一便可:

  1. 做爲可寫的stream,使用書面數據來驗證提供的簽名
  2. 使用verify.updateverify.verify的方法來驗證簽名

二、awesome-crypto

基於上面的一些基本知識,咱們在Nodejs的基礎上封裝了這麼一個基本的工具庫,供平時咱們開始中使用,鑑於還有好多在平時中沒有用到,這裏先提供簡單的一些封裝,等後續有用到的時候在上面繼續完善。

整個工具庫根據crypto的功能分爲如下文件:

├── test 單元測試文件
├── types typescript類型文件
├── lib
│   ├── cipher 封裝了加密解密相關的方法類
│   ├── certificate 封裝了證書相關的方法類
│   ├── diffieHellman 封裝了Diffie-Hellman相關的方法類
│   ├── ecdh 封裝了橢圓曲線Diffie-Hellman相關的方法類
│   ├── hash 封裝了哈希相關的方法類
│   ├── hmac 封裝了Hmac摘要相關的方法類
│   ├── sign 封裝了簽名相關的方法類
│   └── verify 封裝了簽名驗證相關的方法類
複製代碼

後續慢慢完善這個工具庫。傳送門

參考

  1. crypto
  2. 塊加密 工做模式 ECB、CBC、PCBC、CFB、OFB、CTR
相關文章
相關標籤/搜索