部署应用程序时如何避免安装"Unlimited Strength"JCE策略文件?

167 java jce aes policyfiles

我有一个使用256位AES加密的应用程序,开箱即用的Java不支持.我知道要使其正常运行我在安全文件夹中安装JCE无限强度jar.这对我作为开发人员来说很好,我可以安装它们.

我的问题是,由于此应用程序将被分发,最终用户很可能不会安装这些策略文件.让最终用户下载这些只是为了使应用程序功能不是一个有吸引力的解决方案.

有没有办法让我的应用程序运行而不覆盖最终用户机器上的文件?可以在没有安装策略文件的情况下处理它的第三方软件?或者从JAR中引用这些策略文件的方法?

nto*_*rnl 173

这个问题有几个常见的引用解决方案.不幸的是,这些都不完全令人满意:

  • 安装无限强度策略文件.虽然这可能是您的开发工作站的正确解决方案,但非技术用户在每台计算机上安装文件很快成为一个主要的麻烦(如果不是障碍).有没有办法来分发与您的程序文件; 它们必须安装在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"));
}
Run Code Online (Sandbox Code Playgroud)

removeCryptographyRestrictions()在执行任何加密操作之前,只需从静态初始化程序中调用.

JceSecurity.isRestricted = false部分是直接使用256位密码所需的全部内容; 但是,如果没有其他两个操作,Cipher.getMaxAllowedKeyLength()仍将继续报告128,并且256位TLS密码套件将无法工作.

此代码适用于Oracle Java 7和8,并自动跳过Java 9和OpenJDK上不需要的过程.毕竟,作为一个丑陋的黑客,它可能不适用于其他供应商的虚拟机.

它也不适用于Oracle Java 6,因为私有JCE类在那里被混淆了.虽然混淆不会从版本变为版本,因此技术上仍然可以支持Java 6.

  • 反射解决方案可能违反[Java许可协议](http://www.oracle.com/technetwork/java/javase/terms/license/index.html):"F. JAVA技术限制.您可能不会......改变以任何方式标识为'java','javax','sun','oracle'或类似约定的......类,接口或子包的行为......" (23认同)
  • @ M.Dudley可能.在运送包含此代码的产品(如果它涉及到您)之前,请咨询律师. (14认同)
  • 似乎反射解决方案在1.8.0_112中停止工作.它工作在1.8.0_111,但不是112. (8认同)
  • @peabody在某些情况下,在您的程序中包含100MB JRE当然是一种选择.但如果没有,用户仍然必须手动安装策略文件,即使您将它们包含在您的程序中(由于各种原因,如文件权限).根据我的经验,许多用户无法做到这一点. (3认同)
  • @JohnL我在一个应用程序中使用它.在8u111中的'final`字段遇到问题之后,我修改了它以便它可以更改最后的字段,按照[answer](http://stackoverflow.com/a/3301720/6178459).结果与ntoskrnl的新版本大致相同,只是我没有将`modifiersField`声明为`final`.我的一位用户报告说它也适用于8u112. (3认同)
  • 所有这一切都与第二次世界大战的一项神秘法律有关,该法律援引了强大的加密技术实施的出口(包括在互联网上发布),美国政府将其比作出口弹药(武器/武器)。PGP的Phil Zimmerman受到了类似的起诉-因此Oracle直到最近才提供强大的加密库作为标准Java下载的一部分的原因。https://zh.wikipedia.org/wiki/Phil_Zimmermann#Arms_Export_Control_Act_investigation (2认同)

cra*_*hin 85

现在不再需要Java 9,也不再需要Java 6,7或8的最新版本.最后!:)

根据JDK-8170157,默认情况下现在启用无限制加密策略.

JIRA问题的具体版本:

  • Java 9:任何官方发布!
  • Java 8u161或更高版本(现已上市)
  • Java 7u171或更高版本(仅通过"My Oracle Support"提供)
  • Java 6u181或更高版本(仅通过'My Oracle Support'提供)

请注意,如果由于某些奇怪的原因在Java 9中需要旧行为,可以使用以下命令设置:

Security.setProperty("crypto.policy", "limited");
Run Code Online (Sandbox Code Playgroud)

  • 实际上,这个策略是默认的,因此Java 9中没有必要的操作! (4认同)

小智 22

这是解决方案:http://middlesphere-1.blogspot.ru/2014/06/this-code-allows-to-break-limit-if.html

//this code allows to break limit if client jdk/jre has no unlimited policy files for JCE.
//it should be run once. So this static section is always execute during the class loading process.
//this code is useful when working with Bouncycastle library.
static {
    try {
        Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
        field.setAccessible(true);
        field.set(null, java.lang.Boolean.FALSE);
    } catch (Exception ex) {
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 从Java 8 build 111开始,这个解决方案将是不够的,因为`isRestricted`字段已成为final(https://bugs.openjdk.java.net/browse/JDK-8149417).@ ntoskrnl的答案负责任何可能包含的"最终"修饰符.@ M.Dudley对Java许可协议的评论仍然适用. (3认同)

tim*_*yjc 13

据我所知,Bouncy Castle仍然需要安装罐子.

我做了一点测试,似乎证实了这一点:

http://www.bouncycastle.org/wiki/display/JA1/Frequently+Asked+Questions


小智 13

从JDK 8u102开始,依赖于反射的已发布解决方案将不再起作用:这些解决方案设置的字段现在是final(https://bugs.openjdk.java.net/browse/JDK-8149417).

看起来它回到(a)使用Bouncy Castle,或(b)安装JCE策略文件.

  • 您可以随时使用更多反射http://stackoverflow.com/questions/3301635/change-private-static-final-field-using-java-reflection (6认同)

小智 8

有关替代加密库,请查看Bouncy Castle.它具有AES和许多附加功能.它是一个自由的开源库.您将不得不使用轻量级的专有Bouncy Castle API来实现此功能.

  • 它们是一个很好的加密提供程序,但仍然需要无限强度的JCE文件才能使用大密钥. (19认同)
  • 如果直接使用Bouncy Castle API,则不需要无限强度文件. (16认同)

小智 5

你可以使用方法

javax.crypto.Cipher.getMaxAllowedKeyLength(String transformation)
Run Code Online (Sandbox Code Playgroud)

测试可用的密钥长度,使用它并通知用户发生了什么。例如,说明您的应用程序由于未安装策略文件而回退到 128 位密钥的内容。有安全意识的用户将安装策略文件,其他人将继续使用较弱的密钥。


dja*_*fan -1

在安装程序期间,只需提示用户并下载 DOS 批处理脚本或 Bash shell 脚本并将 JCE 复制到正确的系统位置。

我曾经必须为服务器 Web 服务执行此操作,而不是正式安装程序,我只是提供脚本来在用户运行应用程序之前设置应用程序。您可以使应用程序无法运行,直到它们运行安装脚本。您还可以让应用程序抱怨 JCE 丢失,然后要求下载并重新启动应用程序?

  • “让我的应用程序在最终用户计算机上运行*而不覆盖文件*” (8认同)