amplify-android icon indicating copy to clipboard operation
amplify-android copied to clipboard

AndroidKeystoreAesGcm.encryptInternal

Open fauzimubarokk opened this issue 1 year ago • 2 comments

Before opening, please confirm:

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

fauzimubarokk avatar Oct 15 '24 06:10 fauzimubarokk

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.

mattcreaser avatar Oct 15 '24 15:10 mattcreaser

Here are the details of the devices :

Device Name Operating System
image image

@mattcreaser

fauzimubarokk avatar Oct 22 '24 06:10 fauzimubarokk

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%?

vincetran avatar Oct 23 '24 17:10 vincetran

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

tylerjroach avatar Dec 04 '24 21:12 tylerjroach

Hi @tylerjroach , could we use Datastore instead of SharedPreferences. there is a lot of pain on using SharedPreferences. image

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

TrumpDony avatar Dec 13 '24 09:12 TrumpDony

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.

tylerjroach avatar Dec 13 '24 13:12 tylerjroach

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.

tylerjroach avatar Jan 13 '25 19:01 tylerjroach

Amplify v2.26.0 contains the in-memory fallback described above and should no longer cause crashes!

tylerjroach avatar Jan 17 '25 17:01 tylerjroach

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.

github-actions[bot] avatar Jan 17 '25 17:01 github-actions[bot]