nodejs常用加密方式 RSA & AES

Merlo發表於2019-10-18

RSA

RSA演算法是一種非對稱加密演算法,即由一個私鑰和一個公鑰構成的金鑰對,通過私鑰加密,公鑰解密,或者通過公鑰加密,私鑰解密。其中,公鑰可以公開,私鑰必須保密。

// 生成一個RSA金鑰對:
openssl genrsa -aes256 -out rsa-key.pem 2048
// 根據提示輸入密碼,這個密碼是用來加密RSA金鑰的,加密方式指定為AES256,生成的RSA的金鑰長度是2048位。執行成功後,我們獲得了加密的rsa-key.pem檔案。
複製程式碼
// 通過上面的rsa-key.pem加密檔案,我們可以匯出原始的私鑰:
openssl rsa -in rsa-key.pem -outform PEM -out rsa-prv.pem
// 輸入第一步的密碼,我們獲得瞭解密後的私鑰
複製程式碼
// 類似的,我們用下面的命令匯出原始的公鑰:
openssl rsa -in rsa-key.pem -outform PEM -pubout -out rsa-pub.pem
// 這樣,我們就準備好了原始私鑰檔案rsa-prv.pem和原始公鑰檔案rsa-pub.pem,編碼格式均為PEM
複製程式碼

因為RSA加密的原始資訊必須小於Key的長度。那如何用RSA加密一個很長的訊息呢?實際上,RSA並不適合加密大資料,而是先生成一個隨機的AES密碼,用AES加密原始資訊,然後用RSA加密AES口令,這樣,實際使用RSA時,給對方傳的密文分兩部分,一部分是AES加密的密文,另一部分是RSA加密的AES口令。對方用RSA先解密出AES口令,再用AES解密密文,即可獲得明文。


用AES加密原始資訊

AES是一種常用的對稱加密演算法,加解密都用同一個金鑰,node的crypto模組提供了AES支援,但是需要自己封裝好函式(nodejs),便於使用:

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);
複製程式碼

執行結果:

Plain text: Hello, this is a secret message!
Encrypted text: 8a944d97bdabc157a5b7a40cb180e7...
Decrypted text: 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格式。


相關文章