【问题标题】:GCMParameterSpec throws InvalidAlgorithmParameterException: unknown parameter typeGCMParameterSpec 抛出 InvalidAlgorithmParameterException:未知参数类型
【发布时间】:2017-08-13 04:35:37
【问题描述】:

我正在做 android 数据加密以保存在 SharedPreferences 中。 GCMParameterSpec 是在 Android 的 API 19 中引入的,我将其用于AES/GCM/NoPadding 加密。这就是我实现它的方式:

Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
c.init(Cipher.ENCRYPT_MODE, getSecretKey(context),new GCMParameterSpec(128,Base64.decode(myGeneratedIV, Base64.DEFAULT)));

我的问题是,在 Android 4.4.2 (API 19) 中,我得到了提到的错误,但从 API 21 开始它可以工作。

关于异常,来自 Android 文档:

如果给定的算法参数不适合此密码,或者此密码需要算法参数并且 params 为空,或者给定的算法参数暗示的加密强度将超过法律限制(由配置的管辖权政策文件确定) .

我的问题是:这种行为是否有特定原因?为什么 Cipher 中的 init 方法不能识别参数?

我什至尝试在不提供特定 IV 的情况下进行加密:

c.init(Cipher.ENCRYPT_MODE, getSecretKey(context));

一旦我尝试以同样的方式解密:

c.init(Cipher.DECRYPT_MODE, getSecretKey(context));

它抛出相同的异常(InvalidAlgorithmParameterException)说需要GCMParameterSpec 进行解密。

我尝试将GCMParameterSpec 仅用于解密,但我得到了未知参数类型异常。

感谢任何帮助

【问题讨论】:

  • 感谢您的反馈@MaartenBodewes。我最终为 API 19 定义了一种不同的加密模式。除了 GCM 之外,我还寻找一种可行且安全的加密方式,它也使用 IV,我选择使用“AES/CBC/PKCS5Padding”。
  • 我将 IvParamaterSpec 与 AES/GCM/NoPadding 一起使用,并且效果很好。谢谢
  • 由于 Cipher 的实例是 AES/GCM,尽管我不得不使用 GCMParameterSpec,这也是我从未尝试过使用 IvParamaterSpec 的主要原因。工作得很好,我能够避免使用 AES/CBC
  • 对于到达这里的任何人,我设法通过使用ProviderInstaller developer.android.com/training/articles/… 更新安全提供程序解决了同样的问题

标签: java android encryption cryptography aes-gcm


【解决方案1】:

Android 中提供程序中的CipherSpi 实现可能还不支持GCMParameterSpec。定义 API 与在底层加密提供程序中为其提供支持不同。

您也可以使用为其他模式提供的标准IvParameterSpec。只需将 GCMParamterSpec 的 (12) IV/nonce 字节直接用作您的 IV。

因为你有标准的标签大小,这对你的实现应该没有问题。


如果标签大小不同,则解决方案会变得更加复杂,因为验证将只使用结果标签的最左边字节。不幸的是,标签生成和验证隐藏在 Cipher 类的 API 设计中。

【讨论】:

    【解决方案2】:

    正如@Maarten 所说,您可以将IvParameterSpec 用于运行KitKat 的设备:

    private static final int TAG_LENGTH_BYTES = 16;
    
    public byte[] encrypt(...) {
        ...
        Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(rawEncryptionKey, "AES"), getParams(iv));
        ...
    }
    
    public byte[] decrypt(...) {
        ...
        Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(rawEncryptionKey, "AES"), getParams(iv));
        ...
    }
    
    private static AlgorithmParameterSpec getParams(final byte[] iv) {
        return getParams(iv, 0, iv.length);
    }
    
    private static AlgorithmParameterSpec getParams(final byte[] buf, int offset, int len) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            // GCMParameterSpec should always be present in Java 7 or newer, but it's missing on
            // some Android devices with API level <= 19. Fortunately, we can initialize the cipher
            // with just an IvParameterSpec. It will use a tag size of 128 bits.
            return new IvParameterSpec(buf, offset, len);
        }
        return new GCMParameterSpec(TAG_LENGTH_BYTES * 8, buf, offset, len);
    }
    

    【讨论】:

      【解决方案3】:

      试试这个代码...

          private static final String Key = "0123456789abcdef";
      
      public static SecretKey generateKey() throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
          return new SecretKeySpec(Key.getBytes("UTF-8"), "AES");
      }
      
      public static byte[] encryptMsg(String message, SecretKey secret)
              throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
      
          Cipher cipher;
          cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
          cipher.init(Cipher.ENCRYPT_MODE, secret);
          return cipher.doFinal(message.getBytes("UTF-8"));
      }
      
      public static String decryptMsg(byte[] cipherText, SecretKey secret)
              throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
      
          Cipher cipher;
          cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
          cipher.init(Cipher.DECRYPT_MODE, secret);
          return new String(cipher.doFinal(cipherText), "UTF-8");
      }
      

      【讨论】:

      • 我需要满足安全要求,因此不能选择更改 Cipher 实例。进一步的信息,“AES/ECB/PKCS5Padding”有很多安全问题,你不应该使用它进行数据加密的主要原因
      • 那里有很多糟糕的加密代码片段,不幸的是,这就是其中之一。一般来说,请不要粘贴通用加密/解密代码以响应特定答案。另请注意,代码片段本身不被视为 StackOverflow 上的答案:您需要解释 如何为什么 它们解决问题中的问题。感谢您的尝试,请不要让这阻止您发布其他答案。
      猜你喜欢
      • 1970-01-01
      • 2021-09-01
      • 2015-05-04
      • 2017-07-13
      • 1970-01-01
      • 2019-06-06
      • 1970-01-01
      • 2013-10-20
      • 1970-01-01
      相关资源
      最近更新 更多