diff options
Diffstat (limited to 'OpenKeychain/src')
5 files changed, 59 insertions, 24 deletions
| diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index f0ce2ea78..1bb4537dc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -36,7 +36,7 @@ import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;  import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;  import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;  import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; -import org.spongycastle.openpgp.operator.jcajce.NfcPublicKeyDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.NfcSyncPublicKeyDataDecryptorFactoryBuilder;  import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; @@ -82,21 +82,27 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {      }      public enum SecretKeyType { -        UNAVAILABLE(0), GNU_DUMMY (1), PASSPHRASE (2), PASSPHRASE_EMPTY (3), DIVERT_TO_CARD (4); +        UNAVAILABLE(0), GNU_DUMMY(1), PASSPHRASE(2), PASSPHRASE_EMPTY(3), DIVERT_TO_CARD(4);          final int mNum; +          SecretKeyType(int num) {              mNum = num;          }          public static SecretKeyType fromNum(int num) {              switch (num) { -                case 1: return GNU_DUMMY; -                case 2: return PASSPHRASE; -                case 3: return PASSPHRASE_EMPTY; -                case 4: return DIVERT_TO_CARD; +                case 1: +                    return GNU_DUMMY; +                case 2: +                    return PASSPHRASE; +                case 3: +                    return PASSPHRASE_EMPTY; +                case 4: +                    return DIVERT_TO_CARD;                  // if this case happens, it's probably a check from a database value -                default: return UNAVAILABLE; +                default: +                    return UNAVAILABLE;              }          } @@ -250,14 +256,14 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {          }      } -    public PublicKeyDataDecryptorFactory getDecryptorFactory() { +    public PublicKeyDataDecryptorFactory getDecryptorFactory(byte[] nfcDecryptedSessionKey) {          if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {              throw new PrivateKeyNotUnlockedException();          }          if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) { -            return new NfcPublicKeyDataDecryptorFactoryBuilder() -                    .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey); +            return new NfcSyncPublicKeyDataDecryptorFactoryBuilder() +                    .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(nfcDecryptedSessionKey);          } else {              return new JcePublicKeyDataDecryptorFactoryBuilder()                      .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 6abef1ad2..aa85b1082 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -42,7 +42,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;  import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;  import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;  import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; -import org.spongycastle.openpgp.operator.jcajce.NfcPublicKeyDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.NfcSyncPublicKeyDataDecryptorFactoryBuilder;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; @@ -78,6 +78,7 @@ public class PgpDecryptVerify {      private String mPassphrase;      private Set<Long> mAllowedKeyIds;      private boolean mDecryptMetadataOnly; +    private byte[] mDecryptedSessionKey;      private PgpDecryptVerify(Builder builder) {          // private Constructor can only be called from Builder @@ -91,6 +92,7 @@ public class PgpDecryptVerify {          this.mPassphrase = builder.mPassphrase;          this.mAllowedKeyIds = builder.mAllowedKeyIds;          this.mDecryptMetadataOnly = builder.mDecryptMetadataOnly; +        this.mDecryptedSessionKey = builder.mDecryptedSessionKey;      }      public static class Builder { @@ -106,6 +108,7 @@ public class PgpDecryptVerify {          private String mPassphrase = null;          private Set<Long> mAllowedKeyIds = null;          private boolean mDecryptMetadataOnly = false; +        private byte[] mDecryptedSessionKey = null;          public Builder(ProviderHelper providerHelper, PassphraseCache passphraseCache,                         InputData data, OutputStream outStream) { @@ -148,6 +151,11 @@ public class PgpDecryptVerify {              return this;          } +        public Builder setNfcState(byte[] decryptedSessionKey) { +            mDecryptedSessionKey = decryptedSessionKey; +            return this; +        } +          public PgpDecryptVerify build() {              return new PgpDecryptVerify(this);          } @@ -196,10 +204,12 @@ public class PgpDecryptVerify {      }      public static class NeedNfcDataException extends Exception { -        public byte[] mDec; +        public byte[] mEncryptedSessionKey; +        public String mPassphrase; -        public NeedNfcDataException(byte[] dec) { -            mDec = dec; +        public NeedNfcDataException(byte[] encryptedSessionKey, String passphrase) { +            mEncryptedSessionKey = encryptedSessionKey; +            mPassphrase = passphrase;          }      } @@ -379,11 +389,12 @@ public class PgpDecryptVerify {              currentProgress += 2;              updateProgress(R.string.progress_preparing_streams, currentProgress, 100); -            PublicKeyDataDecryptorFactory decryptorFactory = secretEncryptionKey.getDecryptorFactory();              try { +                PublicKeyDataDecryptorFactory decryptorFactory +                        = secretEncryptionKey.getDecryptorFactory(mDecryptedSessionKey);                  clear = encryptedDataAsymmetric.getDataStream(decryptorFactory); -            } catch (NfcPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) { -                throw new NeedNfcDataException(e.dec); +            } catch (NfcSyncPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) { +                throw new NeedNfcDataException(e.encryptedSessionKey, mPassphrase);              }              encryptedData = encryptedDataAsymmetric;          } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index f51a3ac14..0e1dcd7db 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -177,7 +177,7 @@ public class OpenPgpService extends RemoteService {          return result;      } -    private Intent getNfcDecryptIntent(Intent data, String pin, byte[] dec) { +    private Intent getNfcDecryptIntent(Intent data, String pin, byte[] encryptedSessionKey) {          // build PendingIntent for Yubikey NFC operations          Intent intent = new Intent(getBaseContext(), NfcActivity.class);          intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); @@ -185,7 +185,7 @@ public class OpenPgpService extends RemoteService {          intent.putExtra(NfcActivity.EXTRA_DATA, data);          intent.putExtra(NfcActivity.EXTRA_PIN, pin); -        intent.putExtra(NfcActivity.EXTRA_NFC_DEC, dec); +        intent.putExtra(NfcActivity.EXTRA_NFC_ENC_SESSION_KEY, encryptedSessionKey);          intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);          PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,                  intent, @@ -432,7 +432,6 @@ public class OpenPgpService extends RemoteService {              Intent result = new Intent();              try { -                  String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);                  long inputLength = is.available();                  InputData inputData = new InputData(is, inputLength); @@ -453,12 +452,15 @@ public class OpenPgpService extends RemoteService {                          inputData, os                  ); +                byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); +                  // allow only private keys associated with accounts of this app                  // no support for symmetric encryption                  builder.setPassphrase(passphrase)                          .setAllowSymmetricDecryption(false)                          .setAllowedKeyIds(allowedKeyIds) -                        .setDecryptMetadataOnly(decryptMetadataOnly); +                        .setDecryptMetadataOnly(decryptMetadataOnly) +                        .setNfcState(nfcDecryptedSessionKey);                  PgpDecryptVerifyResult decryptVerifyResult;                  try { @@ -478,7 +480,7 @@ public class OpenPgpService extends RemoteService {                      throw new Exception(getString(R.string.error_integrity_check_failed));                  } catch (PgpDecryptVerify.NeedNfcDataException e) {                      // return PendingIntent to execute NFC activity -                    return getNfcDecryptIntent(data, passphrase, e.mDec); +                    return getNfcDecryptIntent(data, e.mPassphrase, e.mEncryptedSessionKey);                  }                  if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { @@ -522,7 +524,6 @@ public class OpenPgpService extends RemoteService {                          result.putExtra(OpenPgpApi.RESULT_METADATA, metadata);                      }                  } -              } finally {                  is.close();                  if (os != null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java index 845fbfa3b..ee1460ee3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java @@ -33,12 +33,15 @@ import android.view.ViewGroup;  import android.widget.CheckBox;  import android.widget.TextView; +import org.openintents.openpgp.util.OpenPgpApi;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.helper.FileHelper; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;  import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;  import org.sufficientlysecure.keychain.service.KeychainIntentService;  import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.PassphraseCacheService;  import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;  import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;  import org.sufficientlysecure.keychain.util.Log; @@ -182,7 +185,20 @@ public class DecryptFileFragment extends DecryptFragment {                              returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);                      if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { -                        showPassphraseDialogForFilename(decryptVerifyResult.getKeyIdPassphraseNeeded()); +                        try { +                            // try to get passphrase from cache... +                            String passphrase = PassphraseCacheService.getCachedPassphrase( +                                    getActivity(), decryptVerifyResult.getKeyIdPassphraseNeeded()); + +                            if (passphrase != null) { +                                // try again with passphrase from cache +                                decryptOriginalFilename(passphrase); +                            } else { +                                showPassphraseDialogForFilename(decryptVerifyResult.getKeyIdPassphraseNeeded()); +                            } +                        } catch (PassphraseCacheService.KeyNotFoundException e) { +                            Log.e(Constants.TAG, "PassphraseCacheService.KeyNotFoundException", e); +                        }                      } else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED ==                              decryptVerifyResult.getStatus()) {                          showPassphraseDialogForFilename(Constants.key.symmetric); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 11d5292bb..830e856aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -186,6 +186,7 @@ public class EditKeyFragment extends LoaderFragment implements                      mSaveKeyringParcel.mMasterKeyId);          } catch (PassphraseCacheService.KeyNotFoundException e) {              Log.e(Constants.TAG, "Key not found!", e); +            Toast.makeText(getActivity(), R.string.error_no_secret_key_found, Toast.LENGTH_SHORT).show();              getActivity().finish();              return;          } | 
