简介
AES是一种对称加密方式,对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。
对称加密通常使用的是相对较小的密钥,一般小于256 bit。因为密钥越大,加密越强,但加密与解密的过程越慢。
加密标准
AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。密钥的长度不同,推荐加密轮数也不同,如下表所示:
AES | 密钥长度(32位比特字) | 分组长度(32位比特字) | 加密轮数 |
---|---|---|---|
AES-128 | 4 | 4 | 10 |
AES-192 | 6 | 4 | 12 |
AES-256 | 8 | 4 | 14 |
Java后端实现(128位)
导入依赖:
<!--AES加解密依赖-->
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
实现工具类:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class AesUtil {
//加密时调用方法,三个参数分别是:明文,密钥,向量,注意向量的长度只能是16byte,而且加密解密时必须使用一致的向量。
public static byte[] AES_CBC_Encrypt(byte[] content, byte[] keyBytes,
byte[] iv) {
try {
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
// PKCS7Padding是缺几个字节就补几个字节的0,而PKCS5Padding是缺几个字节就补充几个字节的几,好比缺6个字节,就补充6个字节的6
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;
}
//解密方法,三个参数:密文,密钥,向量
public 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类型的字符串转成byte类型
* @param key
* @return
* @throws Exception
*/
public static byte[] decryptBASE64(String key) throws Exception {
return Base64.decodeBase64(key.getBytes());
}
/**
* 将byte类型转变为base64类型的字符串
* @param key
* @return
* @throws Exception
*/
public static String encryptBASE64(byte[] key) throws Exception {
return new String(Base64.encodeBase64(key));
}
/**
* 字符串转二进制字符串
*
* @param str
*/
public String toBinary(String str) {
char[] strChar = str.toCharArray();
String result = "";
for (int i = 0; i < strChar.length; i++) {
result += Integer.toBinaryString(strChar[i]) + "";
}
return result;
}
/**
* 字符串转16进制字符串
* @param s
* @return
*/
public static String strTo16(String s) {
String str = "";
for (int i = 0; i < s.length(); i++) {
int ch = (int) s.charAt(i);
String s4 = Integer.toHexString(ch);
str = str + s4;
}
return str;
}
public static void main(String[] args) throws Exception {
//明文
String returnMessageContent = "矛盾综合体";
// 密钥,一定是16byte长度的 前后台需要一致
String key = "SHmfaQwNX6nzb3Ee";
// 向量,一定是16byte长度的 前后台需要一致
String iv = "SHmfaQwNX6nzb3Ee";
//注意第一个参数-明文转化为byte数组的时候,一定要指定是按照utf-8的格式进行转化的,不然对中文的加密就会出现加密后无法解密的情况。
//第三个参数-向量,一定是16byte长度的
byte[] encrypted = AesUtil.AES_CBC_Encrypt(returnMessageContent.getBytes("utf-8"), key.getBytes(), iv.getBytes());
//将加密后的密文转成base64格式的字符串
String secretWord = AesUtil.encryptBASE64(encrypted);
System.out.println(secretWord);
String chat_content = secretWord;
// 解密,获得消息明文
byte[] chat_contentming = AesUtil.AES_CBC_Decrypt(AesUtil.decryptBASE64(chat_content), key.getBytes(), iv.getBytes());
//将明文byte按照utf-8的形式转化为String字符串
String messageming = new String(chat_contentming, "utf-8");
System.out.println(messageming);
}
}
运行结果
GilLsEWESwtMFdyJ6P7rpg==
矛盾综合体
前端实现(JS)
导入依赖, 下载地址: https://github.com/sytelus/CryptoJS
依赖js的路径改成你自己的
<!--js AES需要引入的依赖-->
<script type="text/javascript" src="./CryptoJS-master/components/core.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/md5.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/evpkdf.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/enc-base64.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/cipher-core.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/mode-ecb.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/pad-nopadding.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/aes.js"></script>
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AES加解密</title>
</head>
<body>
<!--js AES需要引入的依赖-->
<script type="text/javascript" src="./CryptoJS-master/components/core.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/md5.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/evpkdf.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/enc-base64.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/cipher-core.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/mode-ecb.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/pad-nopadding.js"></script>
<script type="text/javascript" src="./CryptoJS-master/components/aes.js"></script>
<script type="text/javascript">
// 加密方法
function getAesString(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
});
return encrypted.toString(); // 返回的是base64格式的密文
}
// 解密方法
function getDAesString(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); // 返回明文
}
// 明文
var data = "矛盾综合体";
// 密钥,一定是16byte长度的 前后台需要一致
var key = 'SHmfaQwNX6nzb3Ee';
// 向量,一定是16byte长度的 前后台需要一致
var iv = 'SHmfaQwNX6nzb3Ee';
// 密文,生成的密文就是base64格式的
var encrypted = getAesString(data, key, iv);
console.log(encrypted);
//生成的decryptedStr已经被默认转为了utf-8类型的字符串
var decryptedStr = getDAesString(encrypted, key, iv);
console.log(decryptedStr);
</script>
</body>
</html>
部署运行, 打开浏览器控制台Console, 运行结果
GilLsEWESwtMFdyJ6P7rpg==
矛盾综合体
前后端密文和明文内容一致, 表明没有问题.
实践中遇到的问题
-
JDK自带jar包不支持256位AES加密,需要到官网上下载下面两个jar包替换下面目录中的文件【文件目录:JAVA_HOME/jre/lib/security】:local_policy 和 US_export_policy
-
JAVA中IV【初始化向量不可以为32位,否则异常java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long】
网友评论