视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
CryptoJS中AES实现前后端通用加解密技术
2020-11-27 22:02:28 责编:小采
文档

在项目中如果要对前后端传输的数据双向加密, 比如避免使用明文传输用户名,密码等数据。 就需要对前后端数据用同种方法进行加密,方便解密。这里介绍使用 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.Base;
 
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 = "abcdef01234567"; // 长度必须是 16
 
 private static String IV = "abcdef01234567"; // 长度必须是 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[] 转换成Base编码字符串 !!!!很关键
 return baseToString(AES_CBC_Encrypt(content.getBytes(), key.getBytes(), iv.getBytes()));
 }
 
 /**
 * 将解密返回的数据转换成 String 类型
 * @param content Base编码的密文
 * @param key 秘钥
 * @param iv 初始化向量是16位长度的字符串
 * @return
 * @throws Exception
 */
 public static String decrypt(String content, String key, String iv) throws Exception {
 // stringToBase() 将 Base编码的字符串转换成 byte[] !!!与baseToString()配套使用
 return new String(AES_CBC_Decrypt(stringToBase(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;
 }
 
 /**
 * 字符串装换成 Base
 */
 
 public static byte[] stringToBase(String key) throws Exception {
 return Base.decodeBase(key.getBytes());
 }
 
 /**
 * Base装换成字符串
 */
 public static String baseToString(byte[] key) throws Exception {
 return new Base().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 
 });
 //返回的是base格式的密文 
 return encrypted;
}
 
// encrypted 为是base格式的密文
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 = 'abcdef01234567'; // 密钥 长度16
 var iv = 'abcdef01234567'; // 密钥 长度16
 
 console.log("加密前:" + data);
 
 // 测试加密
 var encrypted = encodeAesString(data,key,iv); // 密文
 console.log("加密后: " + encrypted);
 
 var decryptedStr = decodeAesString(encrypted,key,iv);
 console.log("解密后: " + decryptedStr);
}

贴上效果图:

中间遇到的问题: 

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

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

下载本文
显示全文
专题