【问题标题】:java.security.InvalidKeyException: Illegal key size or default parameters in androidjava.security.InvalidKeyException:android中的非法密钥大小或默认参数
【发布时间】:2020-04-20 23:15:49
【问题描述】:

我收到以下错误,我有点卡住了: 线程“main”中的异常

java.security.InvalidKeyException: Illegal key size or default parameters
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1011)
                at javax.crypto.Cipher.implInit(Cipher.java:786)
                at javax.crypto.Cipher.chooseProvider(Cipher.java:849)
                at javax.crypto.Cipher.init(Cipher.java:1213)
                at javax.crypto.Cipher.init(Cipher.java:1153)
                at net.nakou.indie.wtext.engineClass.Session.cryptString(Session.java:52)

我被困住了,因为我找到的所有答案都是关于 Java 加密扩展 (JCE),它通常包含在 android SDK 中。所以我认为我的问题不是这个。

我一定忘记了什么,但我找不到什么。可能是我的代码错了(这是我第一次用Java加密的方法,我不是专家,下面的代码主要是一些教程的复制粘贴)。

我使用这段代码来加密和解密一个字符串:

public String cryptString(String s) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException {
    byte[] KeyData = this.cryptKey.getBytes();
    SecretKeySpec KS = new SecretKeySpec(KeyData, "Blowfish");
    Cipher cipher = Cipher.getInstance("Blowfish");
    cipher.init(Cipher.ENCRYPT_MODE, KS);
    String ret = new String(cipher.doFinal(s.getBytes("UTF-8")));
    return ret;
}

public String decryptString(byte[] s) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    byte[] KeyData = this.cryptKey.getBytes();
    SecretKeySpec KS = new SecretKeySpec(KeyData, "Blowfish");
    Cipher cipher = Cipher.getInstance("Blowfish");
    cipher.init(Cipher.DECRYPT_MODE, KS);
    String ret = new String(cipher.doFinal(s));
    return ret;
}

还有以下键:

private String cryptKey = "qkjll5@2md3gs5Q@FDFqf";

谢谢你们。

【问题讨论】:

  • 长话短说,无论它是否是 ADK 的一部分,您都需要像任何 java 应用程序一样在 $java/jre/lib/security 中进行更改。

标签: java android


【解决方案1】:

private String cryptKey = "qkjll5@2md3gs5Q@FDFqf";

默认情况下,Java 仅支持 128 位 加密

128 位 == 16 字节 == 16 个字符。

所以cryptKey 不能超过 16 个字符。

如果你想超过 16 个字符,你必须install Java Cryptography Extension (JCE) Unlimited Strength

Why 128bits?

【讨论】:

  • 你能解释一下原因吗?
  • @CaptainNakou 这些是JAVA的一部分
  • 好吧,它有效,谢谢,先生,希望在部署到APK之后可以在移动设备上使用...
  • "事实证明,Cipher 类通常不允许密钥大小超过 128 位的加密。这背后的明显原因是一些国家(尽管越来越少)对允许的密钥有限制进口加密软件的密钥强度,尽管实际数字 128 是有问题的。好消息是:您可以通过使用 Sun 提供的其他安全策略文件覆盖安全策略文件来轻松消除限制。”
【解决方案2】:

自 Java 8/9 以来已有更新

  1. Java 9 包含无限强度管辖策略文件并默认使用
  2. Java 8 Update 161 开始,Java 8 默认采用 Unlimited Strength Jurisdiction Policy。
  3. 从 Java 8 Update 151 开始,Java 8 中包含无限强度管辖策略,但默认情况下不使用。要启用它,您需要编辑 <java_home>/jre/lib/security(对于 JDK)或 <java_home>/lib/security(对于 JRE)中的 java.security 文件。取消注释(或包含)该行

    crypto.policy=unlimited

    确保使用以管理员身份运行的编辑器编辑文件。 策略更改仅在重启 JVM 后生效

Java 8 Update 151 之前,您必须下载 JCE Unlimited Strength Jurisdiction Policy 文件并替换。

更多详情见How to install Java Cryptography Extension (JCE) unlimited strength jurisdiction policy files

PS:以上链接指向我的个人博客,其中包含更多详细信息。

【讨论】:

    【解决方案3】:

    由于美国的限制,默认 JDK 仅支持通过 128 位密钥进行加密。因此,为了支持 256 位长密钥的加密,我们必须替换 $JAVA_HOME/java-8-oracle/jre/lib/security 文件夹中的 local_policy.jar 和 US_export_policy.jars 否则它将给出 java.security.InvalidKeyException: Illegal key size 或默认

    【讨论】:

      【解决方案4】:

      这是一个纯代码解决方案。无需下载或弄乱配置文件。

      这是一个基于反射的解决方案,在 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
      }
      

      【讨论】:

        【解决方案5】:

        您可以通过用无限强度策略 jar 替换现有的 JCE jar 来移除最大密钥限制。

        对于 JAVA 8,从链接下载 JCE Jar - https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

        (/usr/libexec/java_home -v 在Mac中查找Java_HOME)

        将从上面的zip文件中提取的local_policy.jarUS_export_policy.jar复制到$JAVA_HOME/jre/lib/security

        【讨论】:

          猜你喜欢
          • 2011-09-22
          • 2013-11-20
          • 1970-01-01
          • 1970-01-01
          • 2011-10-17
          • 2011-04-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多