Reputation: 456
I have an Android app that uses the Android secure keystore to encrypt/decrypt account information.
The min SDK is set to 23 so a valid keystore should always be available, however, I've had a small number of crash reports about keystore failures with one in particular from a Essential PH1 phone running Android 10.
The error reported is the following
Non-fatal Exception: java.security.InvalidKeyException
Keystore operation failed
android.security.KeyStore.getInvalidKeyException (KeyStore.java:1362)
android.security.KeyStore.getInvalidKeyException (KeyStore.java:1402)
android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit (KeyStoreCryptoOperationUtils.java:54)
android.security.keystore.KeyStoreCryptoOperationUtils.getExceptionForCipherInit (KeyStoreCryptoOperationUtils.java:89)
android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized (AndroidKeyStoreCipherSpiBase.java:265)
android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit (AndroidKeyStoreCipherSpiBase.java:148)
javax.crypto.Cipher.tryTransformWithProvider (Cipher.java:2980)
javax.crypto.Cipher.tryCombinations (Cipher.java:2891)
javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider (Cipher.java:2796)
javax.crypto.Cipher.chooseProvider (Cipher.java:773)
javax.crypto.Cipher.init (Cipher.java:1288)
javax.crypto.Cipher.init (Cipher.java:1223)
Caused by android.security.KeyStoreException
-62
android.security.KeyStore.getKeyStoreException (KeyStore.java:1292)
android.security.KeyStore.getInvalidKeyException (KeyStore.java:1402)
android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit (KeyStoreCryptoOperationUtils.java:54)
android.security.keystore.KeyStoreCryptoOperationUtils.getExceptionForCipherInit (KeyStoreCryptoOperationUtils.java:89)
android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized (AndroidKeyStoreCipherSpiBase.java:265)
android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit (AndroidKeyStoreCipherSpiBase.java:148)
javax.crypto.Cipher.tryTransformWithProvider (Cipher.java:2980)
javax.crypto.Cipher.tryCombinations (Cipher.java:2891)
javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider (Cipher.java:2796)
javax.crypto.Cipher.chooseProvider (Cipher.java:773)
javax.crypto.Cipher.init (Cipher.java:1288)
javax.crypto.Cipher.init (Cipher.java:1223)
It also seems to fail on different occasions getting the key
Caused by android.security.KeyStoreException
-62
android.security.KeyStore.getKeyStoreException (KeyStore.java:839)
android.security.keystore.AndroidKeyStoreProvider.getKeyCharacteristics (AndroidKeyStoreProvider.java:236)
android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore (AndroidKeyStoreProvider.java:356)
android.security.keystore.AndroidKeyStoreSpi.engineGetKey (AndroidKeyStoreSpi.java:101)
java.security.KeyStore.getKey (KeyStore.java:1062)
I've scoured the internet and the Android source code for some information on error -62 and found nothing besides a report containing the same error for 'signal' which doesn't appear to have ever been resolved
https://github.com/signalapp/Signal-Android/issues/8589
I've no idea what's causing this or why when it works on literally every other device.
If someone can shed some light on this issue it would be greatly appreciated.
If it makes a difference I'm using AES 128 encryption with GCMParameterSpec and a fixed IV.
The key is created with the following parameters
setBlockModes(KeyProperties.BLOCK_MODE_GCM)
setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
setKeySize(128)
setRandomizedEncryptionRequired(false)
EDIT
I've finally found the error definition and description here
https://source.android.com/reference/hal/structkeymaster2__device
KM_ERROR_KEY_REQUIRES_UPGRADE = -62,
keymaster_error_t (* upgrade_key)(const struct keymaster2_device *dev, const keymaster_key_blob_t *key_to_upgrade, const keymaster_key_param_set_t *upgrade_params, keymaster_key_blob_t *upgraded_key)
Upgrades an old key. Keys can become "old" in two ways: Keymaster can be upgraded to a new version, or the system can be updated to invalidate the OS version and/or patch level. In either case, attempts to use an old key will result in keymaster returning KM_ERROR_KEY_REQUIRES_UPGRADE. This method should then be called to upgrade the key.
Parameters
[in] dev The keymaster device structure.
[in] key_to_upgrade The keymaster key to upgrade.
[in] upgrade_params Parameters needed to complete the upgrade. In particular, KM_TAG_APPLICATION_ID and KM_TAG_APPLICATION_DATA will be required if they were defined for the key.
[out] upgraded_key The upgraded key blob.
This would suggest security patches or otherwise updating the OS requires keys to be upgraded. This doesn't make sense though as it occurs every time starting the app and the OS definitely isn't being updated that often.
The function 'upgrade_key' seems to be part of the Android system and isn't even accessible from the java side. How on earth are you meant to handle this error?
Upvotes: 3
Views: 3030
Reputation: 21
As an app developer you are not meant to handle this error. This gets handled, transparently, by the keystore daemon. If it trickles all the way up to the application, something has gone seriously wrong. There could be a bug in the keystore daemon or the underlying keymaster implementation.
If you can easily reproduce it, it would be helpful if you would file a bug report: https://developer.android.com/studio/debug/bug-report
Upvotes: 0