前端CryptoJS加密、后端解密代码实现参考
1、使用AES算法的CBC模式加密
1.1、前端加密代码实现参考
vue项目需要安装CryptoJS安装包,安装命令如下:
npm install crypto-js
在项目中引入CryptoJS
import CryptoJS from 'crypto-js'
参考代码如下:
<script>
// 此处key为16进制
let key = '385f33cb91484b04a177828829081ab7';
console.log('密钥:', key);
// key格式化处理
key = CryptoJS.enc.Utf8.parse(key)
// 偏移量长度为16位, 注:偏移量需要与后端定义好,保证一致
let iv = "37fa77f6a3b0462d";
iv = CryptoJS.enc.Utf8.parse("37fa77f6a3b0462d");
// 加密内容
const source = {
"username": "用户名",
"password": "密码",
"timestamp": new Date().getTime()
}
const content = JSON.stringify(source);
console.log('加密前:', source);
// 加密方法
const encryptedContent = CryptoJS.AES.encrypt(content, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
const encStr = encryptedContent.ciphertext.toString()
console.log("加密后:", encStr);
// 解密方法
const decryptedContent = CryptoJS.AES.decrypt(CryptoJS.format.Hex.parse(encStr), key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
console.log('解密:',CryptoJS.enc.Utf8.stringify(decryptedContent));
</script>
前端打印结果
说明:
1> CBC模式前、后端需要确定偏移量的值,并且保持一致,这样才能确保后端解密成功。
2> 前端CBC模式或者ECB模式下的填充方式 Pkcs7,对应后端AES算法模式中的 PKCS5Padding 填充方式
3> CryptoJS对应的API文档地址:https://cryptojs.gitbook.io/docs/#encoders
1.2、后端解密代码实现参考
后端代码实现需要引入的maven依赖如下:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
参考代码实现如下:
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* AES对称加密工具类
*
* @author 星空流年
*/
public class AesUtil {
/**
* 偏移量
*
* 说明:偏移量字符串必须是16位 当模式是CBC的时候必须设置偏移量
* 此处值与前端偏移量值保持一致
*/
private static String iv = "37fa77f6a3b0462d";
/**
* 加密算法
*/
private static String Algorithm = "AES";
/**
* 算法/模式/补码方式
*/
private static String AlgorithmProvider = "AES/CBC/PKCS5Padding";
/**
* 加密
*
* @param src 加密内容
* @param uniqueKey 加密key
* @return
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws InvalidAlgorithmParameterException
* @throws UnsupportedEncodingException
*/
public static String encrypt(String src, String uniqueKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, UnsupportedEncodingException {
byte[] key = uniqueKey.getBytes();
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8"));
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] cipherBytes = cipher.doFinal(src.getBytes("UTF-8"));
return byteToHexString(cipherBytes);
}
/**
* 解密
*
* @param enc 加密内容
* @param uniqueKey 唯一key
* @return
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws DecoderException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String decrypt(String enc, String uniqueKey) throws NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidAlgorithmParameterException, InvalidKeyException, DecoderException, BadPaddingException, IllegalBlockSizeException {
byte[] key = uniqueKey.getBytes();
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8"));
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] hexBytes = hexStringToBytes(enc);
byte[] plainBytes = cipher.doFinal(hexBytes);
return new String(plainBytes, "UTF-8");
}
/**
* 将byte数组转换为16进制字符串
*
* @param src
* @return
*/
private static String byteToHexString(byte[] src) {
return Hex.encodeHexString(src);
}
/**
* 将16进制字符串转换为byte数组
*
* @param hexString
* @return
*/
private static byte[] hexStringToBytes(String hexString) throws DecoderException {
return Hex.decodeHex(hexString);
}
/**
* AES加密、解密测试方法
*
* @param args
*/
public static void main(String[] args) {
try {
// 唯一key作为密钥
String uniqueKey = "385f33cb91484b04a177828829081ab7";
// 加密前数据,此处数据与前端数据一致(加密内容包含有时间戳),请注意查看前端加密前数据
String src = "{\"username\":\"用户名\",\"password\":\"密码\",\"timestamp\":1628218094188}";
System.out.println("密钥:" + uniqueKey);
System.out.println("原字符串:" + src);
// 加密
String encrypt = encrypt(src, uniqueKey);
System.out.println("加密:" + encrypt);
// 解密
String decrypt = decrypt(encrypt, uniqueKey);
System.out.println("解密:" + decrypt);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试结果
2、使用AES算法的ECB模式加密
前面也说到,AES的ECB和CBC模式下的填充方式 Pkcs7,对应后端AES算法模式中的 PKCS5Padding 填充方式,只不过CBC模式需要添加偏移量,而ECB模式则不需要,大体实现方式本质上没有太大差别。
2.1、前端加密代码实现参考
vue项目需要安装CryptoJS安装包,安装命令如下:
npm install crypto-js
在项目中引入CryptoJS
import CryptoJS from 'crypto-js'
参考代码如下:
<script>
// 此处key为16进制
let key = '385f33cb91484b04a177828829081ab7';
console.log('密钥:', key);
// key格式化处理
key = CryptoJS.enc.Utf8.parse(key)
// 加密内容
const source = {
"username": "用户名",
"password": "密码",
"timestamp": new Date().getTime()
}
const content = JSON.stringify(source);
console.log('加密前:', source);
// 加密方法
const encryptedContent = CryptoJS.AES.encrypt(content, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
const encStr = encryptedContent.ciphertext.toString()
console.log('加密后:', encStr);
// 解密方法
const decryptedContent = CryptoJS.AES.decrypt(CryptoJS.format.Hex.parse(encStr), key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
console.log('解密:',CryptoJS.enc.Utf8.stringify(decryptedContent));
</script>
前端打印结果
2.2、后端加密代码实现参考
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* AES对称加密工具类
*
* @author 星空流年
*/
public class AesUtil {
/**
* 加密算法
*/
private static String Algorithm = "AES";
/**
* 算法/模式/补码方式
*/
private static String AlgorithmProvider = "AES/ECB/PKCS5Padding";
/**
* 加密
*
* @param src 原内容
* @param uniqueKey 唯一key
* @return
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws DecoderException
*/
public static String encrypt(String src, String uniqueKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, DecoderException {
byte[] key = uniqueKey.getBytes();
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherBytes = cipher.doFinal(src.getBytes(StandardCharsets.UTF_8));
return byteToHexString(cipherBytes);
}
/**
* 解密
*
* @param enc 加密内容
* @param uniqueKey 唯一key
* @return
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws DecoderException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String decrypt(String enc, String uniqueKey) throws NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidAlgorithmParameterException, InvalidKeyException, DecoderException, BadPaddingException, IllegalBlockSizeException {
byte[] key = uniqueKey.getBytes();
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] hexBytes = hexStringToBytes(enc);
byte[] plainBytes = cipher.doFinal(hexBytes);
return new String(plainBytes, SystemConstants.UTF_8);
}
/**
* 将byte数组转换为16进制字符串
*
* @param src
* @return
*/
private static String byteToHexString(byte[] src) {
return Hex.encodeHexString(src);
}
/**
* 将16进制字符串转换为byte数组
*
* @param hexString
* @return
*/
private static byte[] hexStringToBytes(String hexString) throws DecoderException {
return Hex.decodeHex(hexString);
}
/**
* AES加密、解密测试方法
*
* @param args
*/
public static void main(String[] args) {
try {
// 唯一key作为密钥
String uniqueKey = "385f33cb91484b04a177828829081ab7";
// 加密前数据,此处数据与前端数据一致(加密内容包含有时间戳),请注意查看前端加密前数据
String src = "{\"username\":\"用户名\",\"password\":\"密码\",\"timestamp\":1628220492939}";
System.out.println("密钥:" + uniqueKey);
System.out.println("原字符串:" + src);
// 加密
String encrypt = encrypt(src, uniqueKey);
System.out.println("加密:" + encrypt);
// 解密
String decrypt = decrypt(encrypt, uniqueKey);
System.out.println("解密:" + decrypt);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试结果
参考内容:
1、https://blog.csdn.net/lsvtogergo/article/details/80804312
2、https://cryptojs.gitbook.io/docs/#encoders
3、https://www.cnblogs.com/hetutu-5238/p/10648116.html