我有一个使用 256 位 AES 加密的应用程序,Java 不支持该加密。我知道为了让它正常工作,我在安全文件夹中安装了 JCE 无限强度 jar。这对我作为开发人员来说很好,我可以安装它们。
我的问题是,由于此应用程序将被分发,最终用户很可能不会安装这些策略文件。让最终用户下载这些只是为了使应用程序发挥作用并不是一个有吸引力的解决方案。
有没有办法让我的应用程序运行而不覆盖最终用户计算机上的文件?第三方软件可以在不安装策略文件的情况下处理它吗?或者只是从 JAR 中引用这些策略文件的方法?
对于这个问题,有一些常见的解决方案。不幸的是,这些都不能完全令人满意:
-
安装无限强度策略文件 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html.虽然这可能是适合您的开发工作站的正确解决方案,但让非技术用户在每台计算机上安装文件很快就会成为一个主要麻烦(如果不是障碍)。有no way与您的程序一起分发文件;它们必须安装在 JRE 目录中(由于权限的原因,该目录甚至可能是只读的)。
-
跳过 JCE API并使用另一个密码学库,例如充气城堡 http://www.bouncycastle.org/。这种方法需要额外的 1MB 库,根据应用程序的不同,这可能是一个很大的负担。复制标准库中包含的功能也感觉很愚蠢。显然,该API也与通常的JCE接口完全不同。 (BC 确实实现了 JCE 提供程序,但这没有帮助,因为应用了密钥强度限制before移交给实现。)此解决方案也不允许您使用 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()
在执行任何加密操作之前从静态初始化程序等中获取。
The JceSecurity.isRestricted = false
部分是直接使用 256 位密码所需的全部;然而,如果没有其他两项操作,Cipher.getMaxAllowedKeyLength()
仍将继续报告 128,并且 256 位 TLS 密码套件将不起作用。
此代码适用于 Oracle Java 7 和 8,并在 Java 9 和 OpenJDK 上自动跳过不需要的进程。毕竟,这是一个丑陋的黑客行为,它可能无法在其他供应商的虚拟机上运行。
它也不适用于 Oracle Java 6,因为私有 JCE 类在那里被混淆了。不过,混淆不会因版本而异,因此技术上仍然可以支持 Java 6。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)