前后端配合使用AES/CBC/PKCS7Padding 实现加解密数据(crypto-js、bouncycastle-java)
简述
- 如题,最近项目需要选择一套对称加密算法,来满足前后端之间的加解密操作。
- 初步打算前端使用crypto-js来实现,后端使用java本身的加密算法实现
- 但,遇到了一个问题:java本身只支持NoPadding和PKCS5Padding,如下图:
- 而crypto-js提供的padding包括如下图,没有PKCS5Padding,所以不得以,前后端最终使用PKCS7Padding来实现功能
前端
- npm i crypto-js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script type="text/javascript" src="node_modules/crypto-js/crypto-js.js"></script>
</head>
<body>
<script type="text/javascript">
// 偏移量
let iv = "0000000000000000";
// 加密内容
let message = "abcd中文测试加标点符号!@#¥%……&*(+——)(*&~,。,;,,/;lkk;ki;'[p]./,'\\467646789";
// 密钥,长度必须为16
let secret_key = "1234567890123456";
// utf-8 转换
message = CryptoJS.enc.Utf8.parse(message);
secret_key = CryptoJS.enc.Utf8.parse(secret_key);
iv = CryptoJS.enc.Utf8.parse(iv);
// Encrypt
var ciphertext = CryptoJS.AES.encrypt(message, secret_key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(ciphertext.toString());
// Decrypt
var bytes = CryptoJS.AES.decrypt(ciphertext.toString(), secret_key,{
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(bytes.toString(CryptoJS.enc.Utf8));
</script>
</body>
</html>
- 运行结果:
java
package com.sgcc.atc.importUser.Utils.encrypted;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class AESpkcs7paddingUtil {
/**
* 密钥算法
*/
private static final String KEY_ALGORITHM = "AES";
/**
* 加密/解密算法 / 工作模式 / 填充方式
* Java 6支持PKCS5Padding填充方式
* Bouncy Castle支持PKCS7Padding填充方式
*/
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
/**
* 偏移量,只有CBC模式才需要
*/
private final static String ivParameter = "0000000000000000";
/**
* AES要求密钥长度为128位或192位或256位,java默认限制AES密钥长度最多128位
*/
public static String sKey="" ;
/**
* 编码格式
*/
public static final String ENCODING = "utf-8";
static {
//如果是PKCS7Padding填充方式,则必须加上下面这行
Security.addProvider(new BouncyCastleProvider());
}
/**
* AES加密
* @param source 源字符串
* @param key 密钥
* @return 加密后的密文
* @throws Exception
*/
public static String encrypt(String source, String key) throws Exception {
byte[] sourceBytes = source.getBytes(ENCODING);
byte[] keyBytes = key.getBytes(ENCODING);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(ENCODING));
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM),iv);
byte[] decrypted = cipher.doFinal(sourceBytes);
return Base64.encodeBase64String(decrypted);
}
/**
* AES解密
* @param encryptStr 加密后的密文
* @param key 密钥
* @return 源字符串
* @throws Exception
*/
public static String decrypt(String encryptStr, String key) throws Exception {
byte[] sourceBytes = Base64.decodeBase64(encryptStr);
byte[] keyBytes = key.getBytes(ENCODING);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(ENCODING));
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM),iv);
byte[] decoded = cipher.doFinal(sourceBytes);
return new String(decoded, ENCODING);
}
public static void main(String[] args) throws Exception {
String key = "1234567890123456";
// 加密
long lStart = System.currentTimeMillis();
String enString = AESpkcs7paddingUtil.encrypt("abcd中文测试加标点符号!@#¥%……&*(+——)(*&~,。,;,,/;lkk;ki;'[p]./,'\\467646789",key);
System.out.println("加密后的字串是:" + enString);
long lUseTime = System.currentTimeMillis() - lStart;
System.out.println("加密耗时:" + lUseTime + "毫秒");
// 解密
lStart = System.currentTimeMillis();
String DeString = AESpkcs7paddingUtil.decrypt(enString,key);
System.out.println("解密后的字串是:" + DeString);
lUseTime = System.currentTimeMillis() - lStart;
System.out.println("解密耗时:" + lUseTime + "毫秒");
}
}
- 运行结果
** 注意**,因为使用了BouncyCastleProvider和base64的方法,需要引入以下两个jar包
最后
- 上网查pkcs7 pkcs5区别的时候,发现网上说二者区别不太大,主要就是填充的块的大小不一致,所以java端尝试使用了PKCS5Padding来实现相同的功能,发现还真的可以。不过为了规避风险,最终项目还是选择了上述方案。
- 如果你想降低加密算法难度,提高加解密速度,可以把模式修改成ECB,然后注释掉偏移量即可。
参考
https://www.cnblogs.com/chen-lhx/p/6233954.html
https://www.npmjs.com/package/crypto-js
https://blog.csdn.net/test1280/article/details/75268255
https://blog.csdn.net/sunqiujing/article/details/75065218
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构