Error after Fingerprint touched on Samsung phones: android.security.KeyStoreException: Key user not authenticated
Asked Answered
M

9

21

My app uses Android 6.0 Fingerprint API to protect AES key in the Android KeyStore. The stored key can be used only when user is authenticated by fingerprint sensor because the KeyGenParameterSpec is initialized with setUserAuthenticationRequired(true).

When the user touches the sensor I get the initialized Cipher from the callback onAuthenticationSucceeded(Cipher) and I use it for decryption.

This works perfectly except on Samsung phones with Android 6. When I try to use the returned Cipher, Samsung phones sometimes throw android.security.KeyStoreException: Key user not authenticated. So even though the Cipher is returned by the onAuthenticationSucceeded(Cipher) the Android KeyStore thinks user was NOT authenticated by the fingerprint sensor.

It seems that the crash happens rather when the app was not used for longer time. When the app is wormed up all is working correctly usually.

As this error happens randomly and only on Samsung phones... It seems it is caused by some internal timing issue inside the Samsung implementation of Android 6.0 KeyStore and FingerPrint API.

Edit: This issue was also experienced in OnePlus and Acer phones.

Magel answered 16/3, 2016 at 18:20 Comment(2)
Does it happen when the user adds new finger in device settings?Glazer
setInvalidatedByBiometricEnrollment(false) must be called to keep the key valid after new biometric is added or all biometrics are deleted. The default is true.Franks
M
2

As I don't expect that the mentioned manufacturers will fix this issue soon, I've resolved it by setting the KeyGenParameterSpec.setUserAuthenticationRequired(false) for Samsung, OnePlus, Asus and some other devices.

Magel answered 1/4, 2016 at 23:3 Comment(10)
This answer is implying that one should set user authentication requirements because it is or is not a Samsung phone. This is bad on so many levels. setUserAuthenticationRequired is a question for your security plan, not for fixing bugs.Cremona
Actually supporting fingerprint unlock on Samsung phones with Android 5 was done without the setUserAuthenticationRequired because this option is available since Android 6. And it is bad user experience when the app crashes randomly. Fix from Samsung can't be expecting soon. If you have some idea how this can be fixed write it here. I'll gladly make it the accepted solution.Magel
I don't know the answer myself, unfortunately, but I suspect it's not Samsung given that this happens on many device types. What I do know is that when encountering this error, my team found that they weren't accommodating for the fact that the devices require device authentication in some circumstances - such as if it's been 24 hours, you must enter PIN.Cremona
In fact - if that's the issue - then the question to answer may be, how does one get the user authentication when you only are dealing with fingerprints?Cremona
Last comment - I'd look over developer.android.com/reference/android/security/keystore/… carefully, and it has some links to follow with more info.Cremona
If your team solved this issue, can anyone of them publish solution here? I would appreciate it and will make it accepted solution. The error happens within few minutes and happens randomly. Nothing related to e.g. 24h interval.Magel
Well funny story, it turns out that this was a problem with Samsung 6.0.1 devices, and that we ended up just doing setUserAuthenticationRequired(false). We even had this audited by an outside security firm and there is no actual security problem unless the phone is rooted.Cremona
Somebody filed a bug over here: code.google.com/p/android/issues/detail?id=227919#makechanges. The bug should be fixed in the latest Android N security patch, however somebody else mentioned that the bug still occurs. This also doesn't fix the problem for devices that don't receive the update, so it's probably best to handle te exception.Bixler
@Bixler how would you handle the exception while still allowing things to proceed? I mean will I still get an initialized Cipher?Analysand
@JohnErnestGuadalupe I just do some default error handling and let the user try again. I think there is no other way to recover from this.Bixler
P
21

Setting KeyGenParameterSpec.setUserAuthenticationRequired(false) can be a potential security issue. The above error should be handled similar to KeyPermanentlyInvalidatedException. KeyPermanentlyInvalidatedException is thrown on Cipher initialization if new fingerprints are added after your SecretKey is created. But, if the Cipher is initialized before the new fingerprints are added, you'll get the above KeyStoreException for Key User not authenticated, when you're trying to encrypt or decrypt with that Cipher.

It's easy to reproduce this error. While your app's fingerprint verification screen is in the background, try adding a new fingerprint. Now switch back to the app, and enter the fingerprint, the encryption or decryption methods would throw this error. I could resolve this issue by catching the exception and treating it the same way as KeyPermanentlyInvalidatedException.

Percussionist answered 28/7, 2016 at 18:6 Comment(5)
This error happens randomly on Samsung phones (and some others too) while on other phones like LG it never happens. It is not comfortable for users if they have to re-authenticate for every 5th or 10th access to the app to refresh the stored password.Magel
Yeah, I see this on only Samsung devices too. But how often do people add a new fingerprint to their device? Samsung supports only 4 max. So unless somebody is playing around with their fingerprint settings a lot, it shouldn't be too bad. Do you see this error in any other case, other than adding a new fingerprint?Percussionist
Unfortunately this bug is not related to adding new fingerprint. It happens randomly.Magel
can you please explain how can we handle KeyPermanentlyInvalidatedException or provide a link where it has been handled. ThanksRegeneracy
I've been treating KeyPermanentlyInvalidatedException similar to any other fatal errors, by falling back to using password for authentication. Once the user is authenticated, a new SecretKey is generated and the data is encrypted with a Cipher that uses the new SecretKey. I'm curious to see how others are handling it, to see if there are better ways to do this.Percussionist
D
6

Do NOT listen to the "setUserAuthenticationRequired(false)"

I have been able to reproduce this on Samsung by listening twice. What I think is happening is, you listen twice, authenticate on the one call, but reference it through another.

add Logs and check that you only start listening for fingerprint once and once only.

Daggna answered 14/12, 2016 at 16:45 Comment(3)
Please not that this happens occasionally and randomly. It doesn't happen on all Samsungs always.Magel
Its definitely a race condition between listening too many times. and yes, it only happens on certain samsung phones.Daggna
I agree with some kind of race condition. With my code I'm not actually listening twice, but I had a method where I was calling initSign() to see if the signature had been invalidated, then calling initSign() again later when attempting to complete the login process.Flatways
H
4

I experienced this issue too. In my case, it was due to the fact that I was accidentally starting two concurrent fingerprint authentications by calling FingerprintManager.authenticate() twice. The error disappeared once I removed the second call.

Hosier answered 11/10, 2017 at 19:42 Comment(1)
Yes, this. Since I couldn't figure out why it was set twice. I left it as is and deployed. Funny thing, Samsung S8 crashes, Pixel2 just acts all weird on this bug. It's important to make sure you're actually correctly canceling the authentication, in my case passing around CancellationSignal object I forgot to pass the object to another class, thus was left with deaf CancellationSignalBellanca
D
4

This seems to be a bug in Android that arises after an update.

I had it on a OnePlus. I removed the device lock from the settings and set it again. After that, the issue was gone.

Dendroid answered 24/1, 2019 at 16:30 Comment(0)
F
3

UPDATE: This is a known issue with Android 8.0 https://issuetracker.google.com/issues/65578763

I'm just now seeing this error on Samsung and appears to be caused when adding a new fingerprint. In our code we expect KeyPermenantlyInvalidatedException to be thrown during signature.initSign(). This doesn't occur and the initialized signature is successfully passed inside the CryptoObject to the FingerprintManager. The fingerprint is then successfully verified and onAuthenticationSucceeded is called. The error occurs when attempting to call signature.update(byte[] bytes).

Expected behavior I would believe is that KeyInvalidatedException is actually thrown, but I'm not sure we can ever expect this to be resolved. My solution is to catch it in the onAuthenticationSucceeded side.

@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
            }
        }
    }
Flatways answered 16/10, 2018 at 19:41 Comment(0)
M
2

As I don't expect that the mentioned manufacturers will fix this issue soon, I've resolved it by setting the KeyGenParameterSpec.setUserAuthenticationRequired(false) for Samsung, OnePlus, Asus and some other devices.

Magel answered 1/4, 2016 at 23:3 Comment(10)
This answer is implying that one should set user authentication requirements because it is or is not a Samsung phone. This is bad on so many levels. setUserAuthenticationRequired is a question for your security plan, not for fixing bugs.Cremona
Actually supporting fingerprint unlock on Samsung phones with Android 5 was done without the setUserAuthenticationRequired because this option is available since Android 6. And it is bad user experience when the app crashes randomly. Fix from Samsung can't be expecting soon. If you have some idea how this can be fixed write it here. I'll gladly make it the accepted solution.Magel
I don't know the answer myself, unfortunately, but I suspect it's not Samsung given that this happens on many device types. What I do know is that when encountering this error, my team found that they weren't accommodating for the fact that the devices require device authentication in some circumstances - such as if it's been 24 hours, you must enter PIN.Cremona
In fact - if that's the issue - then the question to answer may be, how does one get the user authentication when you only are dealing with fingerprints?Cremona
Last comment - I'd look over developer.android.com/reference/android/security/keystore/… carefully, and it has some links to follow with more info.Cremona
If your team solved this issue, can anyone of them publish solution here? I would appreciate it and will make it accepted solution. The error happens within few minutes and happens randomly. Nothing related to e.g. 24h interval.Magel
Well funny story, it turns out that this was a problem with Samsung 6.0.1 devices, and that we ended up just doing setUserAuthenticationRequired(false). We even had this audited by an outside security firm and there is no actual security problem unless the phone is rooted.Cremona
Somebody filed a bug over here: code.google.com/p/android/issues/detail?id=227919#makechanges. The bug should be fixed in the latest Android N security patch, however somebody else mentioned that the bug still occurs. This also doesn't fix the problem for devices that don't receive the update, so it's probably best to handle te exception.Bixler
@Bixler how would you handle the exception while still allowing things to proceed? I mean will I still get an initialized Cipher?Analysand
@JohnErnestGuadalupe I just do some default error handling and let the user try again. I think there is no other way to recover from this.Bixler
G
2

I also had this issue when using Samsung Galaxy S8 with android 8. To solve this problem I try to remove the key from keystore and then generate a new key then I use the new generated key to encrypt and decrypt data

try {
    keyStore.deleteEntry(KEY_ALIAS);
} catch (KeyStoreException e) {
    e.printStackTrace();
}
Galantine answered 17/10, 2018 at 14:33 Comment(0)
K
1

It works on my Samsung Galaxy S8 by explicitly setting the authenticated key's validity duration:

setUserAuthenticationValidityDurationSeconds(10);

This however makes it technically possible to use the key multiple times within that timespan without requiring further user authentication.

Personally I don't think it's such a big risk.

I have not tested encrypting large streams that may take several seconds to complete using these protection measures. I wonder what happens if the encryption task takes longer than what the validity duration allows.

Kile answered 23/7, 2017 at 16:46 Comment(0)
D
1

I also had this issue when using RSA and could solve it by creating a copy of the public key as soon as i want to encrypt some data.

// 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)
Duff answered 22/12, 2017 at 12:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.