Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue while using Android fingerprint: IV required when decrypting. Use IvParameterSpec or AlgorithmParameters to provide it

I'm following the ConfirmCredential Android example provided by Google, but it only shows how to encrypt the data. When I try to decrypt it I get exception:

java.security.InvalidKeyException: IV required when decrypting. Use IvParameterSpec or AlgorithmParameters to provide it.

I use the following code:

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"));

The exception is thrown at line:

cipher.init(Cipher.DECRYPT_MODE, secretKey);

Any idea on what is the proper way to do the decryption in this case?

like image 463
Zlatko Avatar asked Oct 19 '15 12:10

Zlatko


People also ask

What is encryption and decryption in Android?

Encryption is the process of encoding all user data on an Android device using symmetric encryption keys. Once a device is encrypted, all user-created data is automatically encrypted before committing it to disk and all reads automatically decrypt data before returning it to the calling process.

What is AES algorithm in Android?

The AES algorithm is a symmetric block cipher that can encrypt (encipher) and decrypt (decipher) information. It uses only one secret key to encrypt plain data, and uses 128-, 192-, and 256-bit keys to process 128-bit data locks. This algorithm receives data and encrypts it using a password.

What is cryptography in Android?

Android builds on the Java Cryptography Architecture (JCA), that provides API for digital signatures, certificates, encryption, keys generation and management. KeyGenerator — provides the public API for generating symmetric cryptographic keys.


2 Answers

Basically you have to pass the IvParameterSpec for the decrypt mode whereas you should not manually set it for encryption mode.

So here is what I did and it worked well:

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(....)
}

You can also encode the IV data with Base64 and save it under shared preferences instead of saving it under a file.

In either case, If you have employed the new full backup feature for Android M, keep in mind that this data should NOT be allowed to backup/restore since it is invalid when a user reinstall the app or install the app on another device.

like image 98
Qianqian Avatar answered Oct 14 '22 12:10

Qianqian


I created an issue in the github project for the sample provided by google (link to the issue here). The response I got is that I must use the IV that was generated when the value was encrypted. (same as in the solution provided by @Qianqian)

cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(encryptCipher.getIV()));
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

I created a sample application that shows how to do this. It is available on github, here.

Hope this is useful to someone.

like image 4
Zlatko Avatar answered Oct 14 '22 11:10

Zlatko