有两个通常引用的解决方案。不幸的是,这些都不是完全令人满意的:
- 安装无限强度策略文件。虽然这可能是适合您的开发工作站的解决方案,但要让非技术用户在每台计算机上安装文件,很快就会成为一个主要麻烦(如果不是障碍)。有没有办法来分发与您的程序文件; 它们必须安装在JRE目录中(由于权限的缘故,它甚至可能是只读的)。
- 跳过JCE API并使用另一个加密库,例如Bouncy Castle。这种方法需要额外的1MB库,根据应用程序的不同,这可能是一个很大的负担。复制标准库中包含的功能也很愚蠢。显然,该API也与通常的JCE接口完全不同。(BC确实实现了JCE提供程序,但这无济于事,因为在移交给实现之前已应用了密钥强度限制。)该解决方案也不允许您使用256位TLS(SSL)密码套件,因为标准TLS库在内部调用JCE以确定任何限制。
但是,有反思。使用反射您无法做任何事情吗?
private static void removeCryptographyRestrictions() {
if (!isRestrictedCryptography()) {
logger.fine("Cryptography restrictions removal not needed");
return;
}
try {
/*
* Do the following, but with reflection to bypass access checks:
*
* JceSecurity.isRestricted = false;
* JceSecurity.defaultPolicy.perms.clear();
* JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
*/
final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
isRestrictedField.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
isRestrictedField.set(null, false);
final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
defaultPolicyField.setAccessible(true);
final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
final Field perms = cryptoPermissions.getDeclaredField("perms");
perms.setAccessible(true);
((Map<?, ?>) perms.get(defaultPolicy)).clear();
final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
instance.setAccessible(true);
defaultPolicy.add((Permission) instance.get(null));
logger.fine("Successfully removed cryptography restrictions");
} catch (final Exception e) {
logger.log(Level.WARNING, "Failed to remove cryptography restrictions", e);
}
}
private static boolean isRestrictedCryptography() {
// This matches Oracle Java 7 and 8, but not Java 9 or OpenJDK.
final String name = System.getProperty("java.runtime.name");
final String ver = System.getProperty("java.version");
return name != null && name.equals("Java(TM) SE Runtime Environment")
&& ver != null && (ver.startsWith("1.7") || ver.startsWith("1.8"));
}
removeCryptographyRestrictions()
在执行任何加密操作之前,只需从静态初始化程序等调用即可。
这JceSecurity.isRestricted = false
就是直接使用256位密码所需的全部内容。但是,如果没有其他两项操作,Cipher.getMaxAllowedKeyLength()
仍将继续报告128个,并且256位TLS密码套件将不起作用。
该代码可在Oracle Java 7和8上运行,并在不需要的Java 9和OpenJDK上自动跳过该过程。毕竟是一个丑陋的骇客,它可能无法在其他供应商的VM上运行。
它在Oracle Java 6上也不起作用,因为私有的JCE类在那里被混淆了。尽管混淆不会随版本的变化而变化,所以从技术上讲,仍然可以支持Java 6。