关于vue中使用AES+RSA混合加密通信笔记(crypto-js、node-forge)

1,059 阅读2分钟

前几天在研究AES+RSA混合加密的问题,AES用来加解密文本数据,RSA用来加解密AES key。一开始方向错了,百度最多的结果关于RSA用到的库是jsencrypt,由于后台的RSA规则是RSA/ECB/OAEPWithSHA-256AndMGF1Padding,后面换了另一个库node-forge,它支持各种加密及解密的规则。

1、思路

加密

1、生成AES key

2、用AES key对数据进行加密(AES 加密)

3、用客户端私钥对AES key加签(RSA 加签)

4、用服务端的公钥对AES key加密(RSA 加密)

解密

1、用服务端的私钥对AES key解密(RSA 解密)

2、用客户端公钥验签(RSA 验签)

3、用AES key解密数据(AES 解密)

2、实施步骤代码

1)生成密钥,pem格式

此处需要是pem格式的,需要用openssl命令去终端生成,我这边用到的密钥是2048、pkcs#8格式的,根据自己需要的格式去生成,默认是PKCS#1格式

//生成2048格式的密钥
openssl genrsa -out private.pem 2048

//查看私钥
cat private.pem

//转成pkcs8格式
openssl pkcs8 -topk8 -inform PEM -in private.pem -outform pem -nocrypt -out pkcs8.pem

//查看转成pkcs#8格式的私钥
cat pkcs8.pem

//生成对应的公钥
openssl rsa -in private.pem -pubout -out public.pem

PKCS#1格式以-----BEGIN RSA PRIVATE KEY-----开头

以-----END RSA PRIVATE KEY-----结束

PKCS#8格式以-----BEGIN PRIVATE KEY-----开头

以-----END PRIVATE KEY-----结束

-----生成私钥----- image.png

-----私钥转pkcs#8格式----- image.png

-----生成对应的公钥----- image.png

2)加密数据

生成AES key

export const getKey = () => {
  let random = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let str = "";
  for (let i = 0; i < 16; i++) {
    str = str + random.charAt(Math.random() * random.length);
  }
  return str;
};

用AES key对数据进行加密

import CryptoJS from "crypto-js";
/**
 * AES加密数据
 * @param {String} data 要加密的数据
 * @param {String} key AES加密密钥
 */
export const aesEncryteData = (data, key) => {
  // 加密选项
  let CBCOptions = {
    iv: CryptoJS.enc.Utf8.parse(key.substr(0, 16)),
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  };
  let encrypted = CryptoJS.AES.encrypt(
    CryptoJS.enc.Utf8.parse(data),
    CryptoJS.enc.Utf8.parse(key),
    CBCOptions
  );
  return encrypted.toString();
};

用客户端私钥对AES key加签

import * as forge from "node-forge";
//加签
export const signPri = (signData) => {
  const priAForrmat =
    "-----BEGIN PRIVATE KEY-----\n" + priA + "\n-----END PRIVATE KEY-----";
  var privateKey = forge.pki.privateKeyFromPem(priAForrmat);
  const md = forge.md.sha256.create();
  md.update(signData, "utf8");
  let decrypttext = privateKey.sign(md);
  let baseText = forge.util.encode64(decrypttext);
  return baseText;
};

用服务端的公钥对AES key加密

import * as forge from "node-forge";
//加密
export const encryte = (str) => {
  let pubKey = `-----BEGIN PUBLIC KEY-----\n${pubA}\n-----END PUBLIC KEY-----`;
  const pub = forge.pki.publicKeyFromPem(pubKey);
  let byteData = str;
  var encrypted = pub.encrypt(byteData, "RSA-OAEP", {
    md: forge.md.sha256.create(),
    mgf1: {
      md: forge.md.sha256.create(),
    },
  });
  let encryptText = forge.util.encode64(encrypted);
  return encryptText;
};

3)解密数据

用服务端的私钥对AES key解密

import * as forge from "node-forge";
//解密
export const decryte = (key) => {
  //base64解密
  let baseData = forge.util.decode64(key);
  let priKey = `-----BEGIN PRIVATE KEY-----\n${priA}\n-----END PRIVATE KEY-----`;

  const pri = forge.pki.privateKeyFromPem(priKey);

  //decrypt 解密 AES key
  var decrypted = pri.decrypt(baseData, "RSA-OAEP", {
    md: forge.md.sha256.create(),
    mgf1: {
      md: forge.md.sha256.create(),
    },
  });
  return decrypted;
};

用客户端公钥验签

import * as forge from "node-forge";
//验签
export const signPub = (signKey, signData) => {
  const pubAForrmat =
    "-----BEGIN PUBLIC KEY-----\n" + pubA + "\n-----END PUBLIC KEY-----";
  var publiceKey = forge.pki.publicKeyFromPem(pubAForrmat);
  const md = forge.md.sha256.create();
  md.update(signKey, "utf8");
  let erg = forge.util.decode64(signData);
  var decrypttext = publiceKey.verify(md.digest().bytes(), erg);

  return decrypttext;
};

用AES key解密数据

import CryptoJS from "crypto-js";
/**
 * AES解密数据
 * @param {String} key  AES解密密钥
 * @param {String} data 要解密的密文
 */
export const aesDecryptData = (key, data) => {
  //加密选项
  let CBCOptions = {
    iv: CryptoJS.enc.Utf8.parse(key.substr(0, 16)),
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  };
  let decrypt = CryptoJS.AES.decrypt(
    data,
    CryptoJS.enc.Utf8.parse(key),
    CBCOptions
  );
  return CryptoJS.enc.Utf8.stringify(decrypt);
};

完毕!希望能给你们带来帮助~~~