4

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

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 为空,或者给定的算法参数暗示的加密强度将超过法律限制(由配置的管辖权策略文件确定)。

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

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

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

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

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

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

我尝试给GCMParameterSpec唯一的解密,我得到未知的参数类型异常。

任何帮助表示赞赏

4

3 回答 3

5

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

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

由于您具有标准标签大小,因此这应该不会对您的实现造成任何问题。


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

于 2017-03-22T12:55:35.273 回答
3

正如@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);
}
于 2018-07-09T19:07:47.840 回答
-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");
}
于 2017-03-21T13:57:20.980 回答