android-password-store / Android-Password-Store

Android application compatible with ZX2C4's Pass command line application
https://passwordstore.app
GNU General Public License v3.0
2.59k stars 270 forks source link

[BUG] master key android-keystore://passphrase exists but is unusable #3214

Closed jimdigriz closed 1 month ago

jimdigriz commented 2 months ago

Describe the bug

I had been running 2.0.0-SNAPSHOT from Aug 2023 with success until recently.

A few weeks back I started being prompted for my SSH passphrase, which I repeatedly tried (maybe I forgot it, not really relevant) and was just told there was a problem decrypting the key.

I found the time today to look into getting this working again, but after cleaning my app storage, and also uninstalling and reinstalling a recent 2.0.0-SNAPSHOT (https://github.com/android-password-store/Android-Password-Store/commit/6bf819ff9dd81d3dd9e21d98d6d14b6e1d9413a6) I then just got "the master key android-keystore://sshkey exists but is unusable". I tried reinstalling as per the advice in https://github.com/android-password-store/Android-Password-Store/issues/2649#issuecomment-1678623336 but similarly to https://github.com/android-password-store/Android-Password-Store/issues/2649#issuecomment-1679014559 it seemed to have no effect.

To make some progress, I unchecked the 'use screensaver lock' (as I was having similar problems to https://github.com/android-password-store/Android-Password-Store/issues/1144) which worked and then imported my GPG key.

When trying to decrypt one of my secrets, I am not prompted for my GPG passphrase, the screen just flickers white and looks like the app just reloads, but from the debug logs I see:

09-16 11:02:58.654   828   828 E AndroidRuntime: FATAL EXCEPTION: main
09-16 11:02:58.654   828   828 E AndroidRuntime: Process: app.passwordstore, PID: 828
09-16 11:02:58.654   828   828 E AndroidRuntime: java.security.KeyStoreException: the master key android-keystore://passphrase exists but is unusable
09-16 11:02:58.654   828   828 E AndroidRuntime:    at app.passwordstore.util.git.sshj.SshjSession.readOrGenerateNewMasterKey(Unknown Source:50)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at app.passwordstore.util.git.sshj.SshjSession.build(Unknown Source:30)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at androidx.security.crypto.EncryptedSharedPreferences.create(Unknown Source:71)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at app.passwordstore.data.crypto.PGPPassphraseCache$getPreferences$2.invokeSuspend(Unknown Source:51)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at app.passwordstore.data.crypto.PGPPassphraseCache$getPreferences$2.invoke(Unknown Source:12)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at kotlin.text.UStringsKt.startUndispatchedOrReturn(Unknown Source:4)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at kotlinx.coroutines.JobKt.withContext(Unknown Source:77)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at com.jcraft.jsch.JSch$1.access$getPreferences(Unknown Source:65)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at app.passwordstore.data.crypto.PGPPassphraseCache$clearAllCachedPassphrases$2.invokeSuspend(Unknown Source:30)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(Unknown Source:8)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at kotlinx.coroutines.DispatchedTask.run(Unknown Source:106)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at com.google.android.gms.tasks.zzi.run(Unknown Source:17)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at kotlinx.coroutines.scheduling.TaskImpl.run(Unknown Source:2)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(Unknown Source:92)
09-16 11:02:58.654   828   828 E AndroidRuntime:    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [DeferredCoroutine{Cancelling}@b362e8a, Dispatchers.Main.immediate]
09-16 11:02:58.654   828   828 E AndroidRuntime: Caused by: android.security.keystore.UserNotAuthenticatedException: User not authenticated
09-16 11:02:58.654   828   828 E AndroidRuntime:    at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1346)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1388)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(KeyStoreCryptoOperationUtils.java:54)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at android.security.keystore.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:89)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:265)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:109)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2984)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at javax.crypto.Cipher.tryCombinations(Cipher.java:2891)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2796)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at javax.crypto.Cipher.chooseProvider(Cipher.java:773)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at javax.crypto.Cipher.init(Cipher.java:1143)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at javax.crypto.Cipher.init(Cipher.java:1084)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.encryptInternal(Unknown Source:20)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.encrypt(Unknown Source:27)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at com.google.crypto.tink.integration.android.AndroidKeystoreKmsClient.getAead(Unknown Source:21)
09-16 11:02:58.654   828   828 E AndroidRuntime:    at app.passwordstore.util.git.sshj.SshjSession.readOrGenerateNewMasterKey(Unknown Source:22)
09-16 11:02:58.654   828   828 E AndroidRuntime:    ... 13 more

So it looks like these keystore secrets are wedged in there and I have no idea how to purge them.

Uninstalling does not burn android-keystore://{sshkey,passphrase} and also burning the app storage does not.

I am completely stuck now.

Any suggestions?

Steps to reproduce

Steps to reproduce the behavior:

  1. Have an phone in the state with android-keystore://{sshkey,passphrase} secrets wedged in there
  2. Install 2.0.0-SNAPSHOT (https://github.com/android-password-store/Android-Password-Store/commit/6bf819ff9dd81d3dd9e21d98d6d14b6e1d9413a6)
  3. Generate an SSH key making sure not to use the screensaver lock
  4. Import GPG key
  5. Attempt to access secret...observe screen flicker white as application reloads

Expected behavior

Ability to burn/ignore existing android-keystore secrets.

Screenshots

No response

Device information

Additional context

Maybe a fix, as my understanding is "Android is buggy", could be to have a prefix (or suffix) to the secrets being stored so via an advanced menu option at least the user could provide a unique string to ignore the unpurgable existing secrets

msfjarvis commented 1 month ago

The problem doesn't seem to be with the key being irrecoverably broken, but by the app trying to access it without authentication. If you can capture a full log following the steps here it'll be easier to identify why that happened.

jimdigriz commented 1 month ago

Updated to the latest snapshot (https://github.com/android-password-store/Android-Password-Store/commit/6a5e35a95c795e7c56048ac36d86da53c2799e4e) and here is the log for generating an ed25519 ssh key and another covering a few (successful) attempts to import the GPG key, but when I tried to access a secret...though it no longer crashes, the app just seemingly jumps in and back out of the particular secret (the error has changed, but I am not being prompted for a passphrase).

msfjarvis commented 1 month ago

I have made the decision to archive the project for reasons outlined here.

This issue is being closed to ensure everyone subscribed to it is made aware of this change in the app's maintenance status.