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

AndroidKeystoreAesGcm.encryptInternal #2939

Open
1 task done
fauzimubarokk opened this issue Oct 15, 2024 · 6 comments
Open
1 task done

AndroidKeystoreAesGcm.encryptInternal #2939

fauzimubarokk opened this issue Oct 15, 2024 · 6 comments
Labels
auth Related to the Auth category/plugins duplicate This issue or pull request already exists feature-request Request a new feature

Comments

@fauzimubarokk
Copy link

fauzimubarokk commented Oct 15, 2024

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

@github-actions github-actions bot added pending-triage Issue is pending triage pending-maintainer-response Issue is pending response from an Amplify team member labels Oct 15, 2024
@mattcreaser mattcreaser added bug Something isn't working duplicate This issue or pull request already exists labels Oct 15, 2024
@github-actions github-actions bot removed the pending-triage Issue is pending triage label Oct 15, 2024
@mattcreaser mattcreaser added feature-request Request a new feature and removed bug Something isn't working labels Oct 15, 2024
@mattcreaser
Copy link
Member

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.

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending response from an Amplify team member label Oct 15, 2024
@mattcreaser mattcreaser added the auth Related to the Auth category/plugins label Oct 15, 2024
@fauzimubarokk
Copy link
Author

fauzimubarokk commented Oct 22, 2024

Here are the details of the devices :

Device Name Operating System
image image

@mattcreaser

@github-actions github-actions bot added the pending-maintainer-response Issue is pending response from an Amplify team member label Oct 22, 2024
@vincetran
Copy link
Member

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

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending response from an Amplify team member label Oct 23, 2024
@tylerjroach
Copy link
Member

tylerjroach commented Dec 4, 2024

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
Copy link

TrumpDony commented Dec 13, 2024

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

@github-actions github-actions bot added the pending-maintainer-response Issue is pending response from an Amplify team member label Dec 13, 2024
@tylerjroach
Copy link
Member

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.

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending response from an Amplify team member label Dec 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auth Related to the Auth category/plugins duplicate This issue or pull request already exists feature-request Request a new feature
Projects
None yet
Development

No branches or pull requests

5 participants