1

I encrypted data successfully using the biometric manager flow as shown by google but on trying the decrypt the encrypted data, I keep hitting the IllegalBlockSizeException clause. I need help please.

This is my class that handles all the fingerprint encryption( which works well) but decryption doesn't work, since it keeps hitting the IllegalBlockSizeException clause

public class FingerPrintEncrypter {
    private static FingerPrintEncrypter fingerPrintEncrypter;
    private static final String ENCRYPTION_BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC;
    private static final String ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7;
    private static final String ENCRYPTION_ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;
    private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
    byte[] initVector;

    private FingerPrintEncrypter(){

    }

    public static synchronized FingerPrintEncrypter getInstance(){
        if(fingerPrintEncrypter == null){
            fingerPrintEncrypter = new FingerPrintEncrypter();
        }
        return fingerPrintEncrypter;

    }

    /*
    gets the Cipher obj in encryptionMode for encryption tasks.
     */
    public Cipher getCipherForEncryption(String aliasKeyName){
        try {
            Cipher cipher = getCipher();
            SecretKey secretKey = getOrCreateSecreteKey(aliasKeyName);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            initVector = cipher.getIV();
            return cipher;
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
    gets the Cipher obj in decryptionMode for decryption tasks.
     */
    public Cipher getCipherForDecryption(String aliasKeyName){
        try{
            Cipher cipher = getCipher();
            SecretKey secretKey = getOrCreateSecreteKey(aliasKeyName);
            IvParameterSpec decryptParamSpec = new IvParameterSpec(initVector);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, decryptParamSpec);
            return cipher;
        }catch (InvalidKeyException e){
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return null;
    }

    private SecretKey getOrCreateSecreteKey(String aliasKeyName) {
        try {
            KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
            keyStore.load(null);
            SecretKey key = ((SecretKey)keyStore.getKey(aliasKeyName, null));
            if(key == null){
                // key previously create so just grab it
                generateSecretKey(aliasKeyName);
            }
            return key;
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void generateSecretKey(String aliasKeyName){
        try {
            // key not create create a new one
            KeyGenParameterSpec parameterSpec = new KeyGenParameterSpec.Builder(aliasKeyName,
                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                    .setBlockModes(ENCRYPTION_BLOCK_MODE)
                    .setEncryptionPaddings(ENCRYPTION_PADDING)
                    .setUserAuthenticationRequired(true)
                    .build();

            KeyGenerator keyGenerator = KeyGenerator.getInstance(ENCRYPTION_ALGORITHM, ANDROID_KEY_STORE);
            keyGenerator.init(parameterSpec);
            keyGenerator.generateKey();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
    }


    private Cipher getCipher() {
        try {
            return Cipher.getInstance(ENCRYPTION_ALGORITHM + "/"
                    + ENCRYPTION_BLOCK_MODE + "/"
                    + ENCRYPTION_PADDING);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String encryptData(String info, Cipher cipher){
        try {
            byte[] encryptedData = cipher.doFinal(info.getBytes("UTF-8"));
            return Base64.encodeToString(encryptedData, Base64.NO_WRAP);
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String decryptData(String stringToDecrypt, Cipher cipher){
        try {
            return new String(cipher.doFinal(Base64.decode(stringToDecrypt, Base64.NO_WRAP)));
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return null;
    }


}
Neo
  • 449
  • 1
  • 5
  • 9
  • One thing that I wonder since I generate a new IV every time, does the IV initVector you get from cipher always stay the same or does it generate new initVectors every time? In that case it would be hard to get the right IV for your decrypt cipher. That being said, if my memory serves me right (I also spent alot of time hunting down these kind of problems), it sounds like you might have a problem with your padding – Vanheden Nov 14 '21 at 00:36
  • I remember a big problem for me was the wrong bit-size in the IV, but if cipher.getIV() works the way you use it then I suppose Cipher class should give you a working one – Vanheden Nov 14 '21 at 00:46
  • well it's supposed too, but honestly I don't know why I keep getting that error, and the official google doc too doesn't help on showing how the decryption process works too. – Neo Nov 14 '21 at 12:54
  • But now, if you encrypt a value, you assign your byte[] initVector. Then if you store what you have encrypted and restart your app and try to decrypt the data, would it not try to decrypt it with a null byte[] initVector if you have not encrypted anything before (to set up initVector)? – Vanheden Nov 14 '21 at 19:43
  • thanks, for your reply vanheden,I've found a way to implement this. It now works easily. – Neo Nov 14 '21 at 22:28
  • 1
    The issue was that the byte[] initVector passed to the IVParameterSpec, was supposed to which I got from cipher.getIV() was supposed to be called, if an only when the cipher has done encryption and not before. – Neo Nov 14 '21 at 22:30

0 Answers0