Issue while using Android fingerprint: IV required when decrypting. Use IvParameterSpec or AlgorithmParameters to provide it
我正在遵循Google提供的ConfirmCredential Android示例,但是它仅显示了如何加密数据。当我尝试解密它时,出现异常:
1 | java.security.InvalidKeyException: IV required when decrypting. Use IvParameterSpec or AlgorithmParameters to provide it. |
我使用以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | String transforation = KeyProperties.KEY_ALGORITHM_AES +"/" + KeyProperties.BLOCK_MODE_CBC +"/" + KeyProperties.ENCRYPTION_PADDING_PKCS7; KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); SecretKey secretKey = (SecretKey) keyStore.getKey(KEY_NAME, null); // encrypt Cipher cipher = Cipher.getInstance(transforation); cipher.init(Cipher.ENCRYPT_MODE, secretKey); String encriptedPassword = cipher.doFinal("Some Password".getBytes("UTF-8")); // decrypt cipher = Cipher.getInstance(transforation); cipher.init(Cipher.DECRYPT_MODE, secretKey); String password = new String(cipher.doFinal(encriptedPassword),"UTF-8")); |
在以下行引发异常:
1 | cipher.init(Cipher.DECRYPT_MODE, secretKey); |
在这种情况下,什么是正确的解密方法的任何想法?
基本上,必须将IvParameterSpec传递给解密模式,而不应手动将其设置为加密模式。
这就是我所做的,并且效果很好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | private initCipher(int mode) { try { byte[] iv; mCipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES +"/" + KeyProperties.BLOCK_MODE_CBC +"/" + KeyProperties.ENCRYPTION_PADDING_PKCS7); IvParameterSpec ivParams; if(mode == Cipher.ENCRYPT_MODE) { mCipher.init(mode, generateKey()); ivParams = mCipher.getParameters().getParameterSpec(IvParameterSpec.class); iv = ivParams.getIV(); fos = getContext().openFileOutput(IV_FILE, Context.MODE_PRIVATE); fos.write(iv); fos.close(); } else { key = (SecretKey)keyStore.getKey(KEY_NAME, null); File file = new File(getContext().getFilesDir()+"/"+IV_FILE); int fileSize = (int)file.length(); iv = new byte[fileSize]; FileInputStream fis = getContext().openFileInput(IV_FILE); fis.read(iv, 0, fileSize); fis.close(); ivParams = new IvParameterSpec(iv); mCipher.init(mode, key, ivParams); } mCryptoObject = new FingerprintManager.CryptoObject(mCipher); } catch(....) } |
您还可以使用Base64对IV数据进行编码,然后将其保存在共享首选项下,而不是将其保存在文件下。
在任何一种情况下,如果您已为Android M使用了新的完整备份功能,请记住,该数据不应被备份/还原,因为当用户重新安装该应用程序或将其安装在另一个应用程序上时,该数据无效设备。
我在github项目中为google提供的示例创建了一个问题(在此处链接到问题)。我得到的响应是我必须使用加密值时生成的IV。 (与@Qianqian提供的解决方案相同)
1 2 | cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(encryptCipher.getIV())); byte[] decryptedBytes = cipher.doFinal(encryptedBytes); |
我创建了一个示例应用程序,演示了如何执行此操作。它可以在github上找到。
希望这对某人有用。
怎么样,
如果您使用Google repo的示例代码,上面的行将起作用,还请注意,对于每个mChiper.init,我们都需要使用指纹进行一次身份验证,这意味着需要两次指纹身份验证,一个用于加密,一个用于解密。
https://github.com/googlesamples/android-FingerprintDialog