Ошибка после того, как Fingerprint коснулся телефонов Samsung: android.security.KeyStoreException: ключевой пользователь не аутентифицирован

Мое приложение использует API отпечатков пальцев Android 6.0 для защиты ключа AES в Android KeyStore. Сохраненная клавиша может использоваться только тогда, когда пользователь аутентифицируется датчиком отпечатков пальцев, потому что KeyGenParameterSpec инициализируется setUserAuthenticationRequired(true).

Когда пользователь прикасается к датчику, я получаю инициализированный шифр от обратного вызова onAuthenticationSucceeded(Cipher), и я использую его для дешифрования.

Это отлично работает, за исключением телефонов Samsung с Android 6. Когда я пытаюсь использовать возвращенный Cipher, телефоны Samsung иногда бросают android.security.KeyStoreException: Key user not authenticated. Поэтому, несмотря на то, что Cipher возвращается onAuthenticationSucceeded(Cipher), Android KeyStore полагает, что пользователь не был аутентифицирован датчиком отпечатков пальцев.

Кажется, что авария происходит скорее, когда приложение не использовалось в течение более длительного времени. Когда приложение прошито, все работает нормально.

Как эта ошибка происходит случайно и только на телефонах Samsung... Кажется, это связано с некоторыми внутренними проблемами времени внутри реализации Samsung Android KeyStore Android и API FingerPrint.

Изменить. Эта проблема также наблюдалась в телефонах OnePlus и Acer.

Ответ 1

Поскольку я не ожидаю, что упомянутые производители исправят эту проблему в ближайшее время, я решил ее, установив KeyGenParameterSpec.setUserAuthenticationRequired(false) для Samsung, OnePlus, Asus и некоторых других устройств.

Ответ 2

Настройка KeyGenParameterSpec.setUserAuthenticationRequired(false) может быть потенциальной проблемой безопасности. Вышеприведенную ошибку следует обрабатывать аналогично KeyPermanentlyInvalidatedException. KeyPermanentlyInvalidatedException выбрасывается при инициализации Cipher, если после создания SecretKey добавляются новые отпечатки пальцев. Но, если Cipher инициализируется до добавления новых отпечатков пальцев, вы получите указанное выше KeyStoreException для ключевого пользователя, не прошедшего проверку подлинности, когда вы пытаетесь зашифровать или расшифровать этот шифр.    

Легко воспроизвести эту ошибку. Пока экран проверки отпечатка пальца вашего приложения находится в фоновом режиме, попробуйте добавить новый отпечаток пальца. Теперь вернитесь к приложению и введите отпечаток пальца, методы шифрования или дешифрования выбросят эту ошибку. Я мог бы решить эту проблему, поймав исключение и рассматривая его так же, как KeyPermanentlyInvalidatedException.

Ответ 3

НЕ прослушивайте "setUserAuthenticationRequired (false)"

Я смог воспроизвести это на Samsung, дважды прослушивая. Я думаю, что это происходит, вы слушаете дважды, проверяете подлинность по одному вызову, но ссылаетесь на него другим.

добавить журналы и проверить, что вы только начинаете прослушивать отпечатки пальцев один раз и один раз.

Ответ 4

У меня тоже возникла эта проблема. В моем случае это произошло из-за того, что я случайно начал две параллельные аутентификации по отпечаткам пальцев, дважды позвонив FingerprintManager.authenticate(). Ошибка исчезла после удаления второго вызова.

Ответ 5

У меня также возникла эта проблема при использовании RSA и вы могли решить ее, создав копию открытого ключа, как только я захочу зашифровать некоторые данные.

// create a copy of the public key -> workaround for android.security.KeyStoreException: Key user not authenticated
val publicKey = KeyFactory
    .getInstance("RSA")
    .generatePublic(X509EncodedKeySpec(keyPair.public.encoded))

// encrypt with the public key
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.ENCRYPT_MODE, publicKey)
val encryptedData = cipher.doFinal(data)

Ответ 6

ОБНОВЛЕНИЕ: Это известная проблема с Android 8.0 https://issuetracker.google.com/issues/65578763

Я только сейчас вижу эту ошибку на Samsung и, кажется, вызвана при добавлении нового отпечатка пальца. В нашем коде мы ожидаем, что KeyPermenantlyInvalidatedException будет генерироваться во время signature.initSign(). Этого не происходит, и инициализированная подпись успешно передается внутри CryptoObject в FingerprintManager. Затем fingerprint успешно проверяется и вызывается onAuthenticationSucceeded. Ошибка возникает при попытке вызвать signature.update(byte [] bytes).

Я предполагаю, что ожидаемое поведение заключается в том, что KeyInvalidatedException фактически генерируется, но я не уверен, что мы когда-либо сможем ожидать, что это будет решено. Мое решение состоит в том, чтобы поймать это в стороне onAuthenticationSucceeded.

@Override
    public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
        Log.d(LOG_TAG, "Device Authentication Succeeded");
        try {
            Signature signature = result.getCryptoObject().getSignature();
            String authData = getAuthData();
            signature.update(authData.getBytes());
            // do something with signature

        } catch (SignatureException e) {
            Log.d(LOG_TAG, e.getMessage());
            if(e.getMessage() != null && e.getMessage().contains("Key user not authenticated")) {
                // handle as if were KeyPermanentlyInvalidatedException
            } else {
                Log.d(LOG_TAG, e.getMessage());
                // handle as regular error
            }
        }
    }

Ответ 7

У меня также была эта проблема при использовании Samsung Galaxy S8 с Android 8. Для решения этой проблемы я просто удаляю ключ из хранилища ключей и генерирую новый, после чего использую новый ключ для шифрования и дешифрования данных.

try {
    keyStore.deleteEntry(KEY_ALIAS);
} catch (KeyStoreException e) {
    e.printStackTrace();
}

Ответ 8

Он работает на моей Samsung Galaxy S8, явно устанавливая продолжительность проверки подлинности ключа:

setUserAuthenticationValidityDurationSeconds(10);

Однако это позволяет технически использовать ключ несколько раз в течение этого промежутка времени, не требуя дополнительной аутентификации пользователя.

Лично я не думаю, что это такой большой риск.

Я не тестировал шифрование больших потоков, которые могут занять несколько секунд, чтобы завершить использование этих мер защиты. Интересно, что произойдет, если задача шифрования займет больше времени, чем позволяет срок действия.

Ответ 9

Независимо от того, случается ли это случайно из-за ошибки в Samsung или нет. Каждый раз, когда ключ недействителен, либо путем добавления нового отпечатка пальца, либо по другой причине. Следующим шагом будет удаление недействительного ключа из KeyStore с помощью KeyStore.delete(keyAlias), а также очистка старых данных, поскольку после удаления ключа шифрования нет возможности дешифровать его. Затем попросите пользователя ввести новые учетные данные и зашифровать его с помощью нового ключа. Новый ключ может иметь тот же псевдоним, что и старый. Здесь вы можете увидеть образец потока: Пример класса, который переносит поток FingerprintManager в Android

Ответ 10

Это похоже на ошибку в Android, которая возникает после обновления.

У меня это было на OnePlus. Я снял блокировку устройства из настроек и установил заново. После этого проблема исчезла.