aes加解密javascript与java语言互通

不同语言同一种加解密算法都有不同配置,可导致的问题:javascript加密之后后端java无法解密,或者java加密之后javascript无法解密。

本篇文章介绍 aes 加解密算法前端javascript与后端java完全互通如何配置参数。

前端javascript

前端依赖crypto.js

使用方法:

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
const CryptoJS = require('./crypto-js.min')
const KEY = 'ABCDEFGHIJKLMN' // 默认的加密KEY

// aes 加密
function aesEncrypt(data, key = KEY) {
key = CryptoJS.enc.Utf8.parse(key)
const encryptedData = CryptoJS.AES.encrypt(data, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return encryptedData.toString()
}

// aes 解密
function aesDecrypt(data, key = KEY) {
key = CryptoJS.enc.Utf8.parse(key)
const decryptedData = CryptoJS.AES.decrypt(data, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return decryptedData.toString(CryptoJS.enc.Utf8)
}


// 使用秘钥 ABCDEFGHIJKLMN 加密 test content
console.log(aesEncrypt('test content', KEY))

module.exports = {
aesEncrypt,
aesDecrypt,
};

此处的 crypto-js.mincrypto.js 离线下载版本,原因是在一个简单的小程序中使用,未用 npm 安装依赖,直接下载的 min 文件。

服务端java

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
package cn.migu.music.util;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;

/**
* AES加、解密算法工具类
*
* @author kyle
*/
public class AesUtil {
/**
* 加密算法AES
*/
private static final String KEY_ALGORITHM = "AES";

/**
* key的长度,Wrong key size: must be equal to 128, 192 or 256
* 传入时需要16、24、36
*/
private static final Integer KEY_LENGTH = 16 * 8;

/**
* 算法名称/加密模式/数据填充方式
* 默认:AES/ECB/PKCS5Padding
*/
private static final String ALGORITHMS = "AES/ECB/PKCS5Padding";

/**
* 后端AES的key,由静态代码块赋值
*/
public static String key;

private static Cipher cipher;

static {
key = getKey();
try {
cipher = Cipher.getInstance(ALGORITHMS, new BouncyCastleProvider());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
}

/**
* 获取key
*/
public static String getKey() {
StringBuilder uid = new StringBuilder();
//产生16位的强随机数
Random rd = new SecureRandom();
for (int i = 0; i < KEY_LENGTH / 8; i++) {
//产生0-2的3位随机数
int type = rd.nextInt(3);
switch (type) {
case 0:
//0-9的随机数
uid.append(rd.nextInt(10));
break;
case 1:
//ASCII在65-90之间为大写,获取大写随机
uid.append((char) (rd.nextInt(25) + 65));
break;
case 2:
//ASCII在97-122之间为小写,获取小写随机
uid.append((char) (rd.nextInt(25) + 97));
break;
default:
break;
}
}
return uid.toString();
}

/**
* 加密
*
* @param content 加密的字符串
* @param encryptKey key值
*/
public static String encrypt(String content, String encryptKey) throws Exception {
//设置Cipher对象
if(cipher == null){
cipher = Cipher.getInstance(ALGORITHMS, new BouncyCastleProvider());
}
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), KEY_ALGORITHM));

//调用doFinal
byte[] b = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));

// 转base64
return Base64.encodeBase64String(b);

}

/**
* 解密
*
* @param encryptStr 解密的字符串
* @param decryptKey 解密的key值
*/
public static String decrypt(String encryptStr, String decryptKey) throws Exception {
//base64格式的key字符串转byte
byte[] decodeBase64 = Base64.decodeBase64(encryptStr);

//设置Cipher对象
if(cipher == null){
cipher = Cipher.getInstance(ALGORITHMS, new BouncyCastleProvider());
}
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), KEY_ALGORITHM));

//调用doFinal解密
byte[] decryptBytes = cipher.doFinal(decodeBase64);
return new String(decryptBytes);
}

// 使用秘钥 ABCDEFGHIJKLMN 加密 test content
public static void main(String[] args) throws Exception {
String content = "test content";
String key = "ABCDEFGHIJKLMN";
System.out.println(encrypt(content,key));
}
}

以上两种语言的互通加解密已在项目中验证使用,长短字符串的加解密都无问题。

本文由 linx(544819896@qq.com) 创作,采用 CC BY 4.0 CN协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。本文链接为: https://blog.jijian.link/2023-03-10/aes-javascript-java/

如果您觉得文章不错,可以请我喝一杯咖啡!