Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authenticated Option on Samsung device throws Exception #12

Closed
html-rulez-d00d opened this issue Nov 16, 2020 · 28 comments
Closed

Authenticated Option on Samsung device throws Exception #12

html-rulez-d00d opened this issue Nov 16, 2020 · 28 comments

Comments

@html-rulez-d00d
Copy link

Greetings and thank you for creating this plugin!

I was able to get your example working (v1.1.0+1) while using the Biometric Authenticated option on my iPhone X (14.2) and my Pixel 3 (Android 11) just fine but on my Samsung S8+ (Android 9, One UI 1.0) when I write, it throws the following exception:

java.security.KeyStoreException: the master key android-keystore://default_authenticated_master_key exists but is unusable
java.security.KeyStoreException: the master key android-keystore://default_authenticated_master_key exists but is unusable
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewMasterKey(AndroidKeysetManager.java:268)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:228)
at androidx.security.crypto.EncryptedFile$Builder.build(EncryptedFile.java:200)
at design.codeux.biometric_storage.BiometricStorageFile.buildEncryptedFile(BiometricStorageFile.kt:67)
at design.codeux.biometric_storage.BiometricStorageFile.writeFile(BiometricStorageFile.kt:73)
at design.codeux.biometric_storage.BiometricStoragePlugin$onMethodCall$8$1.invoke(BiometricStoragePlugin.kt:195)
at design.codeux.biometric_storage.BiometricStoragePlugin$onMethodCall$8$1.invoke(BiometricStoragePlugin.kt:76)
at design.codeux.biometric_storage.BiometricStoragePlugin$onMethodCall$4$1.invoke(BiometricStoragePlugin.kt:159)
at design.codeux.biometric_storage.BiometricStoragePlugin$onMethodCall$4$1.invoke(BiometricStoragePlugin.kt:76)
at design.codeux.biometric_storage.BiometricStoragePlugin$authenticate$prompt$1$onAuthenticationSucceeded$$inlined$ui$1.run(BiometricStoragePlugin.kt:290)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7073)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
Caused by: android.security.keystore.UserNotAuthenticatedException: User not authenticated
at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1233)
at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1331)
at android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(KeyStoreCryptoOperationUtils.java:54)
at android.security.keystore.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:89)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:265)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:109)
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2984)
at javax.crypto.Cipher.tryCombinations(Cipher.java:2891)
at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2796)
at javax.crypto.Cipher.chooseProvider(Cipher.java:773)
at javax.crypto.Cipher.init(Cipher.java:1143)
at javax.crypto.Cipher.init(Cipher.java:1084)
at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.encrypt(AndroidKeystoreAesGcm.java:69)
at com.google.crypto.tink.integration.android.AndroidKeystoreKmsClient.validateAead(AndroidKeystoreKmsClient.java:226)
at com.google.crypto.tink.integration.android.AndroidKeystoreKmsClient.getAead(AndroidKeystoreKmsClient.java:160)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewMasterKey(AndroidKeysetManager.java:259)
... 16 more

Please advise.

@P-Jay357
Copy link

P-Jay357 commented Nov 24, 2020

Hello, I've not been getting all those exceptions, but when I try to use the Write function it does throw this:

AuthException (code: AuthExceptionCode.unknown, message: Unexpected authentication error. the master key android-keystore://biometrics_master_key exists but is unusable).

This is occurs on my emulators and my physical phone (all using Android).

@P-Jay357
Copy link

I have just checked and I get this same issue with the example app after trying to use all of the write options, apart for the Unauthenticated option.

@rokk4
Copy link

rokk4 commented Feb 19, 2021

@html-rulez-d00d @P-Jay357
Found any news on this?
I have also seen this occasionally on the emulator.

@html-rulez-d00d
Copy link
Author

@rokk4 I have since moved on from this plugin, which is a shame since it's exactly what I wanted, minus the inconsistency with Samsung devices. I now use local_auth and flutter_secure_storage (3.3.2 since newer versions have issues) begrudgingly, since that flow is less secure.

@hpoul
Copy link
Collaborator

hpoul commented Feb 20, 2021

If anyone has a way to fix this let me know, not for me in samsung s9+ everything seems fine.. and imho the api calls are all used according to the documentation

@dmotte
Copy link

dmotte commented Feb 21, 2021

First of all, congrats for this wonderful app!! 😄

I also have this problem. I attach some screenshots for help.

My phone is a Xiaomi Mi A1 (Android 9 Pie)

Screenshot_20210221-221509
Screenshot_20210221-221516
Screenshot_20210221-221521

@dmotte
Copy link

dmotte commented Feb 21, 2021

Note: if i uncheck the "Save Password with biometric key store?" option it works.

@P-Jay357
Copy link

The issue occurs on my Huawei P9, and different emulators as well.
It's the same issue that @dmotte shows with his screenshots and the above note.

@rokk4
Copy link

rokk4 commented Feb 22, 2021

https://issuetracker.google.com/issues/176215143
This seems to be it, but I could not get new insights from the google tracker.

Some folks on SO found out it is somehow related to android:allowBackup
https://stackoverflow.com/questions/65463893/getting-keystoreexception-and-generalsecurityexception-by-using-encryptedsharedp

@dmotte
Copy link

dmotte commented Feb 22, 2021

It would be nice at least to add an option in the settings page to disable the Save Password with biometric key store? prompt permanently, because now i have to manually uncheck it every time i access my kdbx database 😅

I dont want to use biometrics. It's ok for me to enter my password each time i login, but unchecking that checkbox manually is a bit annoying

@rokk4
Copy link

rokk4 commented Feb 22, 2021

@Flajt
Copy link

Flajt commented Mar 11, 2021

Hello everyone, I got the same issue as well on a Samsung A51 with the use of FaceID.
I tried @rokk4 Stack Overflow link in combination with this one, apparently one of the packages I used had android:allowBackup set to true. Didn't change anything, the error still persists, are there any workarounds ?
My Plugin version is: 1.1.0+1 (due to null safety migration, which I haven't implemented yet), might that be a part of the issue?

@petro-i
Copy link

petro-i commented Mar 30, 2021

same problem on Samsung Galaxy S10Lite - FaceID is unusable due to this error.
Would be nice to have an option to disable FaceID on Android )) , but use only fingerprint in this plugin.

@hpoul
Copy link
Collaborator

hpoul commented Aug 10, 2021

I have just pushed a complete reimplementation how the encryption works, by directly using the underlying android.security API (and javax.crypto) instead of androidx.security, which should solve this problem.
Although I think the underlying problem was actually that the plugin allowed BIOMETRIC_WEAK - so now BIOMETRIC_STRONG is enforced (hence i think no more FaceID 🤔️ @petro-i )
And since we now have control over the Cipher and CryptoObject it finally works to use authenticationValidityDurationSeconds = -1 (ie. require authentication prompt for every access).

Maybe somebody could give it a try if anything still works? 😅️

(Since this uses a completely different set of keys, old data would be lost. Right now there is a fallback which tries to use the old decryption methods if old data is still around, but the end goal would be to remove the whole androidx.securit nonsense together with the whole host of dependencies)

@P-Jay357
Copy link

P-Jay357 commented Aug 16, 2021

Hi, thanks for replying and reimplementing the package!
Everything works fine now, apart for if I press the cancel button on Android (not sure if it happens on iOS as I don't have an apple device to test with) it throws an AuthException (this is when using the example code, but I removed the logging sections):

AuthException{code: AuthExceptionCode.unknown, message: Cancel}

0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:597:7)
1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:158:18)
<asynchronous suspension>
2 StorageActions.build. (PLACE IN APP WHERE storageFile.read() OR storageFile.write() IS CALLED)
<asynchronous suspension>

The message parameter of the AuthException is the value of the AndroidPromptInfo "negativeButton" parameter.
It seems to still try and read/write the encrypted file even f you press the cancel button, rather than just cancel the authentication, and close the fingerprint dialog.

If I press the back button on my device instead when the fingerprint dialog is showing I get a similar error, but this time the code is "AuthExceptionCode.userCanceled" and the message is "Fingerprint operation cancelled by user"

This is while using the 3.0.0-rc.9 pre-release version of the package.

@P-Jay357
Copy link

Also, I'm not sure if it's anything you have control of, but the negativeButton text is black, and the fingerprint dialog is a dark grey.

Do we have anyway of choosing the colours of the dialog?

I have noticed that on an Android emulator the fingerprint dialog has a white background, but on my phone it's the dark grey. The emulator is on android 10 though and my phone is using Android 7

@hpoul
Copy link
Collaborator

hpoul commented Aug 16, 2021

thanks for testing..

when you press cancel (or pressing back button) AuthExceptionCode.userCanceled would be the expected result. I'll check if I can reproduce that problem.

Do we have anyway of choosing the colours of the dialog?

no, not directly at least. It is a native android dialog which is provided by the system. Although with googling it seems the application can customize the theme: https://stackoverflow.com/a/57429163/109219 so it might be a problem with the example app.. But I don't think the plugin could change this.

@hpoul
Copy link
Collaborator

hpoul commented Aug 16, 2021

@P-Jay357 fyi, i've now fixed the userCanceled code - on android pressing the cancel button produced a ERROR_NEGATIVE_BUTTON error code.

I also can't reproduce your android 7 problem. I've tried the simulator and it seems to work.. It might have to do with your specific android device. But again, I doubt this is something which the plugin can change anyway.

Screen Shot 2021-08-16 at 20 23 21

@P-Jay357
Copy link

Awesome! Thanks for having a look.
Yeah, it definitely looks like a theme issue on my end, and not to do with the package!

@P-Jay357
Copy link

P-Jay357 commented Aug 17, 2021

Hi, I think I've found another bug. Sorry!
If you set androidBiometricOnly to false and don't have a newer device you get this error:

PlatformException(Unexpected Error, Crypto-based authentication is not supported for device credential prior to API 30., java.lang.IllegalArgumentException: Crypto-based authentication is not supported for device credential prior to API 30.
java.lang.IllegalArgumentException: Crypto-based authentication is not supported for device credential prior to API 30.
at androidx.biometric.BiometricPrompt.authenticate(BiometricPrompt.java:954)
at design.codeux.biometric_storage.BiometricStoragePlugin.authenticate(BiometricStoragePlugin.kt:287)
at design.codeux.biometric_storage.BiometricStoragePlugin.onMethodCall$withAuth(BiometricStoragePlugin.kt:166)
at design.codeux.biometric_storage.BiometricStoragePlugin.access$onMethodCall$withAuth(BiometricStoragePlugin.kt:88)
at design.codeux.biometric_storage.BiometricStoragePlugin$onMethodCall$5.invoke(BiometricStoragePlugin.kt:202)
at design.codeux.biometric_storage.BiometricStoragePlugin$onMethodCall$5.invoke(BiometricStoragePlugin.kt:202)
at design.codeux.biometric

It happens if I press the write or read buttons of the test code that have authentication.

This occurs when running the app on my phone which is on Android 7.

If it's set to true then it works as intended.

@hpoul
Copy link
Collaborator

hpoul commented Aug 17, 2021

I don't really think this is a bug. Maybe needs some more documentation. But the caller probably has to decide what is the preferable fix.. this is not something the plugin can take a guess on..
either setting androidBiometricOnly to true.. or changing authenticationValidityDurationSeconds to > 0 seconds.. as far as I understand it at least.. can you try changing authenticationValidityDurationSeconds back to 30 or something?

@P-Jay357
Copy link

If I set authenticationValidityDurationSeconds to > 0 seconds, I get an AuthException:

AuthException{code: AuthExceptionCode.unknown, message: Unexpected authentication error. null}

If androidBiometricOnly is true though then everything seems ok.

@hpoul
Copy link
Collaborator

hpoul commented Aug 18, 2021

@P-Jay357 ok, i've now just implemented that androidBiometricOnly will be ignored prior to 30 .. not sure if that works.. imho this is a pretty useless feature anyway :-) (fwiw I didn't test it.. so if you've got some time.. maybe you could 😅️) 05d2084

@P-Jay357
Copy link

Hi!

I've just tested the new version and no longer get the error :)

@P-Jay357
Copy link

I've found another error similar to the AuthExceptionCode.userCanceled one where it was originally an AuthExceptionCode.unknown error.

If you have the Biometric prompt dialog showing and exit the app and then go back to it, this error is thrown:

AuthException{code: AuthExceptionCode.unknown, message: Fingerprint operation cancelled.}

I believe the ideal behaviour would be that the dialog does not close when you go back onto the app, but if that's not the case then could you set the error code to be AuthExceptionCode.userCanceled

@hpoul
Copy link
Collaborator

hpoul commented Aug 19, 2021

well the android side already handled it, but the dart side ignored it.. I didn't quite know when this error was actually triggered. I don't think userCanceled would be a good translation, on android it's called ERROR_CANCELED.. i've introduced a separate AuthExceptionCode.canceled.

@hpoul
Copy link
Collaborator

hpoul commented Aug 20, 2021

fyi, i've now released -rc.11 as 3.0.0 .. i think it should work much better than the old version 🤞 If there are still problems, open another issue, thanks.

@hpoul hpoul closed this as completed Aug 20, 2021
@hpoul
Copy link
Collaborator

hpoul commented Aug 20, 2021

@P-Jay357 ok, i've now just implemented that androidBiometricOnly will be ignored prior to 30 .. not sure if that works.. imho this is a pretty useless feature anyway :-) (fwiw I didn't test it.. so if you've got some time.. maybe you could 😅️) 05d2084

omfg, it seems this is even more complicated than this.. because when authenticationValidityDurationSeconds == -1 then the androidBiometricOnly must always be true:

Cryptographic operations involving keys which require user authentication to take place for every operation can only use biometric authentication

https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.Builder#:~:text=Cryptographic%20operations%20involving,authentication%20flow%20succeeds.

Screen Shot 2021-08-20 at 10 12 34

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants