NodeJS:用户登录密码:非对称加密(RAS)

769 阅读1分钟

RSA是一种非对称加密,也就是客户端通过公钥进行加密,服务端通过私钥进行解密。 RSA算法请点击维基百科RSA加密演算法进行了解

也就是说公钥并不能进行解密,因此进行明文传输也是安全的。

技术栈

node-rsa

安装

npm i node-rsa

前台部分

import NodeRSA from "node-rsa";
const publicKeyXX = { b: 512 }; // 产生的秘钥长度 必须为8的倍数 

// 请求公钥API
function getPublicKeyApi(BASE_URL) {
  let getPublicKeyAjax = new Promise((resolve) => {
    $.ajax({
      url: BASE_URL + "/get/PublicKey",
      type: "GET",
      success: function (result) {
        resolve(result.data);
      },
      error: function () {},
    });
  });
  return getPublicKeyAjax;
}

// 获取公钥
function getPublicKey() {
    let publicKey_ = new Promise((resolve) => {
      getPublicKeyApi().then((PubKey) => {
        // PubKey 为后台返回的公钥
        resolve(PubKey);
      });
    });
    return publicKey_;
}

// 生成密文
var encryptStr = async function (password) {
  let clientKey = new NodeRSA(publicKeyXX);
  var pubKey = await getPublicKey(); //从服务端接收到的公钥
  clientKey.importKey(pubKey);
  let encrypted = clientKey.encrypt(password, "base64");
  return encrypted;
};

export { encryptStr, getPublicKey };

node后台

const NodeRSA = require('node-rsa');
// 初始化时直接创建公钥、私钥
function initNodeRSA() {
    let key = new NodeRSA({ b: 512 });
    let publicDer = key.exportKey("pkcs8-public");
    let privateDer = key.exportKey("pkcs8-private");
    global.publicCacheDer = publicDer
    global.privateCacheDer = privateDer
}
initNodeRSA()
// 解密 密文
function decryptPassWord (pwd) {
  let key = new NodeRSA({ b: 512 });
  let privateDer_ = global.privateCacheDer; //从缓存读取私钥
  
  if (!privateDer_) {
    console.log("获取RSA私钥失败!!");
    return null;
  }
 
  key.importKey(privateDer_);
  if (!key.isPrivate()) {
    //验证私钥是否正确
    console.log("导入RSA私钥失败!!");
    return null;
  }
  let password = null;
  try{
    password = key.decrypt(pwd, "utf8"); // 注意此处为 utf8 才能得到用户密码,并不是前台的base64
  } catch (e) {
      console.log("密码解密出错 ");
      console.log('e: ', e);
  }
  return password; //解密
};

说明

注意:每次服务重启后公钥会改变,所以前台每次都请求一下,也可以按照自己需求将公钥存在localStorage 每次从缓存中读取,避免频繁请求公钥,当解密失败的时候 再去请求一下公钥即可。