前后端AES加密通讯CBC模式最新可用超详细

97 阅读3分钟

内容都在标题里面了 下面开始介绍环境

本文为技术实现文档 对为什么要使用和加密原理不做解析 后端为Springboot 前端为uni项目 vue2框架 js语言

我会在代码中说明每一行我踩的坑 并且附上通俗易懂的注释 详细阅读相信你一定会有收获

后端加密部分 传入一个object返回一个String密文

public String encrypt(Object data) throws Exception {
        // 创建ObjectMapper实例,用于将数据转换为JSON字符串
        ObjectMapper objectMapper = new ObjectMapper();
        // 将数据转换为JSON字符串
        // 注意这里可能直接拿去是无法直接跑起来的 可能会报错 说jdk8 无法格式化时间类
        // 这个问题是因为你传入的对象中有LocalDateTime这个类型的属性
        // 直接百度查询然后引入一个jackson-datatype-jsr310依赖就可以解决 对前后端
        // 没有任何影响 具体的使用方法查询就好  也私信我 我单独写一篇
        String jsonData = objectMapper.writeValueAsString(data);
        // 生成一个安全随机的iv
        // 这里调用自己写的 随机生成16位16进制的iv方法 代码在下面
        String iv = getIv();
         // 用于初始化向量参数
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());

        // 初始化加密算法
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        // 初始化加密密钥和向量
        // 注意这里的密钥是32字节的 因为使用了256位的方式 这样更加的安全 而且性能也不会很低
        // 密钥长度可以是128位(16字节)、192位(24字节)或256位(32字节
        SecretKeySpec secretKey = new SecretKeySpec("sZi8knPmD0BmXth3Ds48zSwBRs6Ow993".getBytes(), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        // 拿到加密后的数据
        byte[] encryptedBytes = cipher.doFinal(jsonData.getBytes());
        // 将IV和加密后的数据一起返回
		// 将向量和密文进行base64编码 然后传递给前端
        String encodedIV = Base64.getEncoder().encodeToString(iv.getBytes());
        String encodedData = Base64.getEncoder().encodeToString(encryptedBytes);
        return encodedIV + "|" + encodedData;
    }
 // 获取一个随机的16位16进制的iv向量
    public String getIv(){
        SecureRandom random = new SecureRandom();
        byte[] bytes = new byte[8]; //8字节就是16个字符
        random.nextBytes(bytes);
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
        // 这里我目前通过测试 必须先拿到byte数组 然后格式化16进制 再去获取getbyte
        // 然后再去base64编码   不然就会因为随机数出来的值中有负数 
        // 进行base64编码的时候 就是加密成功 前端也是解密不出来 而且base64的解码
        // 也是完全不同 根本不可用
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

前端部分

decrypt(encryptedData) {
      // 分离 IV 和加密数据
      const parts = encryptedData.split('|');
      const iv = CryptoJS.enc.Base64.parse(parts[0]); // 因为后端返回的时候把iv用base64编码了 所有需要用base64的格式化方法
  
      const keyBytes = CryptoJS.enc.Utf8.parse('sZi8knPmD0BmXth3Ds48zSwBRs6Ow993'); //密钥是utf8格式的 所以需要使用utf8的格式方法 
  
      // 解密数据
      const decryptedData = CryptoJS.AES.decrypt({
          ciphertext: CryptoJS.enc.Base64.parse(parts[1]) //密文后端传递的也是base64的方法
        },
        keyBytes, {
          iv: iv, //向量 必须经过CryptoJS.enc.Base64.parse转成对应的类型
          mode: CryptoJS.mode.CBC,//模式
          padding: CryptoJS.pad.Pkcs7//填充方式 位数不够补 等于号
        }
      );
  
      // 将解密后的数据转换为明文
      const decryptedText = decryptedData.toString(CryptoJS.enc.Utf8);
      return JSON.parse(decryptedText) //转成对象返回
  }

最后呢 感谢观看 如果能跑起来的话 还是可以去研究一下 每一个类是什么东西的 当初直接找AI 报了不知道多少错 怎么问都解决不了 最后还得是自己学习一下 才研究明白的 主要注意点就是 编码 这个很关键

感谢观看 如果可以的话 点一个赞吧 不定期更新前后端 踩坑文章 你的点赞就是我坚持下去的动力 保证文章提问永久免费