aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PassphraseCacheInterface.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java26
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java49
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java192
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/DecryptVerifyResult.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/SignEncryptResult.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java137
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java8
-rw-r--r--OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml1
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>