epicshaggy / capacitor-native-biometric

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Keystore key generation failed

RRGT19 opened this issue · comments

Description:

Using Firebase Crashlytics I have a lot of errors about Keystore key generation failed.

Library version:

"capacitor-native-biometric": "^4.2.2"

Platforms:

  • Android 12
  • Android 13

Devices:

  • Redmi 10 2022
  • Galaxy A02s
  • Galaxy A03 Core
  • Galaxy A11
  • Galaxy A13
  • Galaxy A51
  • Galaxy A22
  • Galaxy S21 Ultra 5G
  • Galaxy Z Flip5
  • LG V60 ThinQ
  • etc...

Exception:

Fatal Exception: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
       at com.getcapacitor.Bridge.lambda$callPluginMethod$0(Bridge.java:783)
       at com.getcapacitor.Bridge.$r8$lambda$ehFTi5f4HhVNFKTbCKAYDkpQYRA()
       at com.getcapacitor.Bridge$$ExternalSyntheticLambda3.run(:8)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:211)
       at android.os.Looper.loop(Looper.java:300)
       at android.os.HandlerThread.run(HandlerThread.java:67)


Caused by java.security.ProviderException: Keystore key generation failed
       at android.security.keystore2.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:413)
       at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:612)
       at com.epicshaggy.biometric.NativeBiometric.generateKey(NativeBiometric.java:313)
       at com.epicshaggy.biometric.NativeBiometric.generateKey(NativeBiometric.java:295)
       at com.epicshaggy.biometric.NativeBiometric.getKey(NativeBiometric.java:324)
       at com.epicshaggy.biometric.NativeBiometric.encryptString(NativeBiometric.java:265)
       at com.epicshaggy.biometric.NativeBiometric.setCredentials(NativeBiometric.java:178)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:138)
       at com.getcapacitor.Bridge.lambda$callPluginMethod$0(Bridge.java:774)
       at com.getcapacitor.Bridge.$r8$lambda$ehFTi5f4HhVNFKTbCKAYDkpQYRA()
       at com.getcapacitor.Bridge$$ExternalSyntheticLambda3.run(:8)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:211)
       at android.os.Looper.loop(Looper.java:300)
       at android.os.HandlerThread.run(HandlerThread.java:67)


Caused by android.security.KeyStoreException: System error
       at android.security.KeyStore2.getKeyStoreException(KeyStore2.java:334)
       at android.security.KeyStoreSecurityLevel.handleExceptions(KeyStoreSecurityLevel.java:57)
       at android.security.KeyStoreSecurityLevel.generateKey(KeyStoreSecurityLevel.java:145)
       at android.security.keystore2.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:400)
       at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:612)
       at com.epicshaggy.biometric.NativeBiometric.generateKey(NativeBiometric.java:313)
       at com.epicshaggy.biometric.NativeBiometric.generateKey(NativeBiometric.java:295)
       at com.epicshaggy.biometric.NativeBiometric.getKey(NativeBiometric.java:324)
       at com.epicshaggy.biometric.NativeBiometric.encryptString(NativeBiometric.java:265)
       at com.epicshaggy.biometric.NativeBiometric.setCredentials(NativeBiometric.java:178)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:138)
       at com.getcapacitor.Bridge.lambda$callPluginMethod$0(Bridge.java:774)
       at com.getcapacitor.Bridge.$r8$lambda$ehFTi5f4HhVNFKTbCKAYDkpQYRA()
       at com.getcapacitor.Bridge$$ExternalSyntheticLambda3.run(:8)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:211)
       at android.os.Looper.loop(Looper.java:300)
       at android.os.HandlerThread.run(HandlerThread.java:67)

Code:

const KEYSTORE_ALIAS = 'my-app-name';

setCredentials(credentials: Credentials): void {
      const {username, password} = credentials;
      this.deleteCredentials()
        .then(() => NativeBiometric.setCredentials({username, password, server: KEYSTORE_ALIAS}));
}

private deleteCredentials(): Promise<void> {
    return NativeBiometric.deleteCredentials({server: KEYSTORE_ALIAS});
}

Conclusion:

Any advice or a fix would be appreciated.

After some debugging turns out that this exception is cause when the device has not configured any biometrics. We forgot to also check if it's enabled before trying to save the credentials.

Still, I understand that the generateKey method should return an error that can be trapped inside the catch instead of crashing the app.

I have a similar problem on my Google Pixel 7, using Capacitor v5. I noticed that if I unlock the phone using face unlock, I can't use my fingerprint to log into the app. When I unlock the phone using my fingerprint or pin, the app authentication works fine.

It was fine in previous Capacitor version (v4)

Any solutions?

Thanks!

We're running into the same problem. Here's another stack trace we're seeing on some devices:

09-18 20:46:07.940 E/AndroidRuntime(24230): FATAL EXCEPTION: CapacitorPlugins
09-18 20:46:07.940 E/AndroidRuntime(24230): Process: com.germania.mobile.app, PID: 24230
09-18 20:46:07.940 E/AndroidRuntime(24230): java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.getcapacitor.Bridge.lambda$callPluginMethod$0$com-getcapacitor-Bridge(Bridge.java:770)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.getcapacitor.Bridge$$ExternalSyntheticLambda5.run(Unknown Source:8)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.os.Handler.handleCallback(Handler.java:942)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.os.Handler.dispatchMessage(Handler.java:99)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.os.Looper.loopOnce(Looper.java:240)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.os.Looper.loop(Looper.java:351)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.os.HandlerThread.run(HandlerThread.java:67)
09-18 20:46:07.940 E/AndroidRuntime(24230): Caused by: java.lang.reflect.InvocationTargetException
09-18 20:46:07.940 E/AndroidRuntime(24230):  at java.lang.reflect.Method.invoke(Native Method)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.getcapacitor.PluginHandle.invoke(PluginHandle.java:138)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.getcapacitor.Bridge.lambda$callPluginMethod$0$com-getcapacitor-Bridge(Bridge.java:761)
09-18 20:46:07.940 E/AndroidRuntime(24230):  ... 6 more
09-18 20:46:07.940 E/AndroidRuntime(24230): Caused by: java.security.ProviderException: Keystore key generation failed
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.security.keystore2.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:413)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:612)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.epicshaggy.biometric.NativeBiometric.generateKey(NativeBiometric.java:313)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.epicshaggy.biometric.NativeBiometric.generateKey(NativeBiometric.java:295)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.epicshaggy.biometric.NativeBiometric.getKey(NativeBiometric.java:324)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.epicshaggy.biometric.NativeBiometric.encryptString(NativeBiometric.java:265)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at com.epicshaggy.biometric.NativeBiometric.setCredentials(NativeBiometric.java:178)
09-18 20:46:07.940 E/AndroidRuntime(24230):  ... 9 more
09-18 20:46:07.940 E/AndroidRuntime(24230): Caused by: android.security.KeyStoreException: System error (internal Keystore code: 4 message: In generate_key.
09-18 20:46:07.940 E/AndroidRuntime(24230): 
09-18 20:46:07.940 E/AndroidRuntime(24230): Caused by:
09-18 20:46:07.940 E/AndroidRuntime(24230):     0: In store_new_key.
09-18 20:46:07.940 E/AndroidRuntime(24230):     1: In store_new_key. Failed to handle super encryption.
09-18 20:46:07.940 E/AndroidRuntime(24230):     2: In handle_super_encryption_on_key_init: User ECDH key missing.
09-18 20:46:07.940 E/AndroidRuntime(24230):     3: Error::Rc(ResponseCode(4))) (public error code: 4 internal Keystore code: 4)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.security.KeyStore2.getKeyStoreException(KeyStore2.java:336)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.security.KeyStoreSecurityLevel.handleExceptions(KeyStoreSecurityLevel.java:57)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.security.KeyStoreSecurityLevel.generateKey(KeyStoreSecurityLevel.java:145)
09-18 20:46:07.940 E/AndroidRuntime(24230):  at android.security.keystore2.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:400)
09-18 20:46:07.940 E/AndroidRuntime(24230):  ... 15 more

Further testing on many other devices reveals the following facts:

  • Android 12 and 13 on real devices: crashes
  • Android 12 and 13 on simulator: does not crash
  • Android 14 beta: does not crash

I ended up refactoring the Android support to use EncryptedSharedPreferences. That seems to resolve the issue. See #103.