diff options
| author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-09-17 13:45:16 +0200 | 
|---|---|---|
| committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-09-17 13:45:16 +0200 | 
| commit | d686c55a0a86ef845795fc03a8a5de44b5fe73cc (patch) | |
| tree | d5bb8dfe1d451b392c8c88a3fa8b14b1dd43db1e | |
| parent | 3defd194aaa79309c0a0921a63c5ab157081325c (diff) | |
| download | open-keychain-d686c55a0a86ef845795fc03a8a5de44b5fe73cc.tar.gz open-keychain-d686c55a0a86ef845795fc03a8a5de44b5fe73cc.tar.bz2 open-keychain-d686c55a0a86ef845795fc03a8a5de44b5fe73cc.zip  | |
Work on new result handling (WIP)
14 files changed, 310 insertions, 184 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PassphraseCacheInterface.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PassphraseCacheInterface.java new file mode 100644 index 000000000..433c4db00 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PassphraseCacheInterface.java @@ -0,0 +1,11 @@ +package org.sufficientlysecure.keychain.pgp; + +public interface PassphraseCacheInterface { +    public static class NoSecretKeyException extends Exception { +        public NoSecretKeyException() { +        } +    } + +    public String getCachedPassphrase(long masterKeyId) throws NoSecretKeyException; + +} 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 89e25b2e0..1d8ca1b54 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -72,7 +72,7 @@ import java.util.Set;   */  public class PgpDecryptVerify {      private ProviderHelper mProviderHelper; -    private PassphraseCache mPassphraseCache; +    private PassphraseCacheInterface mPassphraseCache;      private InputData mData;      private OutputStream mOutStream; @@ -101,7 +101,7 @@ public class PgpDecryptVerify {      public static class Builder {          // mandatory parameter          private ProviderHelper mProviderHelper; -        private PassphraseCache mPassphraseCache; +        private PassphraseCacheInterface mPassphraseCache;          private InputData mData;          private OutputStream mOutStream; @@ -113,12 +113,12 @@ public class PgpDecryptVerify {          private boolean mDecryptMetadataOnly = false;          private byte[] mDecryptedSessionKey = null; -        public Builder(ProviderHelper providerHelper, PassphraseCache passphraseCache, +        public Builder(ProviderHelper providerHelper, PassphraseCacheInterface passphraseCache,                         InputData data, OutputStream outStream) { -            this.mProviderHelper = providerHelper; -            this.mPassphraseCache = passphraseCache; -            this.mData = data; -            this.mOutStream = outStream; +            mProviderHelper = providerHelper; +            mPassphraseCache = passphraseCache; +            mData = data; +            mOutStream = outStream;          }          public Builder setProgressable(Progressable progressable) { @@ -176,16 +176,6 @@ public class PgpDecryptVerify {          }      } -    public interface PassphraseCache { -        public String getCachedPassphrase(long masterKeyId) -                throws NoSecretKeyException; -    } - -    public static class NoSecretKeyException extends Exception { -        public NoSecretKeyException() { -        } -    } -      /**       * Decrypts and/or verifies data based on parameters of class       */ @@ -322,7 +312,7 @@ public class PgpDecryptVerify {                          // returns "" if key has no passphrase                          mPassphrase = mPassphraseCache.getCachedPassphrase(subKeyId);                          log.add(LogType.MSG_DC_PASS_CACHED, indent +1); -                    } catch (NoSecretKeyException e) { +                    } catch (PassphraseCacheInterface.NoSecretKeyException e) {                          log.add(LogType.MSG_DC_ERROR_NO_KEY, indent +1);                          return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);                      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index e06335104..25840495e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -59,6 +59,7 @@ import java.util.LinkedList;   */  public class PgpSignEncrypt {      private ProviderHelper mProviderHelper; +    private PassphraseCacheInterface mPassphraseCache;      private String mVersionHeader;      private InputData mData;      private OutputStream mOutStream; @@ -93,6 +94,7 @@ public class PgpSignEncrypt {      private PgpSignEncrypt(Builder builder) {          // private Constructor can only be called from Builder          this.mProviderHelper = builder.mProviderHelper; +        this.mPassphraseCache = builder.mPassphraseCache;          this.mVersionHeader = builder.mVersionHeader;          this.mData = builder.mData;          this.mOutStream = builder.mOutStream; @@ -117,6 +119,7 @@ public class PgpSignEncrypt {      public static class Builder {          // mandatory parameter          private ProviderHelper mProviderHelper; +        private PassphraseCacheInterface mPassphraseCache;          private InputData mData;          private OutputStream mOutStream; @@ -138,8 +141,10 @@ public class PgpSignEncrypt {          private byte[] mNfcSignedHash = null;          private Date mNfcCreationTimestamp = null; -        public Builder(ProviderHelper providerHelper, InputData data, OutputStream outStream) { +        public Builder(ProviderHelper providerHelper, PassphraseCacheInterface passphraseCache, +                       InputData data, OutputStream outStream) {              mProviderHelper = providerHelper; +            mPassphraseCache = passphraseCache;              mData = data;              mOutStream = outStream;          } @@ -290,20 +295,15 @@ public class PgpSignEncrypt {          /* Get keys for signature generation for later usage */          CanonicalizedSecretKey signingKey = null; +        long signKeyId;          if (enableSignature) { -            // If we weren't handed a passphrase, throw early -            if (mSignaturePassphrase == null) { -                log.add(LogType.MSG_SE_ERROR_NO_PASSPHRASE, indent); -                return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); -            } -              try {                  // fetch the indicated master key id (the one whose name we sign in)                  CanonicalizedSecretKeyRing signingKeyRing =                          mProviderHelper.getCanonicalizedSecretKeyRing(mSignatureMasterKeyId);                  // fetch the specific subkey to sign with, or just use the master key if none specified -                long signKeyId = mSignatureSubKeyId != null ? mSignatureSubKeyId : mSignatureMasterKeyId; +                signKeyId = mSignatureSubKeyId != null ? mSignatureSubKeyId : mSignatureMasterKeyId;                  signingKey = signingKeyRing.getSecretKey(signKeyId);                  // make sure it's a signing key alright!              } catch (ProviderHelper.NotFoundException e) { @@ -317,6 +317,28 @@ public class PgpSignEncrypt {                  return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log);              } +            // if no passphrase was explicitly set try to get it from the cache service +            if (mSignaturePassphrase == null) { +                try { +                    // returns "" if key has no passphrase +                    mSignaturePassphrase = mPassphraseCache.getCachedPassphrase(signKeyId); +                    // TODO +//                    log.add(LogType.MSG_DC_PASS_CACHED, indent + 1); +                } catch (PassphraseCacheInterface.NoSecretKeyException e) { +                    // TODO +//                    log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); +                    return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); +                } + +                // if passphrase was not cached, return here indicating that a passphrase is missing! +                if (mSignaturePassphrase == null) { +                    log.add(LogType.MSG_SE_PENDING_PASSPHRASE, indent + 1); +                    SignEncryptResult result = new SignEncryptResult(SignEncryptResult.RESULT_PENDING_PASSPHRASE, log); +                    result.setKeyIdPassphraseNeeded(signKeyId); +                    return result; +                } +            } +              updateProgress(R.string.progress_extracting_signature_key, 0, 100);              try { @@ -369,10 +391,10 @@ public class PgpSignEncrypt {                          log.add(LogType.MSG_SE_KEY_OK, indent + 1,                                  PgpKeyHelper.convertKeyIdToHex(id));                      } catch (PgpGeneralException e) { -                        log.add(LogType.MSG_SE_KEY_WARN, indent +1, +                        log.add(LogType.MSG_SE_KEY_WARN, indent + 1,                                  PgpKeyHelper.convertKeyIdToHex(id));                      } catch (ProviderHelper.NotFoundException e) { -                        log.add(LogType.MSG_SE_KEY_UNKNOWN, indent +1, +                        log.add(LogType.MSG_SE_KEY_UNKNOWN, indent + 1,                                  PgpKeyHelper.convertKeyIdToHex(id));                      }                  } @@ -407,9 +429,10 @@ public class PgpSignEncrypt {                  /* actual encryption */                  updateProgress(R.string.progress_encrypting, 8, 100);                  log.add(enableSignature -                        ? LogType.MSG_SE_SIGCRYPTING -                        : LogType.MSG_SE_ENCRYPTING, -                        indent); +                                ? LogType.MSG_SE_SIGCRYPTING +                                : LogType.MSG_SE_ENCRYPTING, +                        indent +                );                  indent += 1;                  encryptionOut = cPk.open(out, new byte[1 << 16]); 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 a26ee009a..c11f283be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -32,6 +32,7 @@ import org.openintents.openpgp.OpenPgpSignatureResult;  import org.openintents.openpgp.util.OpenPgpApi;  import org.sufficientlysecure.keychain.nfc.NfcActivity;  import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;  import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;  import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;  import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult; @@ -259,6 +260,17 @@ public class OpenPgpService extends RemoteService {                  // sign-only                  PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(                          new ProviderHelper(getContext()), +                        new PassphraseCacheInterface() { +                            @Override +                            public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException { +                                try { +                                    return PassphraseCacheService.getCachedPassphrase( +                                            OpenPgpService.this, masterKeyId); +                                } catch (PassphraseCacheService.KeyNotFoundException e) { +                                    throw new PassphraseCacheInterface.NoSecretKeyException(); +                                } +                            } +                        },                          inputData, os);                  builder.setEnableAsciiArmorOutput(asciiArmor)                          .setVersionHeader(PgpHelper.getVersionForHeader(this)) @@ -271,24 +283,27 @@ public class OpenPgpService extends RemoteService {                  builder.setCleartextInput(true);                  // execute PGP operation! -                SignEncryptResult result = builder.build().execute(); - -                if (result.isPending()) { -                    switch (result.getResult()) { -                        case SignEncryptResult.RESULT_PENDING_NFC: -                            // return PendingIntent to execute NFC activity -                            // pass through the signature creation timestamp to be used again on second execution -                            // of PgpSignEncrypt when we have the signed hash! -                            data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, result.getNfcTimestamp().getTime()); -                            return getNfcSignIntent(data, passphrase, result.getNfcHash(), result.getNfcAlgo()); - -                        default: -                            throw new Exception("Encountered unhandled pending state - please file a bug report!"); +                SignEncryptResult pgpResult = builder.build().execute(); + +                if (pgpResult.isPending()) { +                    if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == +                            SignEncryptResult.RESULT_PENDING_PASSPHRASE) { +                        return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); +                    } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == +                            SignEncryptResult.RESULT_PENDING_NFC) { +                        // return PendingIntent to execute NFC activity +                        // pass through the signature creation timestamp to be used again on second execution +                        // of PgpSignEncrypt when we have the signed hash! +                        data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime()); +                        return getNfcSignIntent(data, passphrase, pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); +                    } else { +                        throw new PgpGeneralException( +                                "Encountered unhandled type of pending action not supported by API!");                      } -                } - -                if (!result.success()) { -                    LogEntryParcel errorMsg = result.getLog().getLast(); +                } else if (pgpResult.success()) { +                    // see end of method +                } else { +                    LogEntryParcel errorMsg = pgpResult.getLog().getLast();                      throw new Exception(getString(errorMsg.mType.getMsgId()));                  } @@ -346,6 +361,17 @@ public class OpenPgpService extends RemoteService {                  PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(                          new ProviderHelper(getContext()), +                        new PassphraseCacheInterface() { +                            @Override +                            public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException { +                                try { +                                    return PassphraseCacheService.getCachedPassphrase( +                                            OpenPgpService.this, masterKeyId); +                                } catch (PassphraseCacheService.KeyNotFoundException e) { +                                    throw new PassphraseCacheInterface.NoSecretKeyException(); +                                } +                            } +                        },                          inputData, os);                  builder.setEnableAsciiArmorOutput(asciiArmor)                          .setVersionHeader(PgpHelper.getVersionForHeader(this)) @@ -384,24 +410,27 @@ public class OpenPgpService extends RemoteService {                  }                  // execute PGP operation! -                SignEncryptResult result = builder.build().execute(); - -                if (result.isPending()) { -                    switch (result.getResult()) { -                        case SignEncryptResult.RESULT_PENDING_NFC: -                            // return PendingIntent to execute NFC activity -                            // pass through the signature creation timestamp to be used again on second execution -                            // of PgpSignEncrypt when we have the signed hash! -                            data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, result.getNfcTimestamp().getTime()); -                            return getNfcSignIntent(data, passphrase, result.getNfcHash(), result.getNfcAlgo()); - -                        default: -                            throw new Exception("Encountered unhandled pending state - please file a bug report!"); +                SignEncryptResult pgpResult = builder.build().execute(); + +                if (pgpResult.isPending()) { +                    if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == +                            SignEncryptResult.RESULT_PENDING_PASSPHRASE) { +                        return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); +                    } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == +                            SignEncryptResult.RESULT_PENDING_NFC) { +                        // return PendingIntent to execute NFC activity +                        // pass through the signature creation timestamp to be used again on second execution +                        // of PgpSignEncrypt when we have the signed hash! +                        data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime()); +                        return getNfcSignIntent(data, passphrase, pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); +                    } else { +                        throw new PgpGeneralException( +                                "Encountered unhandled type of pending action not supported by API!");                      } -                } - -                if (!result.success()) { -                    LogEntryParcel errorMsg = result.getLog().getLast(); +                } else if (pgpResult.success()) { +                    // see end of method +                } else { +                    LogEntryParcel errorMsg = pgpResult.getLog().getLast();                      throw new Exception(getString(errorMsg.mType.getMsgId()));                  } @@ -445,14 +474,14 @@ public class OpenPgpService extends RemoteService {                  PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(                          new ProviderHelper(this), -                        new PgpDecryptVerify.PassphraseCache() { +                        new PassphraseCacheInterface() {                              @Override -                            public String getCachedPassphrase(long masterKeyId) throws PgpDecryptVerify.NoSecretKeyException { +                            public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {                                  try {                                      return PassphraseCacheService.getCachedPassphrase(                                              OpenPgpService.this, masterKeyId);                                  } catch (PassphraseCacheService.KeyNotFoundException e) { -                                    throw new PgpDecryptVerify.NoSecretKeyException(); +                                    throw new PassphraseCacheInterface.NoSecretKeyException();                                  }                              }                          }, @@ -470,57 +499,64 @@ public class OpenPgpService extends RemoteService {                          .setNfcState(nfcDecryptedSessionKey);                  // TODO: currently does not support binary signed-only content -                DecryptVerifyResult decryptVerifyResult = builder.build().execute(); - -                if (decryptVerifyResult.isPending()) { -                    switch (decryptVerifyResult.getResult()) { -                        case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE: -                            return getPassphraseIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded()); -                        case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE: -                            throw new PgpGeneralException( -                                    "Decryption of symmetric content not supported by API!"); -                        case DecryptVerifyResult.RESULT_PENDING_NFC: -                            // TODO get passphrase here? currently not in DecryptVerifyResult -                            return getNfcDecryptIntent( -                                    data, null, decryptVerifyResult.getNfcEncryptedSessionKey()); +                DecryptVerifyResult pgpResult = builder.build().execute(); + +                if (pgpResult.isPending()) { +                    if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == +                            DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { +                        return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); +                    } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == +                            DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { +                        throw new PgpGeneralException( +                                "Decryption of symmetric content not supported by API!"); +                    } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == +                            DecryptVerifyResult.RESULT_PENDING_NFC) { +                        // TODO get passphrase here? currently not in DecryptVerifyResult +                        return getNfcDecryptIntent( +                                data, null, pgpResult.getNfcEncryptedSessionKey()); +                    } else { +                        throw new PgpGeneralException( +                                "Encountered unhandled type of pending action not supported by API!");                      } -                    throw new PgpGeneralException( -                            "Encountered unhandled type of pending action not supported by API!"); -                } +                } else if (pgpResult.success()) { -                OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); -                if (signatureResult != null) { -                    result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); +                    OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult(); +                    if (signatureResult != null) { +                        result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); -                    if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) { -                        // SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5 -                        if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED -                                || signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) { -                            signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); +                        if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) { +                            // SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5 +                            if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED +                                    || signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) { +                                signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); +                            }                          } -                    } -                    if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) { -                        // If signature is unknown we return an _additional_ PendingIntent -                        // to retrieve the missing key -                        Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); -                        intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE); -                        intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId()); -                        intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); +                        if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) { +                            // If signature is unknown we return an _additional_ PendingIntent +                            // to retrieve the missing key +                            Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); +                            intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE); +                            intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId()); +                            intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); -                        PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, -                                intent, -                                PendingIntent.FLAG_CANCEL_CURRENT); +                            PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, +                                    intent, +                                    PendingIntent.FLAG_CANCEL_CURRENT); -                        result.putExtra(OpenPgpApi.RESULT_INTENT, pi); +                            result.putExtra(OpenPgpApi.RESULT_INTENT, pi); +                        }                      } -                } -                if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) { -                    OpenPgpMetadata metadata = decryptVerifyResult.getDecryptMetadata(); -                    if (metadata != null) { -                        result.putExtra(OpenPgpApi.RESULT_METADATA, metadata); +                    if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) { +                        OpenPgpMetadata metadata = pgpResult.getDecryptMetadata(); +                        if (metadata != null) { +                            result.putExtra(OpenPgpApi.RESULT_METADATA, metadata); +                        }                      } +                } else { +                    LogEntryParcel errorMsg = pgpResult.getLog().getLast(); +                    throw new Exception(getString(errorMsg.mType.getMsgId()));                  }              } finally {                  is.close(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 19248dfa3..9d06fe22a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;  import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;  import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;  import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;  import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;  import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult;  import org.sufficientlysecure.keychain.pgp.PgpHelper; @@ -269,6 +270,17 @@ public class KeychainIntentService extends IntentService implements Progressable                      /* Operation */                      PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(                              new ProviderHelper(this), +                            new PassphraseCacheInterface() { +                                @Override +                                public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException { +                                    try { +                                        return PassphraseCacheService.getCachedPassphrase( +                                                KeychainIntentService.this, masterKeyId); +                                    } catch (PassphraseCacheService.KeyNotFoundException e) { +                                        throw new PassphraseCacheInterface.NoSecretKeyException(); +                                    } +                                } +                            },                              inputData, outStream                      );                      builder.setProgressable(this) @@ -342,14 +354,14 @@ public class KeychainIntentService extends IntentService implements Progressable                  // verification of signatures                  PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(                          new ProviderHelper(this), -                        new PgpDecryptVerify.PassphraseCache() { +                        new PassphraseCacheInterface() {                              @Override -                            public String getCachedPassphrase(long masterKeyId) { +                            public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {                                  try {                                      return PassphraseCacheService.getCachedPassphrase(                                              KeychainIntentService.this, masterKeyId);                                  } catch (PassphraseCacheService.KeyNotFoundException e) { -                                    return null; +                                    throw new PassphraseCacheInterface.NoSecretKeyException();                                  }                              }                          }, @@ -390,14 +402,14 @@ public class KeychainIntentService extends IntentService implements Progressable                  // verification of signatures                  PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(                          new ProviderHelper(this), -                        new PgpDecryptVerify.PassphraseCache() { +                        new PassphraseCacheInterface() {                              @Override -                            public String getCachedPassphrase(long masterKeyId) throws PgpDecryptVerify.NoSecretKeyException { +                            public String getCachedPassphrase(long masterKeyId) throws PassphraseCacheInterface.NoSecretKeyException {                                  try {                                      return PassphraseCacheService.getCachedPassphrase(                                              KeychainIntentService.this, masterKeyId);                                  } catch (PassphraseCacheService.KeyNotFoundException e) { -                                    throw new PgpDecryptVerify.NoSecretKeyException(); +                                    throw new PassphraseCacheInterface.NoSecretKeyException();                                  }                              }                          }, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/DecryptVerifyResult.java index 18533ffe6..2113c1ab1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/DecryptVerifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/DecryptVerifyResult.java @@ -26,12 +26,12 @@ import org.openintents.openpgp.OpenPgpSignatureResult;  public class DecryptVerifyResult extends OperationResult {      // the fourth bit indicates a "data pending" result! (it's also a form of non-success) -    public static final int RESULT_PENDING = RESULT_ERROR +8; +    public static final int RESULT_PENDING = RESULT_ERROR + 8;      // fifth to sixth bit in addition indicate specific type of pending -    public static final int RESULT_PENDING_ASYM_PASSPHRASE = RESULT_PENDING +16; -    public static final int RESULT_PENDING_SYM_PASSPHRASE = RESULT_PENDING +32; -    public static final int RESULT_PENDING_NFC = RESULT_PENDING +48; +    public static final int RESULT_PENDING_ASYM_PASSPHRASE = RESULT_PENDING + 16; +    public static final int RESULT_PENDING_SYM_PASSPHRASE = RESULT_PENDING + 32; +    public static final int RESULT_PENDING_NFC = RESULT_PENDING + 48;      long mKeyIdPassphraseNeeded;      byte[] mNfcSessionKey; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java index 39946a026..714f8d9cf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java @@ -475,7 +475,6 @@ public abstract class OperationResult implements Parcelable {          MSG_SE_ERROR_SIGN_KEY(LogLevel.ERROR, R.string.msg_se_error_sign_key),          MSG_SE_ERROR_KEY_SIGN (LogLevel.ERROR, R.string.msg_se_error_key_sign),          MSG_SE_ERROR_NFC (LogLevel.ERROR, R.string.msg_se_error_nfc), -        MSG_SE_ERROR_NO_PASSPHRASE (LogLevel.ERROR, R.string.msg_se_error_no_passphrase),          MSG_SE_ERROR_PGP (LogLevel.ERROR, R.string.msg_se_error_pgp),          MSG_SE_ERROR_SIG (LogLevel.ERROR, R.string.msg_se_error_sig),          MSG_SE_ERROR_UNLOCK (LogLevel.ERROR, R.string.msg_se_error_unlock), @@ -484,6 +483,7 @@ public abstract class OperationResult implements Parcelable {          MSG_SE_KEY_WARN (LogLevel.WARN, R.string.msg_se_key_warn),          MSG_SE_OK (LogLevel.OK, R.string.msg_se_ok),          MSG_SE_PENDING_NFC (LogLevel.INFO, R.string.msg_se_pending_nfc), +        MSG_SE_PENDING_PASSPHRASE (LogLevel.INFO, R.string.msg_se_pending_passphrase),          MSG_SE (LogLevel.DEBUG, R.string.msg_se),          MSG_SE_SIGNING (LogLevel.DEBUG, R.string.msg_se_signing),          MSG_SE_SIGCRYPTING (LogLevel.DEBUG, R.string.msg_se_sigcrypting), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java index 9d492e545..e4e843e83 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java @@ -24,15 +24,26 @@ import java.util.Date;  public class SignEncryptResult extends OperationResult {      // the fourth bit indicates a "data pending" result! (it's also a form of non-success) -    public static final int RESULT_PENDING = RESULT_ERROR +8; +    public static final int RESULT_PENDING = RESULT_ERROR + 8;      // fifth to sixth bit in addition indicate specific type of pending -    public static final int RESULT_PENDING_NFC = RESULT_PENDING +16; +    public static final int RESULT_PENDING_PASSPHRASE = RESULT_PENDING + 16; +    public static final int RESULT_PENDING_NFC = RESULT_PENDING + 32; + +    long mKeyIdPassphraseNeeded;      byte[] mNfcHash;      int mNfcAlgo;      Date mNfcTimestamp; +    public long getKeyIdPassphraseNeeded() { +        return mKeyIdPassphraseNeeded; +    } + +    public void setKeyIdPassphraseNeeded(long keyIdPassphraseNeeded) { +        mKeyIdPassphraseNeeded = keyIdPassphraseNeeded; +    } +      public void setNfcData(byte[] sessionKey, int nfcAlgo, Date nfcTimestamp) {          mNfcHash = sessionKey;          mNfcAlgo = nfcAlgo; @@ -52,7 +63,7 @@ public class SignEncryptResult extends OperationResult {      }      public boolean isPending() { -        return (mResult & RESULT_PENDING) != 0; +        return (mResult & RESULT_PENDING) == RESULT_PENDING;      }      public SignEncryptResult(int result, OperationLog log) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 4bf1cad3c..56a2ef233 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -22,7 +22,6 @@ import android.app.ProgressDialog;  import android.content.Intent;  import android.net.Uri;  import android.os.Bundle; -import android.os.Handler;  import android.os.Message;  import android.os.Messenger;  import android.support.v4.app.Fragment; @@ -35,15 +34,11 @@ import org.sufficientlysecure.keychain.api.OpenKeychainIntents;  import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;  import org.sufficientlysecure.keychain.helper.Preferences;  import org.sufficientlysecure.keychain.helper.ShareHelper; +import org.sufficientlysecure.keychain.nfc.NfcActivity;  import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.ProviderHelper;  import org.sufficientlysecure.keychain.service.KeychainIntentService;  import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService;  import org.sufficientlysecure.keychain.service.results.SignEncryptResult; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.Notify; @@ -200,22 +195,36 @@ public class EncryptTextActivity extends DrawerActivity implements EncryptActivi                      SignEncryptResult result =                              message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); -                    // TODO if (result.isPending()) - -                    if (!result.success()) { -                        result.createNotify(EncryptTextActivity.this).show(); -                        return; -                    } - -                    if (mShareAfterEncrypt) { -                        // Share encrypted message/file -                        startActivity(sendWithChooserExcludingEncrypt(message)); +                    if (result.isPending()) { +                        Log.d(Constants.TAG, "result.getResult() " + result.getResult()); +                        if ((result.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == +                                SignEncryptResult.RESULT_PENDING_PASSPHRASE) { +                            Log.d(Constants.TAG, "passp"); +                            startPassphraseDialog(result.getKeyIdPassphraseNeeded()); +                        } else if ((result.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == +                                SignEncryptResult.RESULT_PENDING_NFC) { +                            Log.d(Constants.TAG, "nfc"); + +                            // use after nfc sign +////                                data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, result.getNfcTimestamp().getTime()); +                            startNfcSign("123456", result.getNfcHash(), result.getNfcAlgo()); +                        } else { +                            throw new RuntimeException("Unhandled pending result!"); +                        } + +                    } else if (result.success()) { +                        if (mShareAfterEncrypt) { +                            // Share encrypted message/file +                            startActivity(sendWithChooserExcludingEncrypt(message)); +                        } else { +                            // Copy to clipboard +                            copyToClipboard(message); +                            result.createNotify(EncryptTextActivity.this).show(); +                            // Notify.showNotify(EncryptTextActivity.this, +                            // R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO); +                        }                      } else { -                        // Copy to clipboard -                        copyToClipboard(message);                          result.createNotify(EncryptTextActivity.this).show(); -                        // Notify.showNotify(EncryptTextActivity.this, -                                // R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO);                      }                  }              } @@ -231,6 +240,36 @@ public class EncryptTextActivity extends DrawerActivity implements EncryptActivi          startService(intent);      } +    private void startNfcSign(String pin, byte[] hashToSign, int hashAlgo) { +        Intent data = new Intent(); + +        // build PendingIntent for Yubikey NFC operations +        Intent intent = new Intent(this, NfcActivity.class); +        intent.setAction(NfcActivity.ACTION_SIGN_HASH); +        // pass params through to activity that it can be returned again later to repeat pgp operation +        intent.putExtra(NfcActivity.EXTRA_DATA, data); +        intent.putExtra(NfcActivity.EXTRA_PIN, pin); + +        intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign); +        intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo); +        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + +        startActivityForResult(intent, 0); +    } + +    private void startPassphraseDialog(long subkeyId) { +        Intent data = new Intent(); + +        // build PendingIntent for Yubikey NFC operations +        Intent intent = new Intent(this, PassphraseDialogActivity.class); +        // pass params through to activity that it can be returned again later to repeat pgp operation +        intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); + +//        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + +        startActivityForResult(intent, 0); +    } +      private Bundle createEncryptBundle() {          // fill values for this action          Bundle data = new Bundle(); @@ -326,35 +365,35 @@ public class EncryptTextActivity extends DrawerActivity implements EncryptActivi                  return false;              } -            try { -                // TODO This should really not be decided here. We do need the info for the passphrase -                // TODO dialog fragment though, so that's just the way it is for now. -                if (mSigningKeyId != 0) { -                    CachedPublicKeyRing signingRing = -                            new ProviderHelper(this).getCachedPublicKeyRing(mSigningKeyId); -                    long sigSubKeyId = signingRing.getSignId(); -                    // Make sure the passphrase is cached, then start over. -                    if (PassphraseCacheService.getCachedPassphrase(this, sigSubKeyId) == null) { -                        PassphraseDialogFragment.show(this, sigSubKeyId, -                                new Handler() { -                                    @Override -                                    public void handleMessage(Message message) { -                                        if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { -                                            // restart -                                            startEncrypt(); -                                        } -                                    } -                                } -                        ); - -                        return false; -                    } -                } -            } catch (PgpGeneralException e) { -                Log.e(Constants.TAG, "Key not found!", e); -            } catch (PassphraseCacheService.KeyNotFoundException e) { -                Log.e(Constants.TAG, "Key not found!", e); -            } +//            try { +//                // TODO This should really not be decided here. We do need the info for the passphrase +//                // TODO dialog fragment though, so that's just the way it is for now. +//                if (mSigningKeyId != 0) { +//                    CachedPublicKeyRing signingRing = +//                            new ProviderHelper(this).getCachedPublicKeyRing(mSigningKeyId); +//                    long sigSubKeyId = signingRing.getSignId(); +//                    // Make sure the passphrase is cached, then start over. +//                    if (PassphraseCacheService.getCachedPassphrase(this, sigSubKeyId) == null) { +//                        PassphraseDialogFragment.show(this, sigSubKeyId, +//                                new Handler() { +//                                    @Override +//                                    public void handleMessage(Message message) { +//                                        if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { +//                                            // restart +//                                            startEncrypt(); +//                                        } +//                                    } +//                                } +//                        ); +// +//                        return false; +//                    } +//                } +//            } catch (PgpGeneralException e) { +//                Log.e(Constants.TAG, "Key not found!", e); +//            } catch (PassphraseCacheService.KeyNotFoundException e) { +//                Log.e(Constants.TAG, "Key not found!", e); +//            }          }          return true;      } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index fa9036565..b13cb7837 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -32,13 +32,12 @@ import org.sufficientlysecure.keychain.R;  public class EncryptTextFragment extends Fragment {      public static final String ARG_TEXT = "text"; -    private TextView mMessage = null; +    private TextView mText;      private View mEncryptShare;      private View mEncryptClipboard;      private EncryptActivityInterface mEncryptInterface; -      @Override      public void onAttach(Activity activity) {          super.onAttach(activity); @@ -56,8 +55,8 @@ public class EncryptTextFragment extends Fragment {      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {          View view = inflater.inflate(R.layout.encrypt_text_fragment, container, false); -        mMessage = (TextView) view.findViewById(R.id.message); -        mMessage.addTextChangedListener(new TextWatcher() { +        mText = (TextView) view.findViewById(R.id.encrypt_text_text); +        mText.addTextChangedListener(new TextWatcher() {              @Override              public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -98,7 +97,7 @@ public class EncryptTextFragment extends Fragment {          String text = mEncryptInterface.getMessage();          if (text != null) { -            mMessage.setText(text); +            mText.setText(text);          }      }  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index fa9444862..705eb51ce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -59,7 +59,7 @@ import org.sufficientlysecure.keychain.util.Log;  public class PassphraseDialogActivity extends FragmentActivity {      public static final String MESSAGE_DATA_PASSPHRASE = "passphrase"; -    public static final String EXTRA_SECRET_KEY_ID = "secret_key_id"; +    public static final String EXTRA_SUBKEY_ID = "secret_key_id";      @Override      protected void onCreate(Bundle savedInstanceState) { @@ -76,7 +76,7 @@ public class PassphraseDialogActivity extends FragmentActivity {          // this activity itself has no content view (see manifest) -        long keyId = getIntent().getLongExtra(EXTRA_SECRET_KEY_ID, 0); +        long keyId = getIntent().getLongExtra(EXTRA_SUBKEY_ID, 0);          show(this, keyId);      } @@ -92,7 +92,7 @@ public class PassphraseDialogActivity extends FragmentActivity {                  // do NOT check if the key even needs a passphrase. that's not our job here.                  PassphraseDialogFragment frag = new PassphraseDialogFragment();                  Bundle args = new Bundle(); -                args.putLong(EXTRA_SECRET_KEY_ID, keyId); +                args.putLong(EXTRA_SUBKEY_ID, keyId);                  frag.setArguments(args); @@ -116,7 +116,7 @@ public class PassphraseDialogActivity extends FragmentActivity {          @Override          public Dialog onCreateDialog(Bundle savedInstanceState) {              final Activity activity = getActivity(); -            mSubKeyId = getArguments().getLong(EXTRA_SECRET_KEY_ID); +            mSubKeyId = getArguments().getLong(EXTRA_SUBKEY_ID);              CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java index 4b40b7ef1..b33bb2763 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java @@ -2,12 +2,14 @@ package org.sufficientlysecure.keychain.ui.dialog;  import android.app.Activity;  import android.app.AlertDialog; +import android.view.ContextThemeWrapper;  import android.view.View;  import android.widget.TextView;  import org.sufficientlysecure.keychain.R; -/** This class extends AlertDiaog.Builder, styling the header using emphasis color. +/** + * This class extends AlertDiaog.Builder, styling the header using emphasis color.   * Note that this class is a huge hack, because dialog boxes aren't easily stylable.   * Also, the dialog NEEDS to be called with show() directly, not create(), otherwise   * the order of internal operations will lead to a crash! @@ -15,7 +17,9 @@ import org.sufficientlysecure.keychain.R;  public class CustomAlertDialogBuilder extends AlertDialog.Builder {      public CustomAlertDialogBuilder(Activity activity) { -        super(activity); +        // if the progress dialog is displayed from the application class, design is missing +        // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay +        super(new ContextThemeWrapper(activity, R.style.Theme_AppCompat_Light));      }      @Override diff --git a/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml index fab983fa5..f724604c2 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml @@ -13,7 +13,7 @@          android:orientation="vertical">          <EditText -            android:id="@+id/message" +            android:id="@+id/encrypt_text_text"              android:layout_width="match_parent"              android:layout_height="0dip"              android:gravity="top" diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 5d0127f5c..9f3a2dedf 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -823,6 +823,7 @@      <string name="msg_se_key_warn">"Bad key for encryption: %s"</string>      <string name="msg_se_ok">"Sign/Encrypt operation successful!"</string>      <string name="msg_se_pending_nfc">"NFC token required, requesting user input…"</string> +    <string name="msg_se_pending_passphrase">"Passphrase required, requesting user input…"</string>      <string name="msg_se_signing">"Signing data (without encryption)"</string>      <string name="msg_se_sigcrypting">"Encrypting data with signature"</string>      <string name="msg_se">"Starting sign and/or encrypt operation"</string>  | 
