Java语言AES加密报错-Illegal key size

讲述Java 语言中使用 AES-256 位加密时遇到的”Illegal key size”错误及其解决方案

一、背景

在使用JDK版本为1.8.0_77时,使用JDK自带的AES加密,能支持128位的key,使用256位的key加密会报错“Illegal key size”

二、环境

JDK 1.8.0_77

Oracle下载列表

JDK_8u77_win下载地址

三、问题重现

第一步:将JDK环境配置为1.8.0_77

第二步:编写key为128位的异常测试用例,运行查看结果

示例代码

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
package com.live;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* @author: sadboy
**/
public class Test {

private static Base64.Encoder base64Encoder = Base64.getEncoder();

public static String encode(String key, String vi, String content) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(1, secretKey, new IvParameterSpec(vi.getBytes()));
byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);
byte[] byteAES = cipher.doFinal(byteEncode);
return base64Encoder.encodeToString(byteAES);
} catch (Exception var7) {
var7.printStackTrace();
return null;
}
}

public static void main(String[] args) {
//key长度为16位,16*8=128(bit)
String key = "14e83f9f55a142du";
String vi = "ATRe9SJd6lR5JcCb";
String content = "测试内容";
String encode = encode(key, vi, content);
System.out.println(encode);
}

}

运行结果

img.png

第三步:编写key为256位的异常测试用例,运行查看结果

示例代码

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
package com.live;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* @author: sadboy
**/
public class Test {

private static Base64.Encoder base64Encoder = Base64.getEncoder();

public static String encode(String key, String vi, String content) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(1, secretKey, new IvParameterSpec(vi.getBytes()));
byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);
byte[] byteAES = cipher.doFinal(byteEncode);
return base64Encoder.encodeToString(byteAES);
} catch (Exception var7) {
var7.printStackTrace();
return null;
}
}

public static void main(String[] args) {
//key长度为32位,32*8=256(bit)
String key = "14e83f9f55a142ducc85fdb27b7b06qg";
String vi = "ATRe9SJd6lR5JcCb";
String content = "测试内容";
String encode = encode(key, vi, content);
System.out.println(encode);
}

}

运行结果

img.png

四、解决方案

一、通过反射修改为不校验key的长度

方案地址

示例代码

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
package com.live;

import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* @author: sadboy
**/
public class Test {
static {
try {
Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
field.setAccessible(true);
field.set(null, java.lang.Boolean.FALSE);
} catch (Exception ex) {
}
}

private static Base64.Encoder base64Encoder = Base64.getEncoder();

public static String encode(String key, String vi, String content) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(1, secretKey, new IvParameterSpec(vi.getBytes()));
byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);
byte[] byteAES = cipher.doFinal(byteEncode);
return base64Encoder.encodeToString(byteAES);
} catch (Exception var7) {
var7.printStackTrace();
return null;
}
}

public static void main(String[] args) {
//key长度为32位,32*8=256(bit)
String key = "14e83f9f55a142ducc85fdb27b7b06qg";
String vi = "ATRe9SJd6lR5JcCb";
String content = "测试内容";
String encode = encode(key, vi, content);
System.out.println(encode);
}

}

运行结果

img.png

二、使用第三方库计算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
package com.live;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;

/**
* @author: sadboy
**/
public class Test {

private static Base64.Encoder base64Encoder = Base64.getEncoder();

public static String encode(String key, String iv, String content) {
byte[] keyB = key.getBytes();
byte[] ivB = iv.getBytes();
byte[] contentB = content.getBytes(StandardCharsets.UTF_8);
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(keyB), ivB);
aes.init(true, ivAndKey);
byte[] bytes = new byte[0];
try {
bytes = cipherData(aes, contentB);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return base64Encoder.encodeToString(bytes);
}

public static byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data) throws Exception {
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
return result;
}


public static void main(String[] args) {
//key长度为32位,32*8=256(bit)
String key = "14e83f9f55a142ducc85fdb27b7b06qg";
String vi = "ATRe9SJd6lR5JcCb";
String content = "测试内容";
String encode = encode(key, vi, content);
System.out.println(encode);
}

}

运行结果

img.png

三、截取key的长度,取前面32位作为key

四、引入jar包解决问题

下载地址(JDK8为例)

下载地址

解决方法

把里面的两个jar包:local_policy.jar 和 US_export_policy.jar 替换掉原来 Jdk 安装目录 $\Java\jre{6|7|8}\lib\security 下的两个jar包即可

五、升级JDK解决问题

JDK 版本在 1.8.0_161之后就没有这个问题了,默认是支持,升级到1.8.0_161及更高版本

实测:JDK版本1.8.0_261没有问题

Java语言AES加密报错-Illegal key size

https://blog.sadboy.cn/2022/10/25/2022-10-25-javaAES/

作者

sadboy

发布于

2022-10-25

更新于

2026-03-28

许可协议

评论