Hi, recently we started observing a larger amount of problems when connecting to TTP that lead to crashes with an exception:
KeyStoreException: Signature/MAC verification failed (internal Keystore code: -30 message: system/security/keystore2/src/operation.rs:850: KeystoreOperation::finish. After a brief research, I found out that this error is caused by an attempt to decrypt the shared preferences with an outdated key.
Such a case, I believe, can occur when an app that has the allowBackup manifest flag is set to true, and the user does a device-to-device restore, which restores the shared preferences, but since they were encrypted using another device keystore, they now cannot be decrypted.
The simplest solution would be to set the allowBackup flag to false, but since we would like to keep the backup feature, the other solution (which is advised by the Android documentation) is to explicitly exclude the specific shared prefs (in that case a list of what shared_prefs files should not be backed up will be needed).
Another solution would be to clear the app/SDK data after receiving this error which resolves the error, but this ideally require a method to reset all the SDK data (but it would be a nice addition since we sometimes experience other KeyStoreExceptions).
Code to reproduce
The 1:1 reproduction requires two devices, so to simulate such a case, we can just delete the asp_key (that leads to a mismatch between the key used to encrypt and the key used to decrypt) and try to connect to Tap to Pay:
The whole stacktrace
```java
java.lang.RuntimeException: Unable to bind to service com.stripe.cots.aidlservice.CotsService@b79208b with Intent { act= cmp=/com.stripe.cots.aidlservice.CotsService }: javax.crypto.AEADBadTagException
at android.app.ActivityThread.handleBindService(ActivityThread.java:4696)
at android.app.ActivityThread.-$$Nest$mhandleBindService(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2272)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: javax.crypto.AEADBadTagException
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:626)
at javax.crypto.Cipher.doFinal(Cipher.java:2114)
at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.decryptInternal(AndroidKeystoreAesGcm.java:118)
at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.decrypt(AndroidKeystoreAesGcm.java:101)
at com.google.crypto.tink.KeysetHandle.decrypt(KeysetHandle.java:919)
at com.google.crypto.tink.KeysetHandle.readWithAssociatedData(KeysetHandle.java:804)
at com.google.crypto.tink.KeysetHandle.read(KeysetHandle.java:785)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readMasterkeyDecryptAndParseKeyset(AndroidKeysetManager.java:381)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:297)
at java.lang.reflect.Method.invoke(Native Method)
at com.s.t.BillingV22436.ad_(:155)
at com.s.t.BillingV22436.ac_(:120)
at com.s.u.managingJ17450.As(:183)
at com.s.u.managingJ17450.(:108)
at com.s.af.choiceF7628.Billing(:17)
at com.s.af.choiceF7628.Dashboard(:1)
at com.s.af.choiceF7628.As(:65354)
at com.s.af.complianceE24073.Dashboard(:2043)
at com.s.af.complianceE24073.As(:65353)
at com.s.af.complianceE24073.Connect(:35)
at com.s.af.complianceE24073.get(:11)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.s.af.deploymentN2911.Connect(:40)
at com.s.af.deploymentN2911.get(:12)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.s.u.accessoriesD1361.Build(:110)
at com.s.u.accessoriesD1361.get(:19)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.s.af.ConnectV30425.Connect(:62)
at com.s.af.ConnectV30425.get(:17)
at com.s.s.BuildF9013.Dashboard(:43)
at com.s.s.BuildF9013.get(:14)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.s.s.DashboardO28928.Billing(:38)
at com.s.s.DashboardO28928.get(:13)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.s.s.BillingW21809.Connect(:43)
at com.s.s.BillingW21809.get(:14)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.s.u.evenY23415$ConnectH22350.Connect(:764)
at com.stripe.cots.aidlservice.CotsService$DashboardA7632.invokeSuspend(:96)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:111)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
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:702)
E Caused by: android.security.KeyStoreException: Signature/MAC verification failed (internal Keystore code: -30 message: system/security/keystore2/src/operation.rs:850: KeystoreOperation::finish
```
Summary
Hi, recently we started observing a larger amount of problems when connecting to TTP that lead to crashes with an exception:
KeyStoreException: Signature/MAC verification failed (internal Keystore code: -30 message: system/security/keystore2/src/operation.rs:850: KeystoreOperation::finish.
After a brief research, I found out that this error is caused by an attempt to decrypt the shared preferences with an outdated key.Such a case, I believe, can occur when an app that has the
allowBackup
manifest flag is set to true, and the user does a device-to-device restore, which restores the shared preferences, but since they were encrypted using another device keystore, they now cannot be decrypted.The simplest solution would be to set the
allowBackup
flag to false, but since we would like to keep the backup feature, the other solution (which is advised by the Android documentation) is to explicitly exclude the specific shared prefs (in that case a list of what shared_prefs files should not be backed up will be needed).Another solution would be to clear the app/SDK data after receiving this error which resolves the error, but this ideally require a method to reset all the SDK data (but it would be a nice addition since we sometimes experience other KeyStoreExceptions).
Code to reproduce
The 1:1 reproduction requires two devices, so to simulate such a case, we can just delete the
asp_key
(that leads to a mismatch between the key used to encrypt and the key used to decrypt) and try to connect to Tap to Pay:Android version
14/13 (does not matter)
Impacted devices (Android devices or readers)
Tap to Pay
SDK version
3.9.5
Other information
The whole stacktrace
```java java.lang.RuntimeException: Unable to bind to service com.stripe.cots.aidlservice.CotsService@b79208b with Intent { act= cmp=