1. 程式人生 > >Node.js 使用 RSA 做加密

Node.js 使用 RSA 做加密

RSA

RSA加密演算法是一種非對稱加密演算法。

假設 A 與 B 通訊。A 和 B 都提供一個公開的公鑰。A 把需要傳遞的資訊,先用自己的私鑰簽名,再用 B 的公鑰加密。B 接收到這串密文後,用自己的私鑰解密,用 A 提供的公鑰驗籤。

為什麼要先簽名後加密?如果你先加密後簽名,非法使用者通過獲取的公鑰就可以破解簽名,破解之後就可以替換籤名。

詳細的原理可以參考以下文件:
RSA演算法原理(一)
RSA演算法原理(二)

node-rsa

在 node.js 中使用 rsa 演算法,我們使用的是 node-rsa 這個包。

const NodeRSA = require('node-rsa');

const a_public_key_data = '-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----';
const a_private_key_data = '-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----';

const b_public_key_data = '-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----';
const b_private_key_data = '-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----';

// 生成 A 的公私鑰物件
const a_public_key = new NodeRSA(a_public_key_data);
const a_private_key = new NodeRSA(a_private_key_data);

// 生成 B 的公私鑰物件
const a_public_key = new NodeRSA(a_public_key_data);
const a_private_key = new NodeRSA(a_private_key_data);

const text = 'Hello RSA!';

// 加簽並加密
const sign = a_private_key.sign(text, 'base64', 'utf8');
console.log('A 私鑰加簽:', sign);

const encrypted = a_public_key.encrypt(sign, 'base64');
console.log('B 公鑰加密:', encrypted);

// 解密並驗籤
const decrypted = a_public_key.decrypt(encrypted, 'utf8');
console.log('B 私鑰解密:', decrypted);

const verify = a_public_key.verify(text, decrypted, 'utf8', 'base64');
console.log('A 公鑰驗籤:', verify);

serialize

介面傳遞的一般是複雜的物件,所以我們需要把物件按一定的順序排列並序列化成字串再進行簽名加密的操作

const serialize = (obj) => {
  const str = [];
  Object.keys(obj).sort().forEach((key) => {
    if (obj.hasOwnProperty(key)) {
      str.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
    }
  });
  return str.join('&');
};

注意

RSA 演算法有一定的計算量,加上 Node 不適合做計算密集型的操作。當介面被頻繁呼叫可能會佔用主執行緒,阻塞其他介面,使用了 RSA 的介面併發量會下降十倍左右。如非必要,謹慎在 Node 裡使用 RSA。