Java 的 AES 加密实现及问题解决

生成密钥

public static final String CIPHER_ALGORITHM_CBC = "AES/CBC/PKCS5Padding";
private final static String ENCRYPTKEY = "0123456789abcdefghijklmnopqretuvwxyz";

private static SecretKey secretKey = null;
private static void initKey() {
	try {
		secretKey = generateKey(ENCRYPTKEY.getBytes());
	} catch (Exception e) {
		e.printStackTrace();
	}
}

private static SecretKey generateKey(byte[] secretKey) throws Exception {
	SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
	secureRandom.setSeed(secretKey);
	KeyGenerator kg = null;
	try {
		kg = KeyGenerator.getInstance("AES");
		kg.init(256, secureRandom);
		SecretKey skey = kg.generateKey();
		byte[] raw = skey.getEncoded();
		SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
		return skeySpec;
	} catch (NoSuchAlgorithmException e) {
		logger.error(e.getMessage(), e);
		return null;
	}

}

加密实现

public static String encrypt(String input) throws Exception {
	if (secretKey == null) {
		initKey();
	}
	Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
	cipher.init(Cipher.ENCRYPT_MODE, secretKey);
	byte[] iv = cipher.getIV();
	byte[] encrypt = cipher.doFinal(input.getBytes("utf-8"));

	byte[] ret = new byte[iv.length + encrypt.length];
	System.arraycopy(encrypt, 0, ret, 0, encrypt.length);
	System.arraycopy(iv, 0, ret, encrypt.length, iv.length);
	return DatatypeConverter.printBase64Binary(ret);
}

解密实现

public static String decrypt(String input) throws Exception {
	if (secretKey == null) {
		initKey();
	}
	byte[] inputBytes = DatatypeConverter.parseBase64Binary(input);
	byte[] iv = new byte[16];
	byte[] cipherBytes = new byte[inputBytes.length - 16];
	System.arraycopy(inputBytes, 0, cipherBytes, 0, cipherBytes.length);
	System.arraycopy(inputBytes, cipherBytes.length, iv, 0, 16);

	Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
	cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
	byte[] decrypt = cipher.doFinal(cipherBytes);

	return new String(decrypt);
}

问题处理

问题描述

在使用 256 位加密时,控制台报错如下:

java.security.InvalidKeyException: Illegal key size or default parameters
        at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1026)
        at javax.crypto.Cipher.implInit(Cipher.java:801)
        at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
        at javax.crypto.Cipher.init(Cipher.java:1249)
        at javax.crypto.Cipher.init(Cipher.java:1186)

这是由于 key 的变更(由原来的 128 位变更为 256 位),导致加密 / 解密的失败。

之所以会出现这种问题,我们就要了解一个新的东西 ——JCE。在 Java 的核心类库中有一个 JCE(Java Cryptography Extension),JCE 是一组包,它们提供用于加密、密钥生成和协商以及 Message Authentication Code(MAC)算法的框架和实现,所以这个是实现加密解密的重要类库。

问题解决

我们要做的就是更换 JCE 的库,该文件位置在你的 JDK/jre/lib/security 目录下面,该目录下我们可以看到两个 jar 包:local_policy.jar,US_export_policy.jar,这两个 jar 包是 jdk 自带的。我们需要下载支持 256 位密钥加密的 jar 包。

  • JDK8:
    其对应的 JCE 下载地址
  • JDK7:
    其对应的 JCE 下载地址
  • JDK6:
    其对应的 JCE 下载地址

下载完后,解压,将其中的 “local_policy.jar” 和 “US_export_policy.jar” 两个文件替换掉自己 % JAVE_HOME%\jre\lib\security 文件夹下对应的原文件(% JAVE_HOME% 是自己电脑的 Java 路径)。

JDK1.8 以上的该目录下压根没有这两个 JAR 包。

针对这种情况,我们的解决方式为:vim 命令打开 java.security 文件,将注释掉的如下配置打开,然后保存即可。

#crypto.policy=unlimited