AndroidKeystoreAesGcm.encryptInternal
Before opening, please confirm:
- [X] I have searched for duplicate or closed issues and discussions.
Language and Async Model
Kotlin - Coroutines
Amplify Categories
Authentication
Gradle script dependencies
implementation("com.amplifyframework:aws-auth-cognito:2.23.0")
Environment information
# Put output below this line
------------------------------------------------------------
Gradle 8.7
------------------------------------------------------------
Please include any relevant guides or documentation you're referencing
https://docs.amplify.aws/lib/auth/signin_web_ui/q/platform/android/#launch-web-ui-sign-in
Describe the bug
Fatal Exception: java.security.KeyStoreException
the master key android-keystore://amplify_master_key exists but is unusable
Fatal Exception: java.security.KeyStoreException: the master key android-keystore://amplify_master_key exists but is unusable
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readOrGenerateNewMasterKey(AndroidKeysetManager.java:332)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:290)
at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:155)
at com.amplifyframework.core.store.EncryptedKeyValueRepository.getSharedPreferencesOrThrow(EncryptedKeyValueRepository.kt:110)
at com.amplifyframework.core.store.EncryptedKeyValueRepository.openKeystoreWithAmplifyMasterKey(EncryptedKeyValueRepository.kt:86)
at com.amplifyframework.core.store.EncryptedKeyValueRepository.getOrCreateSharedPreferences(EncryptedKeyValueRepository.kt:64)
at com.amplifyframework.core.store.EncryptedKeyValueRepository.access$getOrCreateSharedPreferences(EncryptedKeyValueRepository.kt)
at com.amplifyframework.core.store.EncryptedKeyValueRepository$sharedPreferences$2.invoke(EncryptedKeyValueRepository.kt:48)
at com.amplifyframework.core.store.EncryptedKeyValueRepository$sharedPreferences$2.invoke(EncryptedKeyValueRepository.kt:48)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.amplifyframework.core.store.EncryptedKeyValueRepository.getSharedPreferences(EncryptedKeyValueRepository.kt:48)
at com.amplifyframework.core.store.EncryptedKeyValueRepository.get(EncryptedKeyValueRepository.kt:51)
at com.amplifyframework.auth.cognito.data.AWSCognitoAuthCredentialStore.retrieveCredential(AWSCognitoAuthCredentialStore.kt:62)
at com.amplifyframework.auth.cognito.actions.CredentialStoreCognitoActions$loadCredentialStoreAction$$inlined$invoke$1.execute(Action.kt:70)
at com.amplifyframework.statemachine.ConcurrentEffectExecutor$execute$1$1.invokeSuspend(ConcurrentEffectExecutor.kt:26)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:811)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:715)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt)
Reproduction steps (if applicable)
No response
Code Snippet
// Put your code below this line.
Log output
// Put your logs below this line
amplifyconfiguration.json
{
"auth": {
"plugins": {
"awsCognitoAuthPlugin": {
"IdentityManager": {
"Default": {}
},
"AppSync": {
"Default": {
"ApiUrl": "****",
"Region": "ap-southeast-1",
"AuthMode": "API_KEY",
"ApiKey": "*****",
"ClientDatabasePrefix": "***"
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "****",
"Region": "***"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": "ap-southeast",
"AppClientId": "***",
"Region": "ap-southeast"
}
},
"Auth": {
"Default": {
"OAuth": {
"WebDomain": "***",
"AppClientId": "***",
"SignInRedirectURI": "***",
"SignOutRedirectURI": "***",
"Scopes": [
"phone",
"email",
"openid",
"profile",
"aws.cognito.signin.user.admin"
]
}
}
}
}
}
}
GraphQL Schema
// Put your schema below this line
Additional information and screenshots
No response
This is a duplicate of #2845. @fauzimubarokk do you have any details on the devices this occurs on? Some devices simply have faulty keystore implementations - we make a best effort but if the keystore doesn't work there's not much we can do.
Here are the details of the devices :
| Device Name | Operating System |
|---|---|
@mattcreaser
Hmm. On previous projects I have seen that Oppo devices have been notoriously difficult to code around due to the way Oppo has customized Android. When it says 71% Oppo, does that mean there are other devices that have encountered this issue that makes up the rest of the 29%?
This is something that we have begun looking at. My initial experiment is to allow a user-provided implementation of a simple interface we already used internally.
interface KeyValueRepository {
fun put(dataKey: String, value: String?)
fun get(dataKey: String): String?
fun getAll(): Map<String, String?>
fun remove(dataKey: String)
fun removeAll() = Unit
}
Implementers would have the ability to store Amplify data however they choose, standard SharedPreferences, EncryptedSharedPreferences, or any other mechanism that implements the interface above.
Amplify.addPlugin(AWSCognitoAuthPlugin(
options = AWSCognitoAuthPlugin.Options(
customKeyValueRepository = object : KeyValueRepository {
private val sharedPreferences = applicationContext.getSharedPreferences(
"customAuthKeyValueRepository",
Context.MODE_PRIVATE
)
override fun get(dataKey: String): String? {
return sharedPreferences.getString(dataKey, null)
}
override fun getAll(): Map<String, String?> {
return sharedPreferences.all.mapValues { it.value as String? }
}
override fun put(dataKey: String, value: String?) {
sharedPreferences.edit().putString(dataKey, value).apply()
}
override fun remove(dataKey: String) {
sharedPreferences.edit().remove(dataKey).apply()
}
}
)
))
I'll provide further updates as work progresses. Initial progress can be tracked here: https://github.com/aws-amplify/amplify-android/tree/tjroach/allow-custom-keyvaluestore
Hi @tylerjroach , could we use Datastore instead of SharedPreferences. there is a lot of pain on using SharedPreferences.
This is something that we have begun looking at. My initial experiment is to allow a user-provided implementation of a simple interface we already used internally.
interface KeyValueRepository { fun put(dataKey: String, value: String?) fun get(dataKey: String): String? fun getAll(): Map<String, String?> fun remove(dataKey: String) fun removeAll() = Unit }Implementers would have the ability to store Amplify data however they choose, standard SharedPreferences, EncryptedSharedPreferences, or any other mechanism that implements the interface above.
Amplify.addPlugin(AWSCognitoAuthPlugin( options = AWSCognitoAuthPlugin.Options( customKeyValueRepository = object : KeyValueRepository { private val sharedPreferences = applicationContext.getSharedPreferences( "customAuthKeyValueRepository", Context.MODE_PRIVATE ) override fun get(dataKey: String): String? { return sharedPreferences.getString(dataKey, null) } override fun getAll(): Map<String, String?> { return sharedPreferences.all.mapValues { it.value as String? } } override fun put(dataKey: String, value: String?) { sharedPreferences.edit().putString(dataKey, value).apply() } override fun remove(dataKey: String) { sharedPreferences.edit().remove(dataKey).apply() } } ) ))I'll provide further updates as work progresses. Initial progress can be tracked here: https://github.com/aws-amplify/amplify-android/tree/tjroach/allow-custom-keyvaluestore
Sure! With the proposal, as long as the interface below is adhered to, the backing method would be entirely up to you.
interface KeyValueRepository {
fun put(dataKey: String, value: String?)
fun get(dataKey: String): String?
fun getAll(): Map<String, String?>
fun remove(dataKey: String)
fun removeAll() = Unit
}
We still have a few things to work out in the design. My original plan was for each plugin to have its own customKeyValueRepository override. However, some plugins share shared preference data, so we still need to work though these ideas a bit. Next bit of exploration will be to place the customKeyValueRepository at a global amplify level so that plugins can continue to share data.
Crashes will be resolved in the next Amplify release with an in-memory key/value repository fallback 2969. Please see here for additional information on the changes made, and to provide additional feedback on whether or not the solution is fully sufficient for your use case.
Amplify v2.26.0 contains the in-memory fallback described above and should no longer cause crashes!
This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.