Java安全:非法密钥大小或默认参数?

439

之前我曾经提出过这个问题,但并没有得到正确的答案,也没有取得任何进展。

现在我已经澄清了问题的一些细节,非常想听听您对如何解决这个问题或应该尝试什么的建议。

我的Linux服务器上安装了Java 1.6.0.12,下面的代码可以完美运行。

String key = "av45k1pfb024xa3bl359vsb4esortvks74sksr5oy4s5serondry84jsrryuhsr5ys49y5seri5shrdliheuirdygliurguiy5ru";
try {
    Cipher c = Cipher.getInstance("ARCFOUR");

    SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "ARCFOUR");
    c.init(Cipher.DECRYPT_MODE, secretKeySpec);

    return new String(c.doFinal(Hex.decodeHex(data.toCharArray())), "UTF-8");

} catch (InvalidKeyException e) {
    throw new CryptoException(e);
}

今天我在我的服务器上安装了Java 1.6.0.26,但当我尝试运行我的应用程序时,出现以下异常。 我猜测这可能与Java安装配置有关,因为它在早期版本中可以正常工作,但在后来的版本中却不能正常工作。

Caused by: java.security.InvalidKeyException: Illegal key size or default parameters
    at javax.crypto.Cipher.a(DashoA13*..) ~[na:1.6]
    at javax.crypto.Cipher.a(DashoA13*..) ~[na:1.6]
    at javax.crypto.Cipher.a(DashoA13*..) ~[na:1.6]
    at javax.crypto.Cipher.init(DashoA13*..) ~[na:1.6]
    at javax.crypto.Cipher.init(DashoA13*..) ~[na:1.6]
    at my.package.Something.decode(RC4Decoder.java:25) ~[my.package.jar:na]
    ... 5 common frames omitted

第25行是: c.init(Cipher.DECRYPT_MODE, secretKeySpec);

注意:
* 服务器上的java.security中的1.6.0.12版本几乎完全与1.6.0.26版本的java.security文件相匹配。第一个版本中没有额外的提供程序。
* 上一个问题在这里


4
在Java 8中,可能会抛出如下错误:Caused by: java.security.InvalidKeyException: Illegal key size(不包含“或默认参数”)。 - EagleEye208
只需使用OpenJDK,它就可以正常工作。 - Rodrigo Asensio
@RodrigoAsensio:我正在使用OpenJDK,但它无法正常工作。您需要安装无限强度管辖策略文件jar文件。然后它就可以工作了。 - anjanb
7
自 Java 9 和 Java 8u151 后,不再需要下载并手动安装权限策略文件以启用无限制加密。现在可以使用新的 crypto.policy 安全属性来实现。如果在 java.security 文件中设置了新的 Security 属性 (crypto.policy),或者在 JCE 框架初始化之前使用了 Security.setProperty() 调用进行了动态设置,则会遵循该设置。默认情况下,该属性未定义。 - Marcin Kłopotek
20个回答

751

3
是的,为了确保覆盖所有基础,我把JAR文件放在“Java/jre/lib/security”、“Java/jdk/lib/security”和“Java/jdk/jre/lib/security”下。运行“java -version”会返回预期的详细信息。 - aroth
5
对于IBM的SDK(例如WebSphere),请从https://www14.software.ibm.com/webapp/iwm/web/preLogin.do?source=jcesdk下载无限制权限策略文件。 - quietmint
4
自从Java 9和Java 8u151版本以后,就不再需要下载和手动安装权限策略文件。要启用无限制加密,可以使用新的crypto.policy安全属性。如果在java.security文件中设置了新的安全属性(crypto.policy),或者在JCE框架初始化之前使用Security.setProperty()动态设置了该属性,那么该设置将被采纳。默认情况下,该属性将未定义。 - Marcin Kłopotek
4
这个被点赞的回答现已过时且不再建议使用。我们如何对该回答进行投票或抑制,以便 https://dev59.com/qmw15IYBdhLWcg3wo9Vx#46857694 成为“被采纳”的答案? - Jesse Adelman
3
很遗憾,这个已经快七年了,无法再做更改。询问者需要进行更改。 - James Black
显示剩余18条评论

57

2
尝试使用6和7,但它们没有起作用。不得不安装8。谢谢。 - Jason Kim
9
新版本JDK 8u151具有“新的安全属性以控制加密策略”。现在,这是一个属性更改开关。底线:从“lib \ security \ java.security”中的“#crypto.policy = unlimited”行中删除“#”,以启用使用256位密钥。 - hemisphire
1
由于这是一个安全属性,您还可以调用Security.setProperty("crypto.policy", "unlimited")。来源:@hemisphire的链接 :) - Fluf

48

随着Java 9的发布,Java 8u161Java 7u171Java 6u181的默认限制现已被禁用。请参见Java Bug Database中的问题


Java 8u151开始,您可以通过编程方式禁用该限制。

在旧版本中,必须单独下载和安装JCE权限文件,才能允许JDK使用无限制的加密功能。现在不再需要下载和安装步骤。

相反,您现在可以在首次使用JCE类之前(即最好在应用程序启动后立即)调用以下行:

Security.setProperty("crypto.policy", "unlimited");

在Android方面怎么样?这些限制方法在哪个API级别上可以解决? - TheRealChx101

43

对于JAVA 7,下载链接为jce-7-download

将下载的两个JAR文件复制到Java\jdk1.7.0_10\jre\lib\security文件夹中
为了更加安全,请备份旧的JAR文件。

对于JAVA 8,下载链接为jce-8-download
将下载的JAR文件复制到Java\jdk1.8.0_45\jre\lib\security文件夹中
为了更加安全,请备份旧的JAR文件。


35

这是一个仅包含代码的解决方案,无需下载或操纵配置文件。

这是一个基于反射的解决方案,已在java 8上进行了测试。

在程序早期调用此方法一次。

//导入

import javax.crypto.Cipher;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;

//方法

public static void fixKeyLength() {
    String errorString = "Failed manually overriding key-length permissions.";
    int newMaxKeyLength;
    try {
        if ((newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES")) < 256) {
            Class c = Class.forName("javax.crypto.CryptoAllPermissionCollection");
            Constructor con = c.getDeclaredConstructor();
            con.setAccessible(true);
            Object allPermissionCollection = con.newInstance();
            Field f = c.getDeclaredField("all_allowed");
            f.setAccessible(true);
            f.setBoolean(allPermissionCollection, true);

            c = Class.forName("javax.crypto.CryptoPermissions");
            con = c.getDeclaredConstructor();
            con.setAccessible(true);
            Object allPermissions = con.newInstance();
            f = c.getDeclaredField("perms");
            f.setAccessible(true);
            ((Map) f.get(allPermissions)).put("*", allPermissionCollection);

            c = Class.forName("javax.crypto.JceSecurityManager");
            f = c.getDeclaredField("defaultPolicy");
            f.setAccessible(true);
            Field mf = Field.class.getDeclaredField("modifiers");
            mf.setAccessible(true);
            mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);
            f.set(null, allPermissions);

            newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES");
        }
    } catch (Exception e) {
        throw new RuntimeException(errorString, e);
    }
    if (newMaxKeyLength < 256)
        throw new RuntimeException(errorString); // hack failed
}

制作人员: Delthas


6
请注意,这可能会违反Java SE许可协议: D. JAVA TECHNOLOGY RESTRICTIONS. 您不得创建、修改或更改被标识为“java”、“javax”、“javafx”、“sun”、“oracle”或Oracle在任何命名约定指定的类、接口或子包的行为,也不得授权您的许可证持有者创建、修改或更改它们的行为。[...] 来源 - SimMac

18

在Java中,默认情况下AES支持128位密钥,如果您计划使用192位或256位密钥,则Java编译器会抛出非法密钥大小异常,这是您遇到的问题。

解决方案如Victor和James建议的那样,您需要根据您的JRE版本(java6、java7或java8)下载JCE(Java加密扩展)。

JCE zip包含以下JAR:

  1. local_policy.jar
  2. US_export_policy.jar

您需要将这些jar文件替换为您的<JAVA_HOME>/jre/lib/security。如果您使用的是Unix系统,则可能会引用/home/urs/usr/lib/jvm/java-<version>-oracle/

有时只更换安全文件夹中的local_policy.jar和US_export_policy.jar在Unix上不起作用,因此我建议先将安全文件夹复制到桌面,将@Desktop/security文件夹中的jar文件替换,然后从/jre/lib/中删除安全文件夹并将桌面安全文件夹移到/jre/lib/。

例如:sudo mv security /usr/lib/jvm/java-7-oracle/jre/lib


我在Ubuntu 18上尝试了这个,但它不起作用。我在想我们是否需要重新启动PC或Tomcat服务器才能应用更改? - Borgy Manotoy
1
Java编译器不会抛出非法密钥大小异常。在编译时,两个合作方的密钥大小甚至还未知!这种情况要到运行时,在SSL握手过程中才会发生... :-) - Lanzelot

16

我在使用Windows 7 x64、Eclipse和JDK 1.6.0_30时遇到了同样的错误。在JDK安装文件夹中有一个jre文件夹。一开始,我尝试将上述jar包添加到JDK的lib/security文件夹中,但没有成功。完整路径:

C:\Program Files\Java\jdk1.6.0_30\jre\lib\security

此存档中下载并提取包含在jce文件夹中的文件,然后将其放入该文件夹中。


16

5

问题出在安装JRE后,位于文件夹jre\lib\security中的local_policy.jar文件中的default_local.policy文件内容上。

// Some countries have import limits on crypto strength. This policy file
// is worldwide importable.

grant {
    permission javax.crypto.CryptoPermission "DES", 64;
    permission javax.crypto.CryptoPermission "DESede", *;
    permission javax.crypto.CryptoPermission "RC2", 128,
                                     "javax.crypto.spec.RC2ParameterSpec", 128;
    permission javax.crypto.CryptoPermission "RC4", 128;
    permission javax.crypto.CryptoPermission "RC5", 128,
          "javax.crypto.spec.RC5ParameterSpec", *, 12, *;
    permission javax.crypto.CryptoPermission "RSA", *;
    permission javax.crypto.CryptoPermission *, 128;
};

如果您不需要全球通用的设置,您可以直接编辑此文件并更改内容为:

// Country-specific policy file for countries with no limits on crypto strength.
grant {
    // There is no restriction to any algorithms.
    permission javax.crypto.CryptoAllPermission;
};

如果您从Oracle下载JCE,您将得到以下内容。


5
这个问题似乎在这里有一个简短的讨论:这里。它链接到的页面已经不存在了,但其中一个回复可能是你需要的:

的确,将core/lib/jce中的US_export_policy.jar和local_policy.jar复制到$JAVA_HOME/jre/lib/security中有所帮助。谢谢。


谢谢,但是我在安装Java时已经将US_export_policy.jarlocal_policy.jar放在我的lib/security文件夹中了。顺便说一下,我在我的Java安装文件夹中找不到core/lib/jce。 - Rihards

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接