react-native-keychain icon indicating copy to clipboard operation
react-native-keychain copied to clipboard

getGenericPassword is too slow on android 10

Open sm2017 opened this issue 4 years ago • 77 comments

I have slow startup on android 10 , After checking , I understand that getGenericPassword methods takes 7-8 seconds on android 10 I run on android 7 and 6 too , It takes about 600-700ms

sm2017 avatar May 02 '20 10:05 sm2017

I downgraded to v4.0.5 , it is fast on android 10 , just 30ms

sm2017 avatar May 02 '20 11:05 sm2017

react-native-keychain: 6.0.0 react-native: 0.62.2

Same issue for me. In Simulator (API28) and on a Huawei P30 Pro (API29) it works super fast, on a Samsung SM-J730F (API28) it takes way beyond 10 seconds sometimes and fails with following exception. I experience it only happening the very first time after installing the app or wiping app data.

2020-05-04 15:31:18.866 30385-30539/? W/CipherStorageBase: StrongBox security storage is not available.
    android.security.keystore.StrongBoxUnavailableException: Failed to generate key pair
        at android.security.keystore.AndroidKeyStoreKeyPairGeneratorSpi.generateKeystoreKeyPair(AndroidKeyStoreKeyPairGeneratorSpi.java:554)
        at android.security.keystore.AndroidKeyStoreKeyPairGeneratorSpi.generateKeyPair(AndroidKeyStoreKeyPairGeneratorSpi.java:499)
        at java.security.KeyPairGenerator$Delegate.generateKeyPair(KeyPairGenerator.java:727)
        at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.generateKey(CipherStorageKeystoreRsaEcb.java:256)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.tryGenerateStrongBoxSecurityKey(CipherStorageBase.java:444)
        at com.oblador.keychain.cipherStorage.CipherStorageBase.generateKeyAndStoreUnderAlias(CipherStorageBase.java:391)
        at com.oblador.keychain.KeychainModule.internalWarmingBestCipher(KeychainModule.java:171)
        at com.oblador.keychain.KeychainModule.lambda$NuQDyTTfZc67dTNiVeEDbYNRCJw(Unknown Source:0)
        at com.oblador.keychain.-$$Lambda$KeychainModule$NuQDyTTfZc67dTNiVeEDbYNRCJw.run(Unknown Source:2)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: android.security.KeyStoreException: No StrongBox available
        at android.security.keystore.AndroidKeyStoreKeyPairGeneratorSpi.generateKeystoreKeyPair(AndroidKeyStoreKeyPairGeneratorSpi.java:554) 
        at android.security.keystore.AndroidKeyStoreKeyPairGeneratorSpi.generateKeyPair(AndroidKeyStoreKeyPairGeneratorSpi.java:499) 
        at java.security.KeyPairGenerator$Delegate.generateKeyPair(KeyPairGenerator.java:727) 
        at com.oblador.keychain.cipherStorage.CipherStorageKeystoreRsaEcb.generateKey(CipherStorageKeystoreRsaEcb.java:256) 
        at com.oblador.keychain.cipherStorage.CipherStorageBase.tryGenerateStrongBoxSecurityKey(CipherStorageBase.java:444) 
        at com.oblador.keychain.cipherStorage.CipherStorageBase.generateKeyAndStoreUnderAlias(CipherStorageBase.java:391) 
        at com.oblador.keychain.KeychainModule.internalWarmingBestCipher(KeychainModule.java:171) 
        at com.oblador.keychain.KeychainModule.lambda$NuQDyTTfZc67dTNiVeEDbYNRCJw(Unknown Source:0) 
        at com.oblador.keychain.-$$Lambda$KeychainModule$NuQDyTTfZc67dTNiVeEDbYNRCJw.run(Unknown Source:2) 
        at java.lang.Thread.run(Thread.java:764) 

patrickschmelter avatar May 04 '20 14:05 patrickschmelter

I can confirm that downgrading to 4.0.5 solves the issue. Maybe linked to #314

patrickschmelter avatar May 04 '20 14:05 patrickschmelter

@oblador @vonovak take a look please

sm2017 avatar May 05 '20 05:05 sm2017

@oblador @vonovak reply please

sm2017 avatar May 11 '20 09:05 sm2017

@sm2017 given more than one person is seeing this, I guess the issue is indeed present. I'm dealing with other stuff now and this is not a priority for me.

Cc @OleksandrKucherenko as he might have more insight.

As always, if you have an issue, I recommend you contribute a PR with a fix. Thank you!

vonovak avatar May 11 '20 09:05 vonovak

We've also found the same - downgraded has solved it - thanks for spotting this @sm2017 !

tommeier avatar May 18 '20 07:05 tommeier

Did a bit of digging - KeystoreAESCBC seems to be very slow when running CipherStorageBase#extractKey, specifically when doing keyStore.getKey(safeAlias, null). I'm not too sure why there is a slowdown between 4.0.5 and 6.0.0 yet, because they seem to do roughly the same thing when encrypting/decrypyting for storage.

deecewan avatar May 18 '20 12:05 deecewan

from 4.0.5:

// CipherStorageKeystoreAESCBC.java line 101
key = keyStore.getKey(service, null);
// 5ms average over 5 runs

from 6.0.0

// CipherStorageBase.java line 234
key = keyStore.getKey(safeAlias, null);
// 3637ms average over 5 runs

Measurements taken using System.nanoTime() right before/after the call. Samsung Galaxy S10+, running Android 10.

Edit: yup, i'm stumped. The only thing that looks different is that there is now a cache on the keystore (https://github.com/oblador/react-native-keychain/blob/e6090b2966a0965b9326da44f849978c50e6fe2a/android/src/main/java/com/oblador/keychain/cipherStorage/CipherStorageBase.java#L282) whereas that didn't used to be there

Edit edit: Tried making it not a cached instance, tho i am not sure quite how or why that would fix it. It didn't fix it. So it seems that the same method call is taking longer, when the only variable is the package version 😅

Edit: looking into this on a bit further, based on @patrickschmelter's comment. Looking in the android source, it seems like StrongBox is not available on the particular hardware. and throwing early in the tryGenerateStrongBoxSecurityKey (before actually attempting to generate the key) makes the behaviour fast again.

OK. Looks like that's a bit of a red herring. I've been playing around a lot and it seems like the "warm up" happens, and it also gets stuck. Until a log line appears that says CertificatePolicyCache: Creating new instance of CertificatePolicyCache. Then that completes, and it seems to work fast again. Googling around for CertificatePolicyCache doesn't really yield any results 😞.

Final edit for a while: seems like the new RSA type is what's doing it. There seems to be a lock involved, and the system hangs until it's ready. I managed to get the setGenericPassword to work fairly quickly by explicitly setting storage: Keychain.STORAGE_TYPE.AES,, but unfortunately the getGenericPassword is still slow 😞

deecewan avatar May 18 '20 12:05 deecewan

@oblador @vonovak sorry for mention , As I am not an Android developer , I cannot fix this problem and make a PR I think @deecewan's comment can help to fix it , Please take a look again

sm2017 avatar May 27 '20 05:05 sm2017

Possible optimization:

boolean hasStrongBox() {
       return mActivity.getPackageManager()
           .hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
}

Instead of trying and catching the exception we can check the hardware features availability.

src: https://stackoverflow.com/questions/58502299/how-to-check-for-strongbox-keymaster-hardware-availability-before-key-generation

OleksandrKucherenko avatar May 27 '20 07:05 OleksandrKucherenko

@OleksandrKucherenko I tried doing that, too, and it was not noticeably quicker. There is a good chance that I got it mixed up with other tests I was trying, tho.

deecewan avatar May 27 '20 22:05 deecewan

https://github.com/oblador/react-native-keychain/compare/master...OleksandrKucherenko:fix-storngbox-detect?expand=1

quick implementation... I don't think it will improve anything significantly, but it's a good code to have in lib.

OleksandrKucherenko avatar May 28 '20 06:05 OleksandrKucherenko

@sm2017 @patrickschmelter @deecewan @tommeier @vonovak

Gentlemen, I need your help to reproduce this issue. Since it happens only on specific combination of phone and Android version, I need to know what exactly you're running.

Could you please use this APK and attach here the report it produced? get-device-info.apk.zip

Best regards, John

john-y-pazekha avatar May 28 '20 13:05 john-y-pazekha

@john-y-pazekha as you joined 5 hours ago to github, and send us an APK file I cannot trust you and I don't install that apk

I can send you exact details about model of device

sm2017 avatar May 28 '20 15:05 sm2017

@john-y-pazekha here you are IMG-20200528-WA0014

sm2017 avatar May 28 '20 15:05 sm2017

@sm2017 Thanks a lot. Could you please run the APK I provided and attach the log? I'm particularly interested in VENDOR and PRODUCT fields to identify the device precisely.

I need this information because we couldn't reproduce this issue on the devices we have in-house; now we're going to order new devices but we must know what exactly to order.

john-y-pazekha avatar May 29 '20 07:05 john-y-pazekha

@john-y-pazekha as you joined 5 hours ago to github, and send us an APK file I cannot trust you and I don't install that apk

I totally understand your concern. Please rest assured that this APK is not malicious.

When installing an APK, you have a chance to review the permissions it requests. You can see that this one requests no permissions at all. There is no virus in it (sorry, I was too lazy, maybe in the next version :))))

Alternatively, you can clone the source from this repo and run it.

@sm2017 @patrickschmelter @deecewan @tommeier @vonovak Please use either way to produce the log. I really need this information.

john-y-pazekha avatar May 29 '20 08:05 john-y-pazekha

@sm2017: I can vouch for @john-y-pazekha

oblador avatar May 29 '20 08:05 oblador

@john-y-pazekha I tested on mi a2 Currently I have no access to the phone, may be later

sm2017 avatar May 29 '20 10:05 sm2017

I also have this problem, has anyone reached a conclusion? Why did you update, it's corrupted and the previous versions are correct

forkeer avatar May 29 '20 11:05 forkeer

@forkeer Would you please include your device specs as requested here?

Gentlemen, I need your help to reproduce this issue. Since it happens only on specific combination of phone and Android version, I need to know what exactly you're running.

Could you please use this APK and attach here the report it produced? get-device-info.apk.zip

Alternatively, you can clone the source from this repo and run it.

john-y-pazekha avatar May 29 '20 13:05 john-y-pazekha

@forkeer Would you please include your device specs as requested here?

Gentlemen, I need your help to reproduce this issue. Since it happens only on specific combination of phone and Android version, I need to know what exactly you're running. Could you please use this APK and attach here the report it produced? get-device-info.apk.zip Alternatively, you can clone the source from this repo and run it.

i download but cant install show error

forkeer avatar May 29 '20 14:05 forkeer

i download but cant install show error

I updated the APK, should work now. Sorry for the inconvenience.

Alternatively, you can clone the source from this repo and run it in Android Studio.

john-y-pazekha avatar May 29 '20 14:05 john-y-pazekha

{ "BOARD": "sdm660", "LCT_BSP_VERSION": "0.0.1_180722", "LCT_SINGALCARD_DULEMODE": "unknown", "CPU_ABI2": "", "HOST": "c4-miui-ota-bd46.bj", "LQI_PRODUCT_DEVICE": "unknown", "LCT_WATER_MARK": "unknown", "SUPPORTED_64_BIT_ABIS": [ "arm64-v8a" ], "CPU_ABI": "arm64-v8a", "PERMISSIONS_REVIEW_REQUIRED": true, "FINGERPRINT": "xiaomi/jasmine/jasmine_sprout:10/QKQ1.190910.002/V11.0.6.0.QDIMIXM:user/release-keys", "PRODUCT": "jasmine", "INTERNAL": "unknown", "ID": "QKQ1.190910.002", "LCT_WIFI_BRAND": "unknown", "TYPE": "user", "LCT_AUTOREGISTER_NAME": "unknown", "LCT_BUILD_TYPE": "unknown", "VERSION_TYPE": "unknown", "DEVICE": "jasmine_sprout", "BRAND": "xiaomi", "LCT_HARDWARE_PLATFORM": "unknown", "SUPPORTED_32_BIT_ABIS": [ "armeabi-v7a", "armeabi" ], "LCT_DEVICE_BLACK_UI": "unknown", "BOOTLOADER": "unknown", "CUSTOM_NAME": "unknown", "IS_EMULATOR": false, "LCT_BLUETOOTH_BRAND": "unknown", "TAGS": "release-keys", "CUSTOM_INTERNAL": "unknown", "DISPLAY": "QKQ1.190910.002 V11.0.6.0.QDIMIXM", "SUPPORTED_ABIS": [ "arm64-v8a", "armeabi-v7a", "armeabi" ], "LCT_PROJECT_NAME": "jasmine", "EXTERNAL": "unknown", "LCT_NETWORK_TYPE": "unknown", "LCT_PHONENUMBER_MINMATCH": "unknown", "SERIAL": "unknown", "BUILDDATE": "Tue Mar 10 19:55:26 WIB 2020", "DISPLAY_HARDWARE": "unknown", "LCT_ACCELERATOR_BRAND": "unknown", "LCT_DEVICE_NAME": "unknown", "LCT_OPERATOR_NAME": "unknown", "TIME": 1583844926000, "MODEL": "Mi A2", "MANUFACTURER": "Xiaomi", "USER": "builder", "HARDWARE": "qcom", "IS_DEBUGGABLE": false, "IDEAFRIEND_NEED": "unknown", "RADIO": "unknown", "UNKNOWN": "unknown", "LCT_EXTSTORAGE_TYPE": "unknown" }

forkeer avatar May 29 '20 14:05 forkeer

@forkeer Thanks a lot! What was the startup time?

john-y-pazekha avatar May 29 '20 15:05 john-y-pazekha

@forkeer Thanks a lot! What was the startup time?

From 6 to 8 seconds but averages 7 seconds

forkeer avatar May 29 '20 18:05 forkeer

I am using OnePlus 7 Pro with Android 10, but I am pretty sure we had the same issue with a Galaxy S8, I will confirm.

Thanks.

cladjules avatar May 30 '20 14:05 cladjules

@cladjules I could find the following Galaxies, which one exactly was it? Screenshot 2020-05-31 at 13 57 17

john-y-pazekha avatar May 31 '20 11:05 john-y-pazekha

Issue is easily reproduced on Xiaomi Redmi Note 8 Pro (MIUI 11.0.3.0, Android 9), app launch can take up to 45 seconds, blocking the main thread while getting generic password. Downgrading react-native-keychain to 4.0.5 fixes the issue.

On google devices and emulators it works fine.

gentlee avatar Jun 01 '20 14:06 gentlee