我正在做android数据加密以保存在SharedPreferences中。 GCMParameterSpec是在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为null,或者给定的算法参数意味着加密强度超出法定限制(根据配置的管辖区策略文件确定)
我的问题是:这种行为有特定原因吗?为什么Cipher的init
方法没有识别params?
我甚至尝试过加密而不提供特定的IV:
c.init(Cipher.ENCRYPT_MODE, getSecretKey(context));
一旦我尝试以同样的方式解密:
c.init(Cipher.DECRYPT_MODE, getSecretKey(context));
它抛出相同的异常(InvalidAlgorithmParameterException),说解密需要GCMParameterSpec
。
我尝试仅将GCMParameterSpec
提供给解密,并且我获得了未知参数类型异常。
感谢任何帮助
答案 0 :(得分:4)
Android中的提供程序中的CipherSpi
实现可能尚不支持GCMParameterSpec
。定义API与在底层加密提供程序中为其提供支持不同。
相反,您也可以使用为其他模式提供的标准IvParameterSpec
。只需将GCMParamterSpec
的(12)IV / nonce字节直接用作IV。
由于您具有标准标记大小,因此这对您的实现没有任何问题。
如果标签大小不同,则解决方案变得更加复杂,因为验证将仅使用结果标签的最左侧字节。遗憾的是,标记生成和验证隐藏在Cipher
类的API设计中。
答案 1 :(得分:1)
正如@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);
}
答案 2 :(得分:-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");
}