Java、JS版AES加密算法工具类

[TOC]
本文主要是实现AES算法的Java版本和Javascript版本,并提供测试例子。
AES是一个对称分组密码算法,旨在取代DES成为广泛使用的标准。根据使用的密码长度,AES最常见的有3种方案,用以适应不同的场景要求,分别是AES-128、AES-192和AES-256。
Java中的PKCS5Padding和Javascript中的PKCS7Padding的结果是一样。

Java 版 AES 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package cn.tisson.wechat.common.util;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
* AES 加密、解密
*
* @author Created by YL on 2018/2/9
*/
public enum AESUtils {
GBK {
public String getCharset() {
return "GBK";
}
},

UTF8 {
public String getCharset() {
return "UTF-8";
}
};
public static final String AES_KEY = "MHYKD5tes6fhkdv9";

/**
* 获取编码
*/
public String getCharset() {
throw new AbstractMethodError();
}

/**
* 加密
*
* @param str 需要加密的内容
* @param key 加密密码
*
* @return 加密后的字符串
*/
private byte[] enc(String str, String key) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(getCharset()), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
return cipher.doFinal(str.getBytes(getCharset()));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("不支持的编码格式", e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("不支持的加密算法", e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException("不支持的填充机制", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("无效的Key、错误的长度、未初始化等", e);
} catch (IllegalBlockSizeException e) {
throw new RuntimeException("密码的块大小不匹配", e);
} catch (BadPaddingException e) {
throw new RuntimeException("输入的数据错误,导致填充机制未能正常填充", e);
}
}

private byte[] dec(byte[] str, String key) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(getCharset()), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
return cipher.doFinal(str);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("不支持的编码格式", e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("不支持的加密算法", e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException("不支持的填充机制", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("无效的Key、错误的长度、未初始化等", e);
} catch (IllegalBlockSizeException e) {
throw new RuntimeException("密码的块大小不匹配", e);
} catch (BadPaddingException e) {
throw new RuntimeException("输入的数据错误,导致填充机制未能正常填充", e);
}
}

/**
* AES 加密,使用默认 key 加密
*
* @param str 要加密的明文
*
* @return 加密后的密文
*/
public String encrypt(String str) {
return encrypt(str, AESUtils.AES_KEY);
}

/**
* AES加密,使用指定 key 加密
*
* @param str 要加密的明文
* @param key 加密 key
*
* @return 解密后字符串
*/
public String encrypt(String str, String key) {
byte[] encryptBytes = enc(str, key);
return Base64Utils.UTF8.encode(encryptBytes);
}

/**
* AES 解密,使用默认 key 解密
*
* @param str 要解密的密文
*
* @return 解密后的明文
*/
public String decrypt(String str) {
return decrypt(str, AESUtils.AES_KEY);
}

/**
* AES 解密,使用默认 key 解密
*
* @param str 要解密的密文
* @param key 解密 key
*
* @return 解密后的明文
*/
public String decrypt(String str, String key) {
if (str == null || "".equals(str)) {
return "";
}
byte[] bytes = Base64Utils.UTF8.decode2byte(str);
try {
return new String(dec(bytes, key), getCharset());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "";
}
}

Java 版 AES 工具类测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package cn.tisson.wechat.common.util;

import org.junit.Assert;
import org.junit.Test;

/**
* @author Created by YL on 2018/2/13
*/
public class AESUtilsTest {
private static final String KEY = "SYhU9Qf3nmrZAx7D";
private static final String STR = "法拉利_24234slfkjsl《》?:“”{}+——";

@Test
public void aes() {
String encrypt = AESUtils.UTF8.encrypt(STR, KEY);
System.out.println("encrypt ---> " + encrypt);
String decrypt = AESUtils.UTF8.decrypt(encrypt, KEY);
System.out.println(decrypt);
Assert.assertEquals(STR, decrypt);
}
}

JS 版 AES 工具类

要引入的 js 文件
地址:https://github.com/brix/crypto-js

1
2
3
4
5
<script th:src="@{/crypto-js/core.js}"></script>
<script th:src="@{/crypto-js/enc-base64.js}"></script>
<script th:src="@{/crypto-js/cipher-core.js}"></script>
<script th:src="@{/crypto-js/aes.js}"></script>
<script th:src="@{/crypto-js/mode-ecb.js}"></script>

JS 版 AES 工具类扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function getRandom(len) {
var a = len || 16,
s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
n = s.length;
var r = '';
for (var i = 0; i < a; i++) {
r += s.charAt(Math.floor(Math.random() * n));
}
return r;
}

function encryptAES(str, key) {
var s = CryptoJS.enc.Utf8.parse(str),
k = CryptoJS.enc.Utf8.parse(key),
c = CryptoJS.AES.encrypt(s, k, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}),
// 转换为字符串
// return c.toString();
// Hex 转为十六进制
d = CryptoJS.enc.Hex.parse(c.ciphertext.toString());
// Base64 编码
return CryptoJS.enc.Base64.stringify(d);
}

function decryptAES(str, key) {
var k = CryptoJS.enc.Utf8.parse(key),
c = CryptoJS.AES.decrypt(str, k, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
// 转换为 UTF8 字符串
return CryptoJS.enc.Utf8.stringify(c);
// return c.toString(CryptoJS.enc.Utf8);
}

JS 版 AES 工具类测试

1
2
3
4
5
6
7
8
var key = getRandom();
console.log('key: %o', key);
var str = '法拉利_24234slfkjsl《》?:“”{}+——';
console.log('str: %o', str);
var e = encryptAES(str, key);
console.log('e: %o', e);
var d = decryptAES(e, key);
console.log('d: %o', d);
  • 本文作者: forever杨
  • 本文链接: https://blog.yl-online.top/posts/1f7e0ef5.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。如果文章内容对你有用,请记录到你的笔记中。本博客站点随时会停止服务,请不要收藏、转载!