KeyPermanentlyInvalidatedException не работает

Я использовал KeyPermanentlyInvalidatedException для обнаружения добавления нового отпечатка пальца. Но он не генерирует исключение KeyPermanentlyInvalidatedException.

Я попробовал этот шаг:

  1. Пункт списка
  2. Создать пару ключей
  3. Инициализировать подпись с закрытого ключа
  4. Добавить новый отпечаток пальца из настроек телефона
  5. Попробуйте еще раз инициализировать подпись с помощью закрытого ключа, но это не вызывает исключение KeyPermanentlyInvalidatedException.

Я также нашел эту ссылку из stackoverflow, но она не мне не помочь.

Из документа:

Ключ становится необратимо недействительным после отключения экрана безопасной блокировки (перенастройки на «Нет», «Пролистывание» или другого режима, который не аутентифицирует пользователя) или при принудительном сбросе экрана безопасной блокировки (например, администратором устройства). Кроме того, если для ключа требуется, чтобы аутентификация пользователя выполнялась при каждом использовании ключа, он также необратимо аннулируется после регистрации нового отпечатка пальца или после того, как больше не будет зарегистрировано отпечатков пальцев, если только setInvalidatedByBiometricEnrollment(boolean) не используется для обеспечения достоверности после регистрации. Попытки инициализировать криптографические операции с использованием таких ключей вызовут исключение KeyPermanentlyInvalidatedException.

Вот мой код:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_authenticate);

    mButtonTest = findViewById(R.id.button_test);
    mButtonTest.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            buttonTestOnClick();
        }
    });

    boolean isFirstTime = PreferenceManager.getInstances().getFirstTime();
    PreferenceManager.getInstances().setFirstTime(false);

    if (isFirstTime) {
        createKeyPair();
    }
}

private void buttonTestOnClick() {
    boolean result = initSignature();
    Log.e("iii", "Create signature result: " + result);

    boolean isFirstTime = PreferenceManager.getInstances().getFirstTime();

    if (result) {
        if (isFirstTime) {
            enroll();
        }
        startListening();
    }
}


/**
 * Generates an asymmetric key pair in the Android Keystore. Every use of the private key must
 * be authorized by the user authenticating with fingerprint. Public key use is unrestricted.
 */
public void createKeyPair() {
    try {
        mKeyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
    } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
        throw new RuntimeException("Failed to get an instance of KeyPairGenerator", e);
    }

    // The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint
    // for your flow. Use of keys is necessary if you need to know if the set of
    // enrolled fingerprints has changed.
    try {
        // Set the alias of the entry in Android KeyStore where the key will appear
        // and the constrains (purposes) in the constructor of the Builder
        mKeyPairGenerator.initialize(
                new KeyGenParameterSpec.Builder(KEY_NAME,
                        KeyProperties.PURPOSE_SIGN)
                        .setDigests(KeyProperties.DIGEST_SHA256)
                        .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
                        // Require the user to authenticate with a fingerprint to authorize
                        // every use of the private key
                        .setUserAuthenticationRequired(true)
                        .build());
        mKeyPairGenerator.generateKeyPair();
    } catch (InvalidAlgorithmParameterException e) {
        throw new RuntimeException(e);
    }
}


/**
 * Initialize the {@link Signature} instance with the created key in the
 * {@link #createKeyPair()} method.
 *
 * @return {@code true} if initialization is successful, {@code false} if the lock screen has
 * been disabled or reset after the key was generated, or if a fingerprint got enrolled after
 * the key was generated.
 */
private boolean initSignature() {
    // Create keystore
    try {
        mKeyStore = KeyStore.getInstance("AndroidKeyStore");
    } catch (KeyStoreException e) {
        throw new RuntimeException("Failed to get an instance of KeyStore", e);
    }

    // Create signature
    try {
        mSignature = Signature.getInstance("SHA256withECDSA");
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("Failed to get an instance of Signature", e);
    }


    try {
        mKeyStore.load(null);
        PrivateKey key = (PrivateKey) mKeyStore.getKey(KEY_NAME, null);
        mSignature.initSign(key);
        return true;
    } catch (KeyPermanentlyInvalidatedException e) {
        return false;
    } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
            | NoSuchAlgorithmException | InvalidKeyException e) {
        throw new RuntimeException("Failed to init Cipher", e);
    }
}


private void enroll() {
    try {
        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);
        PublicKey publicKey = keyStore.getCertificate(AuthenticateActivity.KEY_NAME).getPublicKey();
        // Provide the public key to the backend. In most cases, the key needs to be transmitted
        // to the backend over the network, for which Key.getEncoded provides a suitable wire
        // format (X.509 DER-encoded). The backend can then create a PublicKey instance from the
        // X.509 encoded form using KeyFactory.generatePublic. This conversion is also currently
        // needed on API Level 23 (Android M) due to a platform bug which prevents the use of
        // Android Keystore public keys when their private keys require user authentication.
        // This conversion creates a new public key which is not backed by Android Keystore and
        // thus is not affected by the bug.
        KeyFactory factory = KeyFactory.getInstance(publicKey.getAlgorithm());
        X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKey.getEncoded());
        PublicKey verificationKey = factory.generatePublic(spec);
        //mStoreBackend.enroll("user", "password", verificationKey);
    } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException |
            IOException | InvalidKeySpecException e) {
        e.printStackTrace();
    }
}

Но функция initSignature() всегда возвращает true.


person hoc nguyen    schedule 27.05.2018    source источник
comment
Какое устройство и версия Android? Я видел похожую проблему на Nexus 5X, но это было при удалении всех зарегистрированных отпечатков пальцев.   -  person Michael    schedule 28.05.2018
comment
У меня Асус Зенфон 3 Макс.   -  person hoc nguyen    schedule 29.05.2018
comment
У меня такая же проблема. Документация неверна или в реализации есть небольшие неизвестные детали.   -  person MatPag    schedule 28.08.2019
comment
Та же проблема, Nexus 6 Plus (SDK 26). Вы нашли какое-нибудь решение?   -  person rewgoes    schedule 07.05.2020
comment
Любое решение, которое вы найдете для этого?   -  person kgandroid    schedule 16.09.2020