javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > 前端crypto-js库aes加解密

前端使用crypto-js库aes加解密详细代码示例

作者:你不讲 wood

在前端开发中数据的加密和解密是为了保障用户隐私和数据的安全性而常见的任务,这篇文章主要给大家介绍了关于前端使用crypto-js库aes加解密的相关资料,需要的朋友可以参考下

前言

CryptoJS是一个JavaScript加密算法库,用于在客户端浏览器中执行加密和解密操作。它提供了一系列常见的加密算法,如AES、DES、Triple DES、Rabbit、RC4、MD5、SHA-1等等。

AES

工作原理

AES(高级加密标准)是一种对称加密算法,即加密和解密使用相同的密钥。它可以加密长度为128、192和256位的数据块,并使用128位的密钥进行加密。AES算法使用了固定的块长度和密钥长度,并且被广泛应用于许多安全协议和标准中,例如SSL/TLS、SSH、IPSec等。

在AES加密中,明文被分成128位的块,每个块使用相同的密钥进行加密。加密过程包括以下步骤:

解密过程与加密过程类似,只是将加密过程中的步骤反过来。需要注意的是,解密的过程中使用的是相同的密钥和轮密钥。由于AES是一种块加密算法,因此在加密过程中,需要对数据进行填充,确保数据块大小为128位。

AES算法的优点

github地址: https://github.com/brix/crypto-js

cryptojs文档: https://cryptojs.gitbook.io/docs/#encoders

在线aes加密解密工具: http://tool.chacuo.net/cryptaes

安装

script 标签嵌入

<script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/aes.min.js"></script>

npm 或 yarn 安装

npm install crypto-js

yarn add crypto-js

CommonJS

const CryptoJS = require('crypto-js');

ES module:

import CryptoJS from 'crypto-js';

封装加密和解密

import CryptoJS from 'crypto-js'

 // ------------AES-------------
 
 function getAesString(data, key, iv) { //加密
   let keys = CryptoJS.enc.Utf8.parse(key)
   let vis = CryptoJS.enc.Utf8.parse(iv)
   let encrypt = CryptoJS.AES.encrypt(data, keys, {
     iv: vis, //iv偏移量 CBC需加偏移量
     mode: CryptoJS.mode.CBC, //CBC模式
     // mode: CryptoJS.mode.ECB, //ECB模式
     padding: CryptoJS.pad.Pkcs7 //padding处理
   });
   // debugger
   return encrypt.toString(); //加密完成后,转换成字符串
 }
 
 function getDAesString(encrypted, key, iv) { // 解密
   var key  = CryptoJS.enc.Utf8.parse(key);
   var iv   = CryptoJS.enc.Utf8.parse(iv);
   var decrypted =CryptoJS.AES.decrypt(encrypted,key,{
     iv:iv,
     mode:CryptoJS.mode.CBC,
     padding:CryptoJS.pad.Pkcs7
   });
   return decrypted.toString(CryptoJS.enc.Utf8);
 }

 // AES 对称秘钥加密
 const aes = {
   en: (data, key) => getAesString(data, key.key, key.iv),
   de: (data, key) => getDAesString(data, key.key, key.iv)
 };
 // BASE64
 const base64 = {
   en: (data) => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)),
   de: (data) => CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8)
 };
 // SHA256
 const sha256 = (data) => {
   return CryptoJS.SHA256(data).toString();
 };
 // MD5
 const md5 = (data) => {
 return CryptoJS.MD5(data).toString();
 };
 
 export { aes, md5, sha256, base64 };

使用 JSEncrypt 生成密钥

JSEncrypt是基于JavaScript的RSA加密库,允许在浏览器端使用RSA算法进行加密和解密操作。它提供了容易使用的API,简化了在客户端上进行加密的过程。

JSEncrypt支持以下操作:

使用JSEncrypt进行RSA加密的基本步骤如下:

需要注意的是,由于JSEncrypt是在客户端上执行的,所以密钥在传输过程中可能会存在安全风险。为了确保数据的安全性,建议在客户端和服务器之间使用安全的通信协议进行数据传输,并在服务器端进行进一步的安全验证和处理。

import JSEncrypt from 'jsencrypt'
const encrypt = new JSEncrypt();
let publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeCDcnFrS7DIRbvZLHreVUzaMbAFy2DYmioxBK606urY4rVR8IgLgUhnyw2/GQ99pyr8lGtqPeOoapantw1XwEVyi74MDxs4UDL8j4OZR1Es7HVGOB0GwKWobdU9cm/1iDwGyouSmijxKyAePg6KsLNgbjDPYZRS11bYEuZ8/RLQIDAQAB';
encrypt.setPublicKey('-----BEGIN PUBLIC KEY-----' + publicKey + '-----END PUBLIC KEY-----')

const random = (length) => {
  var str = Math.random().toString(36).substr(2);
  if (str.length>=length) {
    return str.substr(0, length);
  }
  str += random(length-str.length);
  return str;
}

export const rsaEncode = (src)=>{
  let data = encrypt.encrypt(src); // 加密
  return data
};

export const getKey = ()=>{
  let key = { key: random(16), iv: random(16) }; // 生成密钥
  let code = rsaEncode(key.key + ',' + key.iv) // 给密钥加密,在将加密后的密钥传给后端
  window.codeArr = window.codeArr || {}
  codeArr[code] = key
  return {
    key, code
  }
};

export const getAesKey = (aes)=>{
  let key = JSON.parse(JSON.stringify(codeArr[aes]))
  delete codeArr[aes]
  return key
};



window.getKey = getKey
window.rsaEncode = rsaEncode

publicKey 可以通过发请求后端返回,也可以自己定义,要求前后端一致

封装 axios 拦截器进行加密解密

/**
 *
 * http配置
 *
 */
// 引入axios以及element ui中的loading和message组件
import { aes } from "@/util/encrypt.js";
import { getKey, getAesKey } from "@/config/key.js";
import axios from "axios";
import store from "../store";
import router from "../router/router";
import { Loading, Message } from "element-ui";
import { getSessStore, setSessStore } from "@/util/store";


// 超时时间
if (store.online) axios.defaults.timeout = 20000;
else axios.defaults.timeout = 0;
//跨域请求,允许保存cookie
axios.defaults.withCredentials = true;

// 统一加解密
const Unify = {
  // 统一加密方法
  en(data, key) {
    // 1.aes加密
    let aesStr = aes.en(JSON.stringify(data), key);
    return aesStr;
  },
  // 统一解密
  de(aesStr, key) {
    // 1.aes解密
    let dataStr = aes.de(aesStr, key);
    // 3.转json对象
    let data = JSON.parse(dataStr);
    return data;
  },
};

let loadinginstace;
let cfg, msg;
msg = "服务器君开小差了,请稍后再试";
function ens(data) {
  // debugger
  let src = [...data];
  src = JSON.stringify(src);
  let dataJm = aes.en(src);
  return dataJm;
}
function des(data) {
  // debugger
  let src = [...data];
  let dataJm = aes.de(src);
  dataJm = JSON.parse(dataJm);
  return dataJm;
}
const cancelToken = axios.CancelToken
const source = cancelToken.source()
//HTTPrequest拦截
axios.interceptors.request.use(
  function (config) {
    console.log(config.data, "加密前入参---");
    config.cancelToken = source.token; // 全局添加cancelToken
    loadinginstace = Loading.service({
      fullscreen: true,
    });
    if (store.getters.token) {
      let info = getSessStore("token");
      // console.log("info", info);
      config.headers["Authorization"] = "Bearer " + info; // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
    }
    const contenttype = config.headers.common["Accept"];
    let types = contenttype.includes("application/json");
    let key = getKey(); // 获取密钥
    config.headers["aes"] = key.code; // 将 aes 的 code 设置到请求头,传给后端解密
    config.headers["name"] = "send";
    if (types) {
      if (config.method == "post" || config.method == "put") {
        if (config.data) {
          config.headers["crypto"] = true;
          config.headers["content-type"] = "application/json";
          let data = {
            body: config.data,
          };
          let dataJm = Unify.en(data, key.key); // 加密 post 请求参数
          config.data = dataJm;
        }
      }
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

//HTTPresponse拦截
axios.interceptors.response.use(
  (response) => {
    loadinginstace.close();
    let res = response.data || {};
    if (response.headers["date"]) {
      store.commit("setServiceTime", response.headers.date);
    }
    if (res.crypto) {
      try {
        let key = getAesKey(response.headers.aes); /// 拿到公钥加密字符串
        if (!key) {
          message("获取密钥异常", "error");
          return Promise.reject(res);
        }
        // debugger
        res = Unify.de(res.body, key);
        response.data = res;
      } catch (err) {
        message("系统异常:" + err.message, "error");
        return Promise.reject(err);
      }
    }
    // debugger
    if (res.code === 1) {
      message(res.msg, "error");
      return Promise.reject(res);
    }
    console.log(response, "解密后response");
    return response;
  },
  (error) => {
    console.log("错误信息", error);
    loadinginstace.close();
    const res = error.response || {};
    if (res.status === 478 || res.status === 403 || res.status === 401) {
      let resMsg = res.data.msg ? res.data.msg : res.data.data
      if (res.status === 403) {
        message('服务授权失败,请联系管理添加权限!', "error");
      } else {
        message(resMsg, "error");
      }
      let flg = res.data.msg.includes('当前登录状态已失效')
      if (res.status === 478 && flg) {
        //token失效
        source.cancel('登录信息已过期'); // 取消其他正在进行的请求
        store.dispatch("FedLogOut").then(() => {
          router.push("/login"); ///test
        });
      }
    } else if (res.status === 400) {
      message(res.data.error_description, "error");
    } else if (res.status === 202) {
      //三方未绑定
      this.$router.push({
        path: "/",
      });
    } else if (res.status === 503 || res.status === 504) {
      //服务异常
      message(res.data, "error");
    } else if (
      (res.status === 401 && res.statusText == "Unauthorized") ||
      res.data.error == "invalid_token" ||
      res.data.error == "unauthorized"
    ) {
      //token失效
      store.dispatch("FedLogOut").then(() => {
        router.push("/login"); ///test
      });
    } else {
      message(res.data.message, "error");
    }
    return Promise.reject(error);
  }
);
export function message(text, type) {
  let t = text ? text : "服务或网络异常!"
  Message({
    message: t,
    type: type,
    duration: 30 * 1000,
    center: true,
    showClose: true
  });
}
export default axios;

总结

加密: 使用 JSEncrypt 生成私钥 key 并将密钥 key 加密得到 code, 使用 CryptoJS.AES.encrypt() 和 key 加密请求数据,将 加密后的 code 设置在请求头,后端获取加密后 code 进行解密得到私钥 key ,再对请求数据解密得到原始数据

解密: 前端获取响应头的key,通过解密 JSEncrypt 解密得到私钥 key, 使用 CryptoJS.AES.decrypt() 方法对响应数据进行解密,得到原始数据

到此这篇关于前端使用crypto-js库aes加解密的文章就介绍到这了,更多相关前端crypto-js库aes加解密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文