aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-03-04 20:53:44 +0100
committerDominik Schürmann <dominik@dominikschuermann.de>2014-03-04 20:53:44 +0100
commit06f9134eb1c386446d56fe58fa49c35b7482ed86 (patch)
treecb2d767bfea33dae7e23ff3f8e0b001c24a8eb3d /OpenPGP-Keychain
parent89a4c38cc09425ac2e302882a63a30bdfe8a7e86 (diff)
downloadopen-keychain-06f9134eb1c386446d56fe58fa49c35b7482ed86.tar.gz
open-keychain-06f9134eb1c386446d56fe58fa49c35b7482ed86.tar.bz2
open-keychain-06f9134eb1c386446d56fe58fa49c35b7482ed86.zip
Enforce private key for applications, verify signed-only texts without passphrase input, better internal decrypt and verify method
Diffstat (limited to 'OpenPGP-Keychain')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java137
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java88
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java19
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java111
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java57
5 files changed, 250 insertions, 162 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index fb97f3a5c..be80da4e3 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -18,8 +18,8 @@
package org.sufficientlysecure.keychain.pgp;
import android.content.Context;
-import android.os.Bundle;
+import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.openpgp.PGPCompressedData;
@@ -36,6 +36,7 @@ import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureList;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
@@ -53,7 +54,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
@@ -75,9 +76,10 @@ public class PgpDecryptVerify {
private InputData data;
private OutputStream outStream;
- private ProgressDialogUpdater progress;
- boolean assumeSymmetric;
- String passphrase;
+ private ProgressDialogUpdater progressDialogUpdater;
+ private boolean assumeSymmetric;
+ private String passphrase;
+ private long enforcedKeyId;
private PgpDecryptVerify(Builder builder) {
// private Constructor can only be called from Builder
@@ -85,9 +87,10 @@ public class PgpDecryptVerify {
this.data = builder.data;
this.outStream = builder.outStream;
- this.progress = builder.progress;
+ this.progressDialogUpdater = builder.progressDialogUpdater;
this.assumeSymmetric = builder.assumeSymmetric;
this.passphrase = builder.passphrase;
+ this.enforcedKeyId = builder.enforcedKeyId;
}
public static class Builder {
@@ -97,9 +100,10 @@ public class PgpDecryptVerify {
private OutputStream outStream;
// optional
- private ProgressDialogUpdater progress = null;
+ private ProgressDialogUpdater progressDialogUpdater = null;
private boolean assumeSymmetric = false;
private String passphrase = "";
+ private long enforcedKeyId = 0;
public Builder(Context context, InputData data, OutputStream outStream) {
this.context = context;
@@ -107,8 +111,8 @@ public class PgpDecryptVerify {
this.outStream = outStream;
}
- public Builder progress(ProgressDialogUpdater progress) {
- this.progress = progress;
+ public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) {
+ this.progressDialogUpdater = progressDialogUpdater;
return this;
}
@@ -122,20 +126,32 @@ public class PgpDecryptVerify {
return this;
}
+ /**
+ * Allow this key id alone for decryption.
+ * This means only ciphertexts encrypted for this private key can be decrypted.
+ *
+ * @param enforcedKeyId
+ * @return
+ */
+ public Builder enforcedKeyId(long enforcedKeyId) {
+ this.enforcedKeyId = enforcedKeyId;
+ return this;
+ }
+
public PgpDecryptVerify build() {
return new PgpDecryptVerify(this);
}
}
public void updateProgress(int message, int current, int total) {
- if (progress != null) {
- progress.setProgress(message, current, total);
+ if (progressDialogUpdater != null) {
+ progressDialogUpdater.setProgress(message, current, total);
}
}
public void updateProgress(int current, int total) {
- if (progress != null) {
- progress.setProgress(current, total);
+ if (progressDialogUpdater != null) {
+ progressDialogUpdater.setProgress(current, total);
}
}
@@ -177,9 +193,8 @@ public class PgpDecryptVerify {
* @throws PGPException
* @throws SignatureException
*/
- public Bundle execute()
+ public PgpDecryptVerifyResult execute()
throws IOException, PgpGeneralException, PGPException, SignatureException {
-
// automatically works with ascii armor input and binary
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
if (in instanceof ArmoredInputStream) {
@@ -207,9 +222,9 @@ public class PgpDecryptVerify {
* @throws PGPException
* @throws SignatureException
*/
- private Bundle decryptVerify(InputStream in)
+ private PgpDecryptVerifyResult decryptVerify(InputStream in)
throws IOException, PgpGeneralException, PGPException, SignatureException {
- Bundle returnData = new Bundle();
+ PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult();
PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc;
@@ -277,9 +292,38 @@ public class PgpDecryptVerify {
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID());
if (secretKey != null) {
+ // secret key exists in database
+
+ // allow only a specific key for decryption?
+ if (enforcedKeyId != 0) {
+ // TODO: improve this code! get master key directly!
+ PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, encData.getKeyID());
+ long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID();
+ Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
+ Log.d(Constants.TAG, "enforcedKeyId: " + enforcedKeyId);
+ Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
+
+ if (enforcedKeyId != masterKeyId) {
+ throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found));
+ }
+ }
+
pbe = encData;
+
+ // passphrase handling...
+ if (passphrase == null) {
+ // try to get cached passphrase
+ passphrase = PassphraseCacheService.getCachedPassphrase(context, encData.getKeyID());
+ }
+ // if passphrase was not cached, return here!
+ if (passphrase == null) {
+ returnData.setKeyPassphraseNeeded(true);
+ return returnData;
+ }
break;
}
+
+
}
}
@@ -317,6 +361,7 @@ public class PgpDecryptVerify {
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
Object dataChunk = plainFact.nextObject();
PGPOnePassSignature signature = null;
+ OpenPgpSignatureResult signatureResult = null;
PGPPublicKey signatureKey = null;
int signatureIndex = -1;
@@ -334,7 +379,7 @@ public class PgpDecryptVerify {
if (dataChunk instanceof PGPOnePassSignatureList) {
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
+ signatureResult = new OpenPgpSignatureResult();
PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
for (int i = 0; i < sigList.size(); ++i) {
signature = sigList.get(i);
@@ -354,12 +399,12 @@ public class PgpDecryptVerify {
if (signKeyRing != null) {
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
}
- returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId);
+ signatureResult.setUserId(userId);
break;
}
}
- returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
+ signatureResult.setKeyId(signatureKeyId);
if (signature != null) {
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
@@ -367,7 +412,7 @@ public class PgpDecryptVerify {
signature.init(contentVerifierBuilderProvider, signatureKey);
} else {
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true);
+ signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
}
dataChunk = plainFact.nextObject();
@@ -395,25 +440,24 @@ public class PgpDecryptVerify {
}
int n;
- // TODO: progress calculation is broken here! Try to rework it based on commented code!
-// int progress = 0;
+ // TODO: progressDialogUpdater calculation is broken here! Try to rework it based on commented code!
+// int progressDialogUpdater = 0;
long startPos = data.getStreamPosition();
while ((n = dataIn.read(buffer)) > 0) {
outStream.write(buffer, 0, n);
-// progress += n;
+// progressDialogUpdater += n;
if (signature != null) {
try {
signature.update(buffer, 0, n);
} catch (SignatureException e) {
- returnData
- .putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
+ signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
signature = null;
}
}
// TODO: dead code?!
- // unknown size, but try to at least have a moving, slowing down progress bar
-// currentProgress = startProgress + (endProgress - startProgress) * progress
-// / (progress + 100000);
+ // unknown size, but try to at least have a moving, slowing down progressDialogUpdater bar
+// currentProgress = startProgress + (endProgress - startProgress) * progressDialogUpdater
+// / (progressDialogUpdater + 100000);
if (data.getSize() - startPos == 0) {
currentProgress = endProgress;
} else {
@@ -430,17 +474,20 @@ public class PgpDecryptVerify {
PGPSignature messageSignature = signatureList.get(signatureIndex);
// these are not cleartext signatures!
- returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false);
+ // TODO: what about binary signatures?
+ signatureResult.setSignatureOnly(false);
//Now check binding signatures
boolean keyBinding_isok = verifyKeyBinding(context, messageSignature, signatureKey);
boolean sig_isok = signature.verify(messageSignature);
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, keyBinding_isok & sig_isok);
+ // TODO: implement CERTIFIED!
+ if (keyBinding_isok & sig_isok) {
+ signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED);
+ }
}
}
- // TODO: test if this integrity really check works!
if (encryptedData.isIntegrityProtected()) {
updateProgress(R.string.progress_verifying_integrity, 95, 100);
@@ -455,9 +502,12 @@ public class PgpDecryptVerify {
} else {
// no integrity check
Log.e(Constants.TAG, "Encrypted data was not integrity protected!");
+ // TODO: inform user?
}
updateProgress(R.string.progress_done, 100, 100);
+
+ returnData.setSignatureResult(signatureResult);
return returnData;
}
@@ -474,11 +524,12 @@ public class PgpDecryptVerify {
* @throws PGPException
* @throws SignatureException
*/
- private Bundle verifyCleartextSignature(ArmoredInputStream aIn)
+ private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn)
throws IOException, PgpGeneralException, PGPException, SignatureException {
- Bundle returnData = new Bundle();
+ PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult();
+ OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult();
// cleartext signatures are never encrypted ;)
- returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, true);
+ signatureResult.setSignatureOnly(true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -504,8 +555,6 @@ public class PgpDecryptVerify {
byte[] clearText = out.toByteArray();
outStream.write(clearText);
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
-
updateProgress(R.string.progress_processing_signature, 60, 100);
PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
@@ -533,15 +582,15 @@ public class PgpDecryptVerify {
if (signKeyRing != null) {
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
}
- returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId);
+ signatureResult.setUserId(userId);
break;
}
}
- returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId);
+ signatureResult.setKeyId(signatureKeyId);
if (signature == null) {
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true);
+ signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
updateProgress(R.string.progress_done, 100, 100);
return returnData;
}
@@ -574,9 +623,15 @@ public class PgpDecryptVerify {
//Now check binding signatures
boolean keyBinding_isok = verifyKeyBinding(context, signature, signatureKey);
- returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, sig_isok & keyBinding_isok);
+ if (sig_isok & keyBinding_isok) {
+ signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED);
+ }
+
+ // TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR????
updateProgress(R.string.progress_done, 100, 100);
+
+ returnData.setSignatureResult(signatureResult);
return returnData;
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java
new file mode 100644
index 000000000..0477c4fdf
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.pgp;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.openintents.openpgp.OpenPgpSignatureResult;
+
+public class PgpDecryptVerifyResult implements Parcelable {
+ boolean symmetricPassphraseNeeded;
+ boolean keyPassphraseNeeded;
+ OpenPgpSignatureResult signatureResult;
+
+ public boolean isSymmetricPassphraseNeeded() {
+ return symmetricPassphraseNeeded;
+ }
+
+ public void setSymmetricPassphraseNeeded(boolean symmetricPassphraseNeeded) {
+ this.symmetricPassphraseNeeded = symmetricPassphraseNeeded;
+ }
+
+ public boolean isKeyPassphraseNeeded() {
+ return keyPassphraseNeeded;
+ }
+
+ public void setKeyPassphraseNeeded(boolean keyPassphraseNeeded) {
+ this.keyPassphraseNeeded = keyPassphraseNeeded;
+ }
+
+ public OpenPgpSignatureResult getSignatureResult() {
+ return signatureResult;
+ }
+
+ public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
+ this.signatureResult = signatureResult;
+ }
+
+ public PgpDecryptVerifyResult() {
+
+ }
+
+ public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) {
+ this.symmetricPassphraseNeeded = b.symmetricPassphraseNeeded;
+ this.keyPassphraseNeeded = b.keyPassphraseNeeded;
+ this.signatureResult = b.signatureResult;
+ }
+
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte((byte) (symmetricPassphraseNeeded ? 1 : 0));
+ dest.writeByte((byte) (keyPassphraseNeeded ? 1 : 0));
+ dest.writeParcelable(signatureResult, 0);
+ }
+
+ public static final Creator<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() {
+ public PgpDecryptVerifyResult createFromParcel(final Parcel source) {
+ PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult();
+ vr.symmetricPassphraseNeeded = source.readByte() == 1;
+ vr.keyPassphraseNeeded = source.readByte() == 1;
+ vr.signatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
+ return vr;
+ }
+
+ public PgpDecryptVerifyResult[] newArray(final int size) {
+ return new PgpDecryptVerifyResult[size];
+ }
+ };
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 302dbea0b..9c499ebd7 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -44,6 +44,7 @@ import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
@@ -181,13 +182,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// decrypt/verify
public static final String RESULT_DECRYPTED_STRING = "decrypted_message";
public static final String RESULT_DECRYPTED_BYTES = "decrypted_data";
- public static final String RESULT_SIGNATURE = "signature";
- public static final String RESULT_SIGNATURE_KEY_ID = "signature_key_id";
- public static final String RESULT_SIGNATURE_USER_ID = "signature_user_id";
- public static final String RESULT_CLEARTEXT_SIGNATURE_ONLY = "signature_only";
-
- public static final String RESULT_SIGNATURE_SUCCESS = "signature_success";
- public static final String RESULT_SIGNATURE_UNKNOWN = "signature_unknown";
+ public static final String RESULT_DECRYPT_VERIFY_RESULT = "signature";
// import
public static final String RESULT_IMPORT_ADDED = "added";
@@ -489,15 +484,17 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// verifyText and decrypt returning additional resultData values for the
// verification of signatures
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
- builder.progress(this);
+ builder.progressDialogUpdater(this);
builder.assumeSymmetric(assumeSymmetricEncryption)
.passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
- resultData = builder.build().execute();
+ PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
outStream.close();
+ resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult);
+
/* Output */
switch (target) {
@@ -867,10 +864,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
}
/**
- * Set progress of ProgressDialog by sending message to handler on UI thread
+ * Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread
*/
public void setProgress(String message, int progress, int max) {
- Log.d(Constants.TAG, "Send message by setProgress with progress=" + progress + ", max="
+ Log.d(Constants.TAG, "Send message by setProgress with progressDialogUpdater=" + progress + ", max="
+ max);
Bundle data = new Bundle();
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
index 5d2f5a815..8b34c4421 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
@@ -21,7 +21,6 @@ import android.app.PendingIntent;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -33,9 +32,10 @@ import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -284,98 +284,29 @@ public class OpenPgpService extends RemoteService {
Intent result = new Intent();
try {
- // TODO:
- // fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream
- // should we allow to decrypt everything under every key id or only the one set?
- // TODO: instead of trying to get the passphrase before
- // pause stream when passphrase is missing and then resume
-
- // TODO: put this code into PgpDecryptVerify class
-
- // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
- // app, Fix this?
-// String passphrase = null;
-// if (!signedOnly) {
-// // BEGIN Get key
-// // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it
-// // better!
-// InputStream inputStream2 = new ByteArrayInputStream(inputBytes);
-//
-// // TODO: duplicates functions from DecryptActivity!
-// long secretKeyId;
-// try {
-// if (inputStream2.markSupported()) {
-// // should probably set this to the max size of two
-// // pgpF objects, if it even needs to be anything other
-// // than 0.
-// inputStream2.mark(200);
-// }
-// secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2);
-// if (secretKeyId == Id.key.none) {
-// throw new PgpGeneralException(getString(R.string.error_no_secret_key_found));
-// }
-// } catch (NoAsymmetricEncryptionException e) {
-// if (inputStream2.markSupported()) {
-// inputStream2.reset();
-// }
-// secretKeyId = Id.key.symmetric;
-// if (!PgpDecryptVerify.hasSymmetricEncryption(this, inputStream2)) {
-// throw new PgpGeneralException(
-// getString(R.string.error_no_known_encryption_found));
-// }
-// // we do not support symmetric decryption from the API!
-// throw new Exception("Symmetric decryption is not supported!");
-// }
-//
-// Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
-
- // NOTE: currently this only gets the passphrase for the key set for this client
- String passphrase;
- if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
- passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
- } else {
- passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
- }
- if (passphrase == null) {
- // get PendingIntent for passphrase input, add it to given params and return to client
- Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
- return passphraseBundle;
- }
-
+ String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
long inputLength = is.available();
InputData inputData = new InputData(is, inputLength);
- Bundle outputBundle;
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
-
- builder.assumeSymmetric(false)
+ builder.assumeSymmetric(false) // no support for symmetric encryption
+ .enforcedKeyId(appSettings.getKeyId()) // allow only the private key for this app for decryption
.passphrase(passphrase);
- // TODO: this also decrypts with other secret keys that have no passphrase!!!
- outputBundle = builder.build().execute();
-
- //TODO: instead of using all these wrapping use OpenPgpSignatureResult directly
- // in DecryptVerify class and then in DecryptActivity
- boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE, false);
- if (signature) {
- long signatureKeyId = outputBundle
- .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, 0);
- String signatureUserId = outputBundle
- .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
- boolean signatureSuccess = outputBundle
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
- boolean signatureUnknown = outputBundle
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, false);
- boolean signatureOnly = outputBundle
- .getBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false);
-
- // TODO: SIGNATURE_SUCCESS_CERTIFIED is currently not implemented
- int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
- if (signatureSuccess) {
- signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED;
- } else if (signatureUnknown) {
- signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
+ // TODO: currently does not support binary signed-only content
+ PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
+ if (decryptVerifyResult.isKeyPassphraseNeeded()) {
+ // get PendingIntent for passphrase input, add it to given params and return to client
+ Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
+ return passphraseBundle;
+ } else if (decryptVerifyResult.isSymmetricPassphraseNeeded()) {
+ throw new PgpGeneralException("Decryption of symmetric content not supported by API!");
+ }
+
+ OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
+ if (signatureResult != null) {
+ if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY) {
// If signature is unknown we return an additional PendingIntent
// to retrieve the missing key
// TODO!!!
@@ -390,11 +321,9 @@ public class OpenPgpService extends RemoteService {
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
}
-
- OpenPgpSignatureResult sigResult = new OpenPgpSignatureResult(signatureStatus,
- signatureUserId, signatureOnly, signatureKeyId);
- result.putExtra(OpenPgpApi.RESULT_SIGNATURE, sigResult);
+ result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
}
+
} finally {
is.close();
os.close();
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 9bb675db0..a81576687 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -25,6 +25,7 @@ import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.regex.Matcher;
+import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
@@ -32,6 +33,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.FileHelper;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
@@ -690,11 +692,15 @@ public class DecryptActivity extends DrawerActivity {
}
- if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE)) {
- String userId = returnData
- .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
- mSignatureKeyId = returnData
- .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);
+ PgpDecryptVerifyResult decryptVerifyResult =
+ returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
+
+ OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
+
+ if (signatureResult != null) {
+
+ String userId = signatureResult.getUserId();
+ mSignatureKeyId = signatureResult.getKeyId();
mUserIdRest.setText("id: "
+ PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId));
if (userId == null) {
@@ -707,19 +713,32 @@ public class DecryptActivity extends DrawerActivity {
}
mUserId.setText(userId);
- if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS)) {
- mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
- mLookupKey.setVisibility(View.GONE);
- } else if (returnData
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN)) {
- mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
- mLookupKey.setVisibility(View.VISIBLE);
- AppMsg.makeText(DecryptActivity.this,
- R.string.unknown_signature,
- AppMsg.STYLE_ALERT).show();
- } else {
- mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
- mLookupKey.setVisibility(View.GONE);
+ switch (signatureResult.getStatus()) {
+ case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
+ mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
+ mLookupKey.setVisibility(View.GONE);
+ break;
+ }
+
+ // TODO!
+// case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
+// break;
+// }
+
+ case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: {
+ mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
+ mLookupKey.setVisibility(View.VISIBLE);
+ AppMsg.makeText(DecryptActivity.this,
+ R.string.unknown_signature,
+ AppMsg.STYLE_ALERT).show();
+ break;
+ }
+
+ default: {
+ mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
+ mLookupKey.setVisibility(View.GONE);
+ break;
+ }
}
mSignatureLayout.setVisibility(View.VISIBLE);
}
@@ -733,7 +752,7 @@ public class DecryptActivity extends DrawerActivity {
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
- // show progress dialog
+ // show progressDialogUpdater dialog
saveHandler.showProgressDialog(this);
// start service with intent