CryptoJS中AES实现前后端通用加解密技术


Posted in Javascript onDecember 18, 2018

在项目中如果要对前后端传输的数据双向加密, 比如避免使用明文传输用户名,密码等数据。 就需要对前后端数据用同种方法进行加密,方便解密。这里介绍使用 CryptoJS 实现 AES 加解密。

首先需要下载前台使用 CryptoJS 实现 AES 加解密的,所以要先下载组件,下载 CryptoJS-v3.1.2 版本之后,文件中包含components 和 rollups 两个文件夹,components 文件夹下是单个组件,rollups 文件夹下是汇总,引用 rollups 下的 aes.js 文件即可。

已解决解密数据时出现的异常: exception:javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher

 这里提供 CryptoJS-v3.1.2 的 Github链接

 先上后台Java代码: 

package com.company.pms.pmsbase.utils;
 
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.commons.codec.binary.Base64;
 
public class AesUtil {
 
 public static void main(String args[]) throws Exception {
 
  String content = "明文 123 abc";
 
  //加密
  String encrypted = encrypt(content, KEY, IV);
  //解密
  String decrypted = decrypt(encrypted, KEY, IV);
 
  System.out.println("加密前:" + content);
 
  System.out.println("加密后:" + encrypted);
 
  System.out.println("解密后:" + decrypted);
 }
 
 private static String KEY = "abcdef0123456789"; // 长度必须是 16
 
 private static String IV = "abcdef0123456789"; // 长度必须是 16
 
 /**
  * 加密返回的数据转换成 String 类型
  * @param content 明文
  * @param key 秘钥
  * @param iv 初始化向量是16位长度的字符串
  * @return
  * @throws Exception
  */
 public static String encrypt(String content, String key, String iv) throws Exception {
  // 将返回的加密过的 byte[] 转换成Base64编码字符串 !!!!很关键
  return base64ToString(AES_CBC_Encrypt(content.getBytes(), key.getBytes(), iv.getBytes()));
 }
 
 /**
  * 将解密返回的数据转换成 String 类型
  * @param content Base64编码的密文
  * @param key 秘钥
  * @param iv 初始化向量是16位长度的字符串
  * @return
  * @throws Exception
  */
 public static String decrypt(String content, String key, String iv) throws Exception {
  // stringToBase64() 将 Base64编码的字符串转换成 byte[] !!!与base64ToString()配套使用
  return new String(AES_CBC_Decrypt(stringToBase64(content), key.getBytes(), iv.getBytes()));
 }
 
 private static byte[] AES_CBC_Encrypt(byte[] content, byte[] keyBytes, byte[] iv){
  try {
   SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
   Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
   cipher.init(Cipher.ENCRYPT_MODE,key, new IvParameterSpec(iv));
   byte[] result = cipher.doFinal(content);
   return result;
  } catch (Exception e) {
   System.out.println("exception:"+e.toString());
  }
  return null;
 }
 
 private static byte[] AES_CBC_Decrypt(byte[] content, byte[] keyBytes, byte[] iv){
  try {
   SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
   Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
   cipher.init(Cipher.DECRYPT_MODE,key, new IvParameterSpec(iv));
   byte[] result = cipher.doFinal(content);
   return result;
  } catch (Exception e) {
   System.out.println("exception:"+e.toString());
  }
  return null;
 }
 
 /**
  * 字符串装换成 Base64
  */
 
 public static byte[] stringToBase64(String key) throws Exception {
  return Base64.decodeBase64(key.getBytes());
 }
 
 /**
  * Base64装换成字符串
  */
 public static String base64ToString(byte[] key) throws Exception {
  return new Base64().encodeToString(key);
 }
 
}

再上前端代码(需引用 rollups 目录下的 aes.js ):

function encodeAesString(data,key,iv){
 var key = CryptoJS.enc.Utf8.parse(key); 
 var iv = CryptoJS.enc.Utf8.parse(iv); 
 var encrypted =CryptoJS.AES.encrypt(data,key,{
 iv:iv, 
 mode:CryptoJS.mode.CBC,
 padding:CryptoJS.pad.Pkcs7 
 });
 //返回的是base64格式的密文 
 return encrypted;
}
 
// encrypted 为是base64格式的密文
function decodeAesString(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);
}
 
// 测试加、解密
function testAES(){
 var data = "明文 123 abc"; // 明文 
 var key = 'abcdef0123456789'; // 密钥 长度16
 var iv = 'abcdef0123456789'; // 密钥 长度16
 
 console.log("加密前:" + data);
 
 // 测试加密
 var encrypted = encodeAesString(data,key,iv); // 密文
 console.log("加密后: " + encrypted);
 
 var decryptedStr = decodeAesString(encrypted,key,iv);
 console.log("解密后: " + decryptedStr);
}

贴上效果图:

CryptoJS中AES实现前后端通用加解密技术

CryptoJS中AES实现前后端通用加解密技术

中间遇到的问题: 

    1.  秘钥问题, 秘钥的长度必须为16位, 否则会报错

    2. 加密得到的 byte[] 需用使用Base64转换成字符串, 不能直接转成字符串,因为加密所采用的AES, MD5, SHA-256, SHA-512 等等算法,它们是通过对byte[] 进行各种变换和运算,得到加密之后的byte[],那么这个加密之后的 byte[] 结果显然 就不会符合任何一种的编码方案,比如 UTF-8, GBK等,因为加密的过程是任意对byte[]进行运算的。所以你用任何一种编码方案来解码 加密之后的 byte[] 结果,得到的都会是乱码。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js兼容火狐获取图片宽和高的方法
May 21 Javascript
举例详解JavaScript中Promise的使用
Jun 24 Javascript
适用于javascript开发者的Processing.js入门教程
Feb 24 Javascript
sso跨域写cookie的一段js脚本(推荐)
May 25 Javascript
jQuery Dialog 打开时自动聚焦的解决方法(两种方法)
Nov 24 Javascript
详解js产生对象的3种基本方式(工厂模式,构造函数模式,原型模式)
Jan 09 Javascript
jQuery实现导航回弹效果
Feb 27 Javascript
详解webpack进阶之插件篇
Jul 06 Javascript
js构建二叉树进行数值数组的去重与优化详解
Mar 26 Javascript
移动端如何用下拉刷新的方式实现上拉加载
Dec 10 Javascript
JS中的算法与数据结构之链表(Linked-list)实例详解
Aug 20 Javascript
vue使用screenfull插件实现全屏功能
Sep 17 Javascript
antd组件Upload实现自己上传的实现示例
Dec 18 #Javascript
微信小程序解除10个请求并发限制
Dec 18 #Javascript
vue项目中axios请求网络接口封装的示例代码
Dec 18 #Javascript
vue中引入第三方字体文件的方法示例
Dec 17 #Javascript
vue 表单验证按钮事件交由父组件触发的方法
Dec 17 #Javascript
Vue 报错TypeError: this.$set is not a function 的解决方法
Dec 17 #Javascript
vuex 解决报错this.$store.commit is not a function的方法
Dec 17 #Javascript
You might like
dede全站URL静态化改造[070414更正]
2007/04/17 PHP
提高PHP编程效率的方法
2013/11/07 PHP
PHP实现数字补零功能的2个函数介绍
2014/05/12 PHP
PHP使用mysql与mysqli连接Mysql数据库用法示例
2016/07/07 PHP
Jquery之美中不足小结
2011/02/16 Javascript
jQuery 全选/反选以及单击行改变背景色实例
2013/07/02 Javascript
复选框全选与全不选操作实现思路
2013/08/18 Javascript
JavaScript SetInterval与setTimeout使用方法详解
2013/11/15 Javascript
通过jquery 获取URL参数并进行转码
2014/08/18 Javascript
javascript抽象工厂模式详细说明
2014/12/16 Javascript
原生js验证简洁注册登录页面
2016/12/17 Javascript
使用mint-ui实现省市区三级联动效果的示例代码
2018/02/09 Javascript
详解webpack打包第三方类库的正确姿势
2018/10/20 Javascript
小程序使用分包的示例代码
2020/03/23 Javascript
element中Steps步骤条和Tabs标签页关联的解决
2020/12/08 Javascript
vue el-upload上传文件的示例代码
2020/12/21 Vue.js
[57:24]LGD vs VGJ.T 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python读文件逐行处理的示例代码分享
2013/12/27 Python
MySQL中表的复制以及大型数据表的备份教程
2015/11/25 Python
Python实现读取txt文件并转换为excel的方法示例
2018/05/17 Python
python中的插值 scipy-interp的实现代码
2018/07/23 Python
python实现简单http服务器功能
2018/09/17 Python
详解Python中正则匹配TAB及空格的小技巧
2019/07/26 Python
django drf框架中的user验证以及JWT拓展的介绍
2019/08/12 Python
python 模拟创建seafile 目录操作示例
2019/09/26 Python
python模拟预测一下新型冠状病毒肺炎的数据
2020/02/01 Python
CSS3中Animation动画属性用法详解
2016/07/04 HTML / CSS
基于Html5实现的语音搜索功能
2019/05/13 HTML / CSS
Rossignol金鸡美国官网:始于1907年法国百年雪具品牌
2019/03/06 全球购物
加拿大在线隐形眼镜和眼镜店:VisionPros
2019/10/06 全球购物
经典c++面试题二
2015/08/14 面试题
心理健康教育制度
2014/01/27 职场文书
临时用工协议书范本
2014/10/29 职场文书
卫生主题班会
2015/08/14 职场文书
安全生产标语口号
2015/12/26 职场文书
详解MySQL 用户权限管理
2021/04/20 MySQL