博客的文章详情页面传递参数是使用AES加密过得,如下图所示:
这个AES加密是通用的加密方式,使用同一套算法,前端和后端都可以对加密之后的字符串进行加密解密操作。
目前线上正在使用的是前端javascript进行加密操作,将加密之后的字符串再传递到后端,PHP再进行解密操作。
现在我们将后端换成了SpringBoot,就需要使用java来实现后端解密操作。
一:javascript使用AES加密解密
需要引入加密文件库
https://s3.pstatp.com/cdn/expire-1-M/crypto-js/3.1.9/crypto-js.min.js
加密解密方法如下所示:
/**
* @name:crypto-js 加密
* @author: camellia
* @email: [email protected]
* @date: 2021-01-22
*/
export function encryptCode(param)
{
var text = JSON.stringify(param);
var key = CryptoJS.enc.Latin1.parse(‘1234567890789456’); //为了避免补位,直接用16位的秘钥
var iv = CryptoJS.enc.Latin1.parse(‘1234567890789456’); //16位初始向量
var encrypted = CryptoJS.AES.encrypt(text, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
}).toString();
return encrypted;
}
/**
* @name:crypto-js 解密
* @author: camellia
* @email: [email protected]
* @date: 2021-01-22
*/
export function decryptCode(param)
{
var key = CryptoJS.enc.Latin1.parse(‘1234567890789456’); //为了避免补位,直接用16位的秘钥
var iv = CryptoJS.enc.Latin1.parse(‘1234567890789456’); //16位初始向量
const decrypt = CryptoJS.AES.decrypt(param, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
}).toString(CryptoJS.enc.Utf8);
return decrypt;
}
通过观察上方代码,我们可以发现,我使用的是AES-128算法加密,加解密模式为CBC,ZeroPadding是填充方法。
我的key和iv都是标准的16位,理论上来说,这个填充模式直接选择NoPadding就可以了,因为我不需要补位。
二:java使用AES加密解密
protected String key = "1234567890789456";
protected String iv = "1234567890789456";
/**
* @Description AES算法加密明文
* @param data 明文
* @param key 密钥,长度16
* @param iv 偏移量,长度16
* @return 密文
*/
public String encryptAES(String data,String key,String iv) throws Exception
{
try
{
// Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
// Cipher cipher = Cipher.getInstance("AES/CBC/ZeroPadding"); java中没有实现这个方法
// 声明加密算法 / 加密方式 / 填充方式
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes();
int plaintextLength = dataBytes.length;
if (plaintextLength % blockSize != 0)
{
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); // CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return encode(encrypted).trim(); // BASE64做转码。
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
/**
* @Description AES算法解密密文
* @param data 密文
* @param key 密钥,长度16
* @param iv 偏移量,长度16
* @return 明文
*/
public String decryptAES(String data,String key,String iv) throws Exception
{
try
{
byte[] encrypted1 = decode(data);//先用base64解密
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original,"UTF-8");
return originalString.trim();
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
/**
* 编码
* @param byteArray
* @return
*/
public String encode(byte[] byteArray)
{
return new String(new Base64().encode(byteArray));
}
/**
* 解码
* @param base64EncodedString
* @return
*/
public byte[] decode(String base64EncodedString)
{
return new Base64().decode(base64EncodedString);
}
这里注意一下,我使用的是java11,他是没有实现ZeroPadding这个填充方式的,但是,由于我的key和iv都是16位,不需要补位,因此我这里直接使用NoPadding即可。如果我的上述条件您不满足,可能您就需要换一个填充方式了。
三:AES加密简单介绍
AES加密又分成AES-128、AES-196、AES-256,其中128、196、256是针对加解密密钥长度的要求,即128位(16字节),196位(24字节),256位(32字节);
关于加解密模式和填充方式
针对待加解密明文、密文,长度有严格要求,即必须为16字节的整数倍(所以针对不同长度的数据,需要对齐,不够16位的需要填充数据,由此产生了不同的填充方式)。整个加解密的过程是对所有分割成16个字节长度的数据块进行循环加解密,最后合并起来形成最终结果集(加解密过程的不同产生了不同的加解密模式)。
常见加密模式:
常见填充方式:
以上大概就是java中AES加密和解密的使用。
有好的建议,请在下方输入你的评论。