Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Key permanently invalidated Exception after adding/removing fingerprint

When user adds new fingerprint or removes any existing fingerprint and then tries to launch the application it throws KeyPermanentlyInvalidatedException

Here's my fingerprint code:

 public Boolean auth(FingerprintManager.AuthenticationCallback callback) {
    try {
        KeyStore store = accessKeyStore(DEFAULT_KEYSTORE);
        if (store == null) {
            return null;
        }

        Cipher cipher = accessCipher();
        if (cipher == null) {
            return null;
        }

        store.load(null);
        SecretKey key = (SecretKey) store.getKey(DEFAULT_KEY_NAME, DEFAULT_STORE_PASS.toCharArray());
        cipher.init(Cipher.ENCRYPT_MODE, key);

        FingerprintManager manager = initManager();
        if (manager == null) {
            return null;
        }

        manager.authenticate(
                generateCryptoObject(cipher),
                generateCancellationSignal(),
                0,
                callback,
                null
        );

        return true;
    } catch (Throwable exc) {
        Logger.error(TAG, exc.getLocalizedMessage(), exc);
        return null;
    }
}



private Cipher accessCipher() {
    try {
        return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                + KeyProperties.BLOCK_MODE_CBC + "/"
                + KeyProperties.ENCRYPTION_PADDING_PKCS7);
    } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
        // Was not available.
        return null;
    }
}

Called auth method in onResume().

Entire FingerPrintUtils class:

`

public class FingerPrintUtils {

    private static final String TAG = FingerPrintUtils.class.getSimpleName();
    private static final String DEFAULT_KEYSTORE = "AndroidKeyStore";
    private static final String DEFAULT_KEY_NAME = "myApplication";
    private static final String DEFAULT_STORE_PASS = "csdgh@jkbvj@";
    private static FingerPrintUtils fingerPrintUtils;

    private Boolean isCancelled;
    private CancellationSignal cancellationSignal;

    @TargetApi(23)
    public static FingerPrintUtils getInstance() {
        if (fingerPrintUtils == null) {
            fingerPrintUtils = new FingerPrintUtils();
        }
        return fingerPrintUtils;
    }

    @TargetApi(23)
    public Boolean isFingerAuthAvailable() {
        Boolean hasHarware = hasHardware();
        if (hasHarware == null || !hasHarware) {
            return false;
        }

        Boolean hasPrint = hasRegisteredPrint();
        if (hasPrint == null || !hasPrint) {
            return false;
        }
        return true;
    }

    @TargetApi(23)
    public Boolean hasHardware() {
        FingerprintManager manager = initManager();
        if (manager == null) {
            return null;
        }

        return manager.isHardwareDetected();
    }

    @TargetApi(23)
    public Boolean hasRegisteredPrint() {
        FingerprintManager manager = initManager();
        if (manager == null) {
            return null;
        }

        return manager.hasEnrolledFingerprints();
    }

    @TargetApi(23)
    public Boolean createKey() {
        try {
            KeyStore store = accessKeyStore(DEFAULT_KEYSTORE);
            if (store == null) {
                return null;
            }

            KeyGenerator generator = accessKeyGen(KeyProperties.KEY_ALGORITHM_AES, DEFAULT_KEYSTORE);
            if (generator == null) {
                return null;
            }

            generator.init(new KeyGenParameterSpec.Builder(
                    DEFAULT_KEY_NAME,
                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
            )
                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                            // Require the user to authenticate with a fingerprint to authorize every use
                            // of the key
                    .setUserAuthenticationRequired(true)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
                    .build());
            generator.generateKey();
            return true;
        } catch (Throwable exc) {
            Logger.error(TAG, exc.getLocalizedMessage(), exc);
            return false;
        }
    }

    @TargetApi(23)
    public Boolean keyExist() {
        try {
            KeyStore store = accessKeyStore(DEFAULT_KEYSTORE);
            if (store == null) {
                return null;
            }

            store.load(null);
            SecretKey key = (SecretKey) store.getKey(DEFAULT_KEY_NAME, DEFAULT_STORE_PASS.toCharArray());
            if (key != null) {
                return true;
            }

        } catch (Throwable exc) {
            Logger.error(TAG, exc.getLocalizedMessage(), exc);
            return null;
        }
        return false;
    }

    @TargetApi(23)
    public Boolean auth(FingerprintManager.AuthenticationCallback callback) {
        try {
            KeyStore store = accessKeyStore(DEFAULT_KEYSTORE);
            if (store == null) {
                return null;
            }

            Cipher cipher = accessCipher();
            if (cipher == null) {
                return null;
            }

            store.load(null);
            SecretKey key = (SecretKey) store.getKey(DEFAULT_KEY_NAME, DEFAULT_STORE_PASS.toCharArray());
            cipher.init(Cipher.ENCRYPT_MODE, key);

            FingerprintManager manager = initManager();
            if (manager == null) {
                return null;
            }

            manager.authenticate(
                    generateCryptoObject(cipher),
                    generateCancellationSignal(),
                    0,
                    callback,
                    null
            );

            return true;
        } catch (Throwable exc) {
            Logger.error(TAG, exc.getLocalizedMessage(), exc);
            return null;
        }
    }

    @TargetApi(23)
    public Boolean stop() {
        if (isCancelled != null && !isCancelled) {
            isCancelled = true;
            cancellationSignal.cancel();
            cancellationSignal = null;
            return true;
        }
        return false;
    }

    @TargetApi(23)
    private FingerprintManager initManager() {
        Context context = BasePreferenceHelper.getCurrentContext();
        if (context == null) {
            return null;
        }

        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return null;
        }

        FingerprintManager manager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
        if (manager == null) {
            return null;
        }

        return manager;
    }

    @TargetApi(23)
    private Cipher accessCipher() {
        try {
            return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                    + KeyProperties.BLOCK_MODE_CBC + "/"
                    + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            // Was not available.
            return null;
        }
    }

    @TargetApi(23)
    private KeyStore accessKeyStore(String storeName) {
        try {
            return KeyStore.getInstance(storeName);
        } catch (Throwable exc) {
            // Was not available.
            return null;
        }
    }

    @TargetApi(23)
    private FingerprintManager.CryptoObject generateCryptoObject(Cipher cipher) {
        if (cipher == null) {
            throw new IllegalArgumentException("Cipher is required.");
        }
        return new FingerprintManager.CryptoObject(cipher);
    }

    @TargetApi(23)
    private CancellationSignal generateCancellationSignal() {
        cancellationSignal = new CancellationSignal();
        isCancelled = false;
        return cancellationSignal;
    }

    @TargetApi(23)
    private KeyGenerator accessKeyGen(String algo, String storeName) {
        try {
            return KeyGenerator.getInstance(algo, storeName);
        } catch (Throwable exc) {
            // Was not available.
            return null;
        }
    }
}

`

like image 200
musica Avatar asked Dec 08 '22 17:12

musica


1 Answers

In your FingerPrintUtils#Auth() method, while initializing cipher.init(), put it into try catch block. Handle KeyInvalidatedException by deleting key from keystore and again create key using createKey() method. It will definitely work.

use below code for the same.

try
{
    cipher.init(Cipher.ENCRYPT_MODE, key);
}
catch (KeyPermanentlyInvalidatedException e)
{
    store.deleteEntry(DEFAULT_KEY_NAME);
    createKey();
    auth(callback);
    return false;
}
like image 78
Nirav Bhandari Avatar answered Dec 10 '22 11:12

Nirav Bhandari