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

getGenericPassword on Android sometimes fails and crashes app #525

Open
jm90m opened this issue Jan 20, 2022 · 9 comments · May be fixed by #576
Open

getGenericPassword on Android sometimes fails and crashes app #525

jm90m opened this issue Jan 20, 2022 · 9 comments · May be fixed by #576

Comments

@jm90m
Copy link

jm90m commented Jan 20, 2022

getGenericPassword on android sometimes fails. I can't figure out why, it just crashes the app.

@kriit24
Copy link

kriit24 commented Jan 30, 2022

in my android it does not do anything code stopes on "await Keychain.getGenericPassword" and thats it

@sgal
Copy link
Contributor

sgal commented Apr 20, 2022

@jm90m @kriit24 Could you folks please share more info on your environments?
Android version, Keychain options that you pass to the getGenericPassword would help investigating the issue.

@hazim-j
Copy link

hazim-j commented Jul 19, 2022

@jm90m @kriit24 Did you manage to find a fix for this?

Getting a similar experience as well but can't seem to figure out what exactly is causing it or how to reproduce.

Only hacky workaround that I could find is if I run async code before calling getGenericPassword() that forces a state update + some delay. Otherwise app freezes until I eventually get an "App isn't responding" alert.

Example:

setLoading(true);
await delay(500);

const credentials = await Keychain.getGenericPassword();
setLoading(false);

For more context:

  • Android version 12
  • react-native-keychain version 8.1.1
  • Not passing any options to getGenericPassword

Lmk if there's any other information I can give to debug this.

@kabirbaidhya
Copy link

kabirbaidhya commented Sep 20, 2022

I've dug deeper into this issue and have been able to consistently reproduce it.

TLDR: It seems to occur when biometrics is triggered in the middle of unfinished UI navigation or rendering;
which blocks the main thread and makes the app unresponsive and eventually it crashes.

Reproduction steps:

In an Android device try these:

  1. Invoke Keychain.getGenericPassword
  2. Without awaiting the promise, close the current screen and immediately navigate to a new screen that takes some time to render i.e. contains some UI operation.
  3. When the Biometrics prompt shows up, you'll notice in the overlay that the ongoing rendering in the background is already frozen.
  4. Either fail or pass the Biometrics. Both will crash the app.

Why?

Looking through the android device logs, I've seen this occur only in cases where biometrics is triggered in the middle of navigation/rendering or when a UI operation is in-progress but not complete, and then the biometrics prompt is presented just in time.

When the prompt is presented, the underlying logic blocks the main activity thread while waiting to capture user’s biometrics and this freezes the main thread in the middle of ongoing UI operation which leads to it being unresponsive even after user’s biometrics input is done.

And once it is frozen, regardless of the result – success or failure – the app always crashes.

Additionally, it is also susceptible to race conditions which makes it harder to reproduce.
This means if the main thread UI operation completes quickly enough before the thread is frozen, it would work but otherwise, it always crashes.

Android Logs

Regular flow logs (no crash)

2022-09-19 00:22:50.226 25048-25048/com.myapp W/unknown:ReactContext: initializeMessageQueueThreads() is called.
2022-09-19 00:22:50.229 25048-25048/com.myapp D/SoLoader: libyoga.so found on /data/app/~~19AIo1aFY8KYmv5T_rODKg==/com.myapp-s7IQZfzxCAla_qyvQQRtLw==/lib/arm64
2022-09-19 00:22:50.229 25048-25048/com.myapp D/SoLoader: Not resolving dependencies for libyoga.so
2022-09-19 00:22:50.234 25048-25048/com.myapp I/DecorView: notifyKeepScreenOnChanged: keepScreenOn=false
2022-09-19 00:22:50.239 25048-25258/com.myapp I/ReactNativeJS: Running "myapp/ROUTE1" with {"initialProps":{"componentId":"myapp/ROUTE1"},"rootTag":1}
2022-09-19 00:22:50.249 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=8 res=0x1 s={true 531055612176} ch=false fn=2
2022-09-19 00:22:50.266 25048-25048/com.myapp D/PhoneWindow: forceLight changed to false [com.myapp/com.myapp.MainActivity] from com.android.internal.policy.PhoneWindow.updateForceLightNavigationBar:4319 com.android.internal.policy.PhoneWindow.setNavigationBarColor:4011 com.reactnativenavigation.utils.SystemUiUtils.setNavigationBarBackgroundColor:165 com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter.setNavigationBarBackgroundColor:232 com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter.applyNavigationBarOptions:206 
2022-09-19 00:22:50.266 25048-25048/com.myapp I/DecorView: notifyKeepScreenOnChanged: keepScreenOn=false
2022-09-19 00:22:50.278 25048-25048/com.myapp D/PhoneWindow: forceLight changed to true [com.myapp/com.myapp.MainActivity] from com.android.internal.policy.PhoneWindow.updateForceLightNavigationBar:4315 com.android.internal.policy.PhoneWindow.setNavigationBarColor:4011 com.reactnativenavigation.utils.SystemUiUtils.setNavigationBarBackgroundColor:165 com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter.setNavigationBarBackgroundColor:232 com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter.applyNavigationBarOptions:206 
2022-09-19 00:22:50.279 25048-25048/com.myapp I/DecorView: notifyKeepScreenOnChanged: keepScreenOn=false
2022-09-19 00:22:50.363 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=9 res=0x1 s={true 531055612176} ch=false fn=3
2022-09-19 00:22:50.371 25048-25048/com.myapp I/DecorView: notifyKeepScreenOnChanged: keepScreenOn=false
2022-09-19 00:22:50.410 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=14 res=0x1 s={true 531055612176} ch=false fn=4
2022-09-19 00:22:50.686 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=10 res=0x1 s={true 531055612176} ch=false fn=7
2022-09-19 00:22:50.693 25048-25048/com.myapp I/ReactNative: [GESTURE HANDLER] Initialize gesture handler for root view com.reactnativenavigation.react.ReactView{6e9054f V.E...... ......ID 0,0-1080,2154 #1}

---

2022-09-19 00:22:51.223 25048-25258/com.myapp I/ReactNativeJS: TEST --------------------------> GETTING BIOMETRICS SECRET
2022-09-19 00:22:52.276 25048-25258/com.myapp I/ReactNativeJS: TEST -> Invoking Keychain.getGenericPassword

---

2022-09-19 00:22:52.312 25048-25259/com.myapp W/CipherStorageBase: User not authenticated
    android.security.keystore.UserNotAuthenticatedException: User not authenticated
        at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
        at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:154)
        at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:345)
        at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:177)
        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.oblador.keychain.cipherStorage.CipherStorageBase$Defaults.lambda$static$1(CipherStorageBase.java:533)
        at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults$$ExternalSyntheticLambda0.initialize(Unknown Source:0)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:382)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:337)
        at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.decrypt(CipherStorageKeystoreRsaEcb.java:129)
        at com.oblador.keychain.KeychainModule.decryptToResult(KeychainModule.java:679)
        at com.oblador.keychain.KeychainModule.decryptCredentials(KeychainModule.java:646)
        at com.oblador.keychain.KeychainModule.getGenericPassword(KeychainModule.java:306)
        at com.oblador.keychain.KeychainModule.getGenericPasswordForOptions(KeychainModule.java:367)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
        at android.os.Looper.loopOnce(Looper.java:226)
        at android.os.Looper.loop(Looper.java:313)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
        at java.lang.Thread.run(Thread.java:920)
2022-09-19 00:22:52.315 25048-25259/com.myapp D/CipherStorageBase: Unlock of keystore is needed. Error: User not authenticated
    android.security.keystore.UserNotAuthenticatedException: User not authenticated
        at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
        at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:154)
        at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:345)
        at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:177)
        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.oblador.keychain.cipherStorage.CipherStorageBase$Defaults.lambda$static$1(CipherStorageBase.java:533)
        at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults$$ExternalSyntheticLambda0.initialize(Unknown Source:0)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:382)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:337)
        at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.decrypt(CipherStorageKeystoreRsaEcb.java:129)
        at com.oblador.keychain.KeychainModule.decryptToResult(KeychainModule.java:679)
        at com.oblador.keychain.KeychainModule.decryptCredentials(KeychainModule.java:646)
        at com.oblador.keychain.KeychainModule.getGenericPassword(KeychainModule.java:306)
        at com.oblador.keychain.KeychainModule.getGenericPasswordForOptions(KeychainModule.java:367)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
        at android.os.Looper.loopOnce(Looper.java:226)
        at android.os.Looper.loop(Looper.java:313)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
        at java.lang.Thread.run(Thread.java:920)


2022-09-19 00:22:52.321 25048-25259/com.myapp I/DecryptionResultHandlerInteractiveBiometric: blocking thread. waiting for done UI operation.
2022-09-19 00:22:52.575 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 0 1
2022-09-19 00:22:52.617 25048-25048/com.myapp D/InputTransport: Input channel destroyed: 'ClientS', fd=157



2022-09-19 00:22:57.978 25048-25070/com.myapp I/BiometricPrompt: onAuthenticationSucceeded: 2
2022-09-19 00:22:58.029 25048-25048/com.myapp D/InsetsSourceConsumer: ensureControlAlpha: for ITYPE_NAVIGATION_BAR on com.myapp/com.myapp.MainActivity
2022-09-19 00:22:58.030 25048-25048/com.myapp D/InsetsSourceConsumer: ensureControlAlpha: for ITYPE_STATUS_BAR on com.myapp/com.myapp.MainActivity
2022-09-19 00:22:58.045 25048-25048/com.myapp I/ViewRootImpl@5bc5c04[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 1 1
2022-09-19 00:22:58.049 25048-25048/com.myapp D/InputMethodManager: startInputInner - Id : 0
2022-09-19 00:22:58.049 25048-25048/com.myapp I/InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
2022-09-19 00:22:58.108 25048-25259/com.myapp I/DecryptionResultHandlerInteractiveBiometric: unblocking thread.


2022-09-19 00:22:58.109 25048-25258/com.myapp I/ReactNativeJS: 'TEST -> RESOLVED Keychain.getGenericPassword'
2022-09-19 00:22:58.110 25048-25258/com.myapp I/ReactNativeJS: '--------------------------> RETRIEVED BIOMETRICS SECRET', { result: 'cf86f6a6-743f-4307-b96e-eb00e2b35c7a' }

Logs during the crash

2022-09-18 23:32:22.096 11615-11615/com.myapp W/unknown:ReactContext: initializeMessageQueueThreads() is called.
2022-09-18 23:32:22.127 11615-11615/com.myapp I/ReactNative: [GESTURE HANDLER] Tearing down gesture handler registered for root view com.reactnativenavigation.react.ReactView{da7299e V.E...... ......ID 0,0-1080,2154 #51}
2022-09-18 23:32:22.129 11615-11615/com.myapp I/ReactNative: [GESTURE HANDLER] Tearing down gesture handler registered for root view com.reactnativenavigation.react.ReactView{4fcf8bb V.E...... ......ID 0,0-1080,2154 #5b}
2022-09-18 23:32:22.143 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=7 res=0x1 s={true 531055507536} ch=false fn=921
2022-09-18 23:32:22.145 11615-11826/com.myapp I/ReactNativeJS: Running "myapp/ROUTE1" with {"initialProps":{"componentId":"myapp/ROUTE1"},"rootTag":101}
2022-09-18 23:32:22.155 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=5 res=0x1 s={true 531055507536} ch=false fn=921
2022-09-18 23:32:22.188 11615-11615/com.myapp I/ReactNative: [GESTURE HANDLER] Initialize gesture handler for root view com.reactnativenavigation.react.ReactView{9a90135 V.E...... ......ID 0,0-1080,2154 #65}
2022-09-18 23:32:22.223 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=3 res=0x1 s={true 531055507536} ch=false fn=922
2022-09-18 23:32:22.234 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=5 res=0x1 s={true 531055507536} ch=false fn=923
2022-09-18 23:32:22.399 11615-11827/com.myapp D/RNKeychainManager: Probe cipher storage: CipherStorageFacebookConceal
2022-09-18 23:32:22.399 11615-11827/com.myapp D/RNKeychainManager: Probe cipher storage: CipherStorageKeystoreAesCbc
2022-09-18 23:32:22.399 11615-11827/com.myapp D/RNKeychainManager: Probe cipher storage: CipherStorageKeystoreRsaEcb
2022-09-18 23:32:22.399 11615-11827/com.myapp D/RNKeychainManager: Selected storage: CipherStorageKeystoreAesCbc
2022-09-18 23:32:22.412 11615-11827/com.myapp D/libmdf: libmdf v3.0.0.0 On 64bit PLATFORM
2022-09-18 23:32:22.611 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=9 res=0x1 s={true 531055507536} ch=false fn=945

---

2022-09-18 23:32:22.892 11615-11826/com.myapp I/ReactNativeJS: TEST --------------------------> GETTING BIOMETRICS SECRET
2022-09-18 23:32:22.918 11615-11826/com.myapp I/ReactNativeJS: TEST -> Invoking Keychain.getGenericPassword

---

2022-09-18 23:32:22.919 11615-11615/com.myapp W/unknown:ReactContext: initializeMessageQueueThreads() is called.
2022-09-18 23:32:22.919 11615-11826/com.myapp I/ReactNativeJS: Running "myapp/ROUTE2" with {"initialProps":{"componentId":"myapp/ROUTE2"},"rootTag":111}

---

2022-09-18 23:32:22.937 11615-11827/com.myapp W/CipherStorageBase: User not authenticated
    android.security.keystore.UserNotAuthenticatedException: User not authenticated
        at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
        at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:154)
        at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:345)
        at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:177)
        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.oblador.keychain.cipherStorage.CipherStorageBase$Defaults.lambda$static$1(CipherStorageBase.java:533)
        at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults$$ExternalSyntheticLambda0.initialize(Unknown Source:0)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:382)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:337)
        at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.decrypt(CipherStorageKeystoreRsaEcb.java:129)
        at com.oblador.keychain.KeychainModule.decryptToResult(KeychainModule.java:679)
        at com.oblador.keychain.KeychainModule.decryptCredentials(KeychainModule.java:646)
        at com.oblador.keychain.KeychainModule.getGenericPassword(KeychainModule.java:306)
        at com.oblador.keychain.KeychainModule.getGenericPasswordForOptions(KeychainModule.java:367)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
        at android.os.Looper.loopOnce(Looper.java:226)
        at android.os.Looper.loop(Looper.java:313)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
        at java.lang.Thread.run(Thread.java:920)
2022-09-18 23:32:22.938 11615-11827/com.myapp D/CipherStorageBase: Unlock of keystore is needed. Error: User not authenticated
    android.security.keystore.UserNotAuthenticatedException: User not authenticated
        at android.security.keystore2.KeyStoreCryptoOperationUtils.getInvalidKeyException(KeyStoreCryptoOperationUtils.java:128)
        at android.security.keystore2.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:154)
        at android.security.keystore2.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:345)
        at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:177)
        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.oblador.keychain.cipherStorage.CipherStorageBase$Defaults.lambda$static$1(CipherStorageBase.java:533)
        at com.oblador.keychain.cipherStorage.CipherStorageBase$Defaults$$ExternalSyntheticLambda0.initialize(Unknown Source:0)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:382)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.decryptBytes(CipherStorageBase.java:337)
        at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.decrypt(CipherStorageKeystoreRsaEcb.java:129)
        at com.oblador.keychain.KeychainModule.decryptToResult(KeychainModule.java:679)
        at com.oblador.keychain.KeychainModule.decryptCredentials(KeychainModule.java:646)
        at com.oblador.keychain.KeychainModule.getGenericPassword(KeychainModule.java:306)
        at com.oblador.keychain.KeychainModule.getGenericPasswordForOptions(KeychainModule.java:367)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188)
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
        at android.os.Looper.loopOnce(Looper.java:226)
        at android.os.Looper.loop(Looper.java:313)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)
        at java.lang.Thread.run(Thread.java:920)

2022-09-18 23:32:22.940 11615-11827/com.myapp I/DecryptionResultHandlerInteractiveBiometric: blocking thread. waiting for done UI operation.
2022-09-18 23:32:23.035 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=9 res=0x1 s={true 531055507536} ch=false fn=961
2022-09-18 23:32:23.072 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)0 dur=9 res=0x1 s={true 531055507536} ch=false fn=962
2022-09-18 23:32:23.251 11615-11615/com.myapp I/ViewRootImpl@45495ed[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 0 1
2022-09-18 23:32:23.289 11615-11615/com.myapp D/InputTransport: Input channel destroyed: 'ClientS', fd=215

2022-09-18 23:32:26.715 11615-11899/com.myapp I/BiometricPrompt: onAuthenticationSucceeded: 2
2022-09-18 23:32:37.423 11615-11620/com.myapp I/com.myapp: Thread[4,tid=11620,WaitingInMainSignalCatcherLoop,Thread*=0x7b956236a0,peer=0x15f00228,"Signal Catcher"]: reacting to signal 3
2022-09-18 23:32:37.423 11615-11620/com.myapp I/com.myapp: 
2022-09-18 23:32:37.846 11615-11620/com.myapp I/com.myapp: Wrote stack traces to tombstoned

You can see in that there are 2 main differences in the above logs:

  1. In both cases, onAuthenticationSucceeded handler was triggered. But in the second case, you cannot see the thread being unblocked after that. The entry unblocking thread. is seen only in the first case.
  2. In the second case you can see a UI rendering started right after the getGenericPassword call from this line ReactContext: initializeMessageQueueThreads() is called. This is the cause of this unresponsiveness as the main thread didn't get chance to complete it before it was blocked.

@alex-tsx
Copy link

alex-tsx commented Jan 18, 2023

Same problem occurs in our app on Android. No particular version - seems to occur on any device.

We reproduce it like so:

import Keychain from 'react-native-keychain';

async function getBiometryPassword() {
   console.log(1);

   /*
   // Optionally, we can block the thread for a couple of seconds,
   // just to not have to be quick with minimizing the app.

   const start = Date.now();
   while (Date.now() < start + 2000) {}
   console.log(2);
   */
    
   const value = await Keychain.getGenericPassword({
      service: 'our-bio-password-key',
      accessible: Keychain.ACCESSIBLE.WHEN_PASSCODE_SET_THIS_DEVICE_ONLY,
      securityLevel: Keychain.SECURITY_LEVEL.SECURE_HARDWARE,
      accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET,
      authenticationType: Keychain.AUTHENTICATION_TYPE.BIOMETRICS
   }).catch(error => {
      console.log(3);
      throw error;
   });
   
   console.log(4);
   
   return value;
}

If you start the app, call getBiometryPassword and immediately minimize the app (gotta be quick), then open back, you get only 1 & 2(optionally) printed to the console, and the app is frozen.

Also, we don't get app state change event fired (handleAppStateChange called) in this case.

import { AppState } from 'react-native';

AppState.addEventListener('change', handleAppStateChange);

@tsdmrfth
Copy link

I'm having the same issue. As soon as I call getGenericPassword the app freezes and a few seconds later "App not responding" pop-up shows up! This is a serious issue guys!

@BraveEvidence
Copy link

This will help https://www.youtube.com/watch?v=J0OSn7s9YiA&list=PLQhQEGkwKZUrempLnmxjt7ZCZJu1W3p2i&index=15

@tsdmrfth
Copy link

@BraveEvidence Thanks, I'll take a look at it for sure but the thing is I had to prepare a release for pen-testing so wouldn't have time to deal with this stuff :/ thanks to @hazim-j the solution he found worked for me!

@rbansal-snap
Copy link

@tsdmrfth what was the fix ?

@ShepSims
Copy link

ShepSims commented Nov 7, 2023

This is happening for me as well - dev and prod - unsure of what the conditions are, but it typically seems to hang most if called relatively quickly after an app background -> foreground . Killing the app and restarting always fixes the issue.

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

Successfully merging a pull request may close this issue.

10 participants