讲述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;
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) { String key = "14e83f9f55a142du"; String vi = "ATRe9SJd6lR5JcCb"; String content = "测试内容"; String encode = encode(key, vi, content); System.out.println(encode); }
}
|
运行结果

第三步:编写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;
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) { String key = "14e83f9f55a142ducc85fdb27b7b06qg"; String vi = "ATRe9SJd6lR5JcCb"; String content = "测试内容"; String encode = encode(key, vi, content); System.out.println(encode); }
}
|
运行结果

四、解决方案
一、通过反射修改为不校验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;
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) { String key = "14e83f9f55a142ducc85fdb27b7b06qg"; String vi = "ATRe9SJd6lR5JcCb"; String content = "测试内容"; String encode = encode(key, vi, content); System.out.println(encode); }
}
|
运行结果

二、使用第三方库计算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;
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) { String key = "14e83f9f55a142ducc85fdb27b7b06qg"; String vi = "ATRe9SJd6lR5JcCb"; String content = "测试内容"; String encode = encode(key, vi, content); System.out.println(encode); }
}
|
运行结果

三、截取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没有问题