今天在调用获取微信支付平台证书V3接口时,需要对其内容进行解密。根据官方的demo如下:

static final int KEY_LENGTH_BYTE = 32;
	static final int TAG_LENGTH_BIT = 128;

	public String decryptToString(byte[] apiV3Key, byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {

		if (apiV3Key.length != KEY_LENGTH_BYTE) {
			throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
		}

		try {
			Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

			SecretKeySpec key = new SecretKeySpec(apiV3Key, "AES");
			GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);

			cipher.init(Cipher.DECRYPT_MODE, key, spec);
			cipher.updateAAD(associatedData);

			return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
		} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
			throw new IllegalStateException(e);
		} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
			throw new IllegalArgumentException(e);
		}
	}

发现执行到 cipher.init(Cipher.DECRYPT_MODE, key, spec); 的时候报 java.security.InvalidKeyException: Illegal key size 错误。

经过资料查阅,得出原因如下:

JDK受版本安全限制,默认只允许128位长度以内的。秘钥长度,如果密钥大于128, 会抛出java.security.InvalidKeyException: Illegal key size 异常. java运行时环境默认读到的是受限的policy文件. 文件位于${java_home}/jre/lib/security, 这种限制是因为美国对软件出口的控制所造成的的.JDK1.8之后已经兼容了该问题。

解决方案:

方法一:升级不受限制JDK版本
升级JDK9级以上版本,未测试

方法二:替换JDK受限文件级配置
JDK7的下载地址: Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7 Download
JDK8的下载地址: JCE Unlimited Strength Jurisdiction Policy Files for JDK/JRE 8 Download
下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件
如果安装了JDK,还要将两个jar文件也放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件

方法三:JDK1.8 代码策略修改
JDK1.8 已经支持不受限的jar,但配置默认是受限的
修改代码配置,在加密之前,修改不受限配置.

WXBizMsgCrypt wxcpt = createWXBizMsgCrypt(suiteId, getCorpId(postData), false);
Security.setProperty("crypto.policy", "unlimited");
sMsg = wxcpt.decryptMsg(msgSignature, timestamp, nonce, postData);