aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/main
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-02-21 02:31:30 +0100
committerDominik Schürmann <dominik@dominikschuermann.de>2014-02-21 02:31:30 +0100
commitaaddd26b51a9d3a8e230a704cb33de8e9a5bcbef (patch)
tree257cdf197b20a450a3561c9e5e3cd83000792aa6 /OpenPGP-Keychain/src/main
parentb4f977673f32278e6a5c2ef5abd071e2d934adaf (diff)
downloadopen-keychain-aaddd26b51a9d3a8e230a704cb33de8e9a5bcbef.tar.gz
open-keychain-aaddd26b51a9d3a8e230a704cb33de8e9a5bcbef.tar.bz2
open-keychain-aaddd26b51a9d3a8e230a704cb33de8e9a5bcbef.zip
verification of cleartext signatures works
Diffstat (limited to 'OpenPGP-Keychain/src/main')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationIncoming.java77
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java16
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java17
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java39
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java6
5 files changed, 106 insertions, 49 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationIncoming.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationIncoming.java
index 3f0cb0d1a..7f78f6b07 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationIncoming.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationIncoming.java
@@ -168,15 +168,37 @@ public class PgpOperationIncoming {
return false;
}
- public Bundle decryptAndVerify()
+ /**
+ * Decrypts and/or verifies data based on parameters of class
+ *
+ * @return
+ * @throws IOException
+ * @throws PgpGeneralException
+ * @throws PGPException
+ * @throws SignatureException
+ */
+ public Bundle decryptVerify()
throws IOException, PgpGeneralException, PGPException, SignatureException {
-
Bundle returnData = new Bundle();
+
// automatically works with ascii armor input and binary
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
+ if (in instanceof ArmoredInputStream) {
+ ArmoredInputStream aIn = (ArmoredInputStream) in;
+ // it is ascii armored
+ Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine());
+
+ if (aIn.isClearText()) {
+ // a cleartext signature, verify it with the other method
+ return verifyCleartextSignature(aIn);
+ } else {
+ // go on...
+ }
+ }
PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
+ Log.d(Constants.TAG, "o: " + o.getClass().getName());
int currentProgress = 0;
updateProgress(R.string.progress_reading_data, currentProgress, 100);
@@ -345,7 +367,6 @@ public class PgpOperationIncoming {
updateProgress(R.string.progress_decrypting, currentProgress, 100);
PGPLiteralData literalData = (PGPLiteralData) dataChunk;
- OutputStream out = outStream;
byte[] buffer = new byte[1 << 16];
InputStream dataIn = literalData.getInputStream();
@@ -359,10 +380,11 @@ public class PgpOperationIncoming {
}
int n;
+ // TODO: progress calculation is broken here! Try to rework it based on commented code!
// int progress = 0;
long startPos = data.getStreamPosition();
while ((n = dataIn.read(buffer)) > 0) {
- out.write(buffer, 0, n);
+ outStream.write(buffer, 0, n);
// progress += n;
if (signature != null) {
try {
@@ -392,9 +414,13 @@ public class PgpOperationIncoming {
PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject();
PGPSignature messageSignature = signatureList.get(signatureIndex);
+ // these are not cleartext signatures!
+ returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, 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);
}
}
@@ -420,17 +446,29 @@ public class PgpOperationIncoming {
return returnData;
}
- // TODO: merge into decryptAndVerify by checking what the input is
- public Bundle verifyText() throws IOException, PgpGeneralException,
- PGPException, SignatureException {
+ /**
+ * This method verifies cleartext signatures
+ * as defined in http://tools.ietf.org/html/rfc4880#section-7
+ * <p/>
+ * The method is heavily based on
+ * pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
+ *
+ * @return
+ * @throws IOException
+ * @throws PgpGeneralException
+ * @throws PGPException
+ * @throws SignatureException
+ */
+ private Bundle verifyCleartextSignature(ArmoredInputStream aIn)
+ throws IOException, PgpGeneralException, PGPException, SignatureException {
Bundle returnData = new Bundle();
+ // cleartext signatures are never encrypted ;)
+ returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ArmoredInputStream aIn = new ArmoredInputStream(data.getInputStream());
updateProgress(R.string.progress_done, 0, 100);
- // mostly taken from pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
int lookAhead = readInputLine(lineOut, aIn);
byte[] lineSep = getLineSeparator();
@@ -489,13 +527,13 @@ public class PgpOperationIncoming {
if (signature == null) {
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true);
- if (progress != null)
- progress.setProgress(R.string.progress_done, 100, 100);
+ updateProgress(R.string.progress_done, 100, 100);
return returnData;
}
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
signature.init(contentVerifierBuilderProvider, signatureKey);
@@ -527,11 +565,11 @@ public class PgpOperationIncoming {
return returnData;
}
- private static boolean verifyKeyBinding(Context mContext, PGPSignature signature, PGPPublicKey signatureKey) {
+ private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) {
long signatureKeyId = signature.getKeyID();
boolean keyBinding_isok = false;
String userId = null;
- PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(mContext,
+ PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
signatureKeyId);
PGPPublicKey mKey = null;
if (signKeyRing != null) {
@@ -621,7 +659,14 @@ public class PgpOperationIncoming {
return primkeyBinding_isok;
}
- // taken from ClearSignedFileProcessor in BC
+ /**
+ * Mostly taken from ClearSignedFileProcessor in Bouncy Castle
+ *
+ * @param sig
+ * @param line
+ * @throws SignatureException
+ * @throws IOException
+ */
private static void processLine(PGPSignature sig, byte[] line)
throws SignatureException, IOException {
int length = getLengthWithoutWhiteSpace(line);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java
index 044fe5aad..fd859fd5a 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java
@@ -187,7 +187,17 @@ public class PgpOperationOutgoing {
}
}
- public void signAndEncrypt()
+ /**
+ * Signs and/or encrypts data based on parameters of class
+ *
+ * @throws IOException
+ * @throws PgpGeneralException
+ * @throws PGPException
+ * @throws NoSuchProviderException
+ * @throws NoSuchAlgorithmException
+ * @throws SignatureException
+ */
+ public void signEncrypt()
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException {
@@ -383,6 +393,8 @@ public class PgpOperationOutgoing {
}
armorOut.write(newline);
+
+ // update signature buffer with input line
if (signatureForceV3) {
signatureV3Generator.update(newline);
processLine(line, armorOut, signatureV3Generator);
@@ -430,7 +442,7 @@ public class PgpOperationOutgoing {
updateProgress(R.string.progress_done, 100, 100);
}
- // TODO: merge this into signAndEncrypt method!
+ // TODO: merge this into signEncrypt method!
// TODO: allow binary input for this class
public void generateSignature()
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
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 422ce010c..4ce1569f0 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
@@ -120,7 +120,6 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String ENCRYPT_PROVIDER_URI = "provider_uri";
// decrypt/verify
- public static final String DECRYPT_SIGNED_ONLY = "signed_only";
public static final String DECRYPT_RETURN_BYTES = "return_binary";
public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes";
public static final String DECRYPT_ASSUME_SYMMETRIC = "assume_symmetric";
@@ -185,6 +184,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
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";
@@ -338,7 +338,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
- builder.build().signAndEncrypt();
+ builder.build().signEncrypt();
} else {
Log.d(Constants.TAG, "encrypt...");
builder.enableAsciiArmorOutput(useAsciiArmor)
@@ -351,7 +351,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
- builder.build().signAndEncrypt();
+ builder.build().signEncrypt();
}
outStream.close();
@@ -404,7 +404,6 @@ public class KeychainIntentService extends IntentService implements ProgressDial
long secretKeyId = data.getLong(ENCRYPT_SECRET_KEY_ID);
byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES);
- boolean signedOnly = data.getBoolean(DECRYPT_SIGNED_ONLY);
boolean returnBytes = data.getBoolean(DECRYPT_RETURN_BYTES);
boolean assumeSymmetricEncryption = data.getBoolean(DECRYPT_ASSUME_SYMMETRIC);
@@ -484,14 +483,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
PgpOperationIncoming.Builder builder = new PgpOperationIncoming.Builder(this, inputData, outStream);
builder.progress(this);
- if (signedOnly) {
- resultData = builder.build().verifyText();
- } else {
- builder.assumeSymmetric(assumeSymmetricEncryption)
- .passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+ builder.assumeSymmetric(assumeSymmetricEncryption)
+ .passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
- resultData = builder.build().decryptAndVerify();
- }
+ resultData = builder.build().decryptVerify();
outStream.close();
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 74e311294..688537be5 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
@@ -168,7 +168,7 @@ public class OpenPgpService extends RemoteService {
.signatureForceV3(false)
.signatureKeyId(appSettings.getKeyId())
.signaturePassphrase(passphrase);
- builder.build().signAndEncrypt();
+ builder.build().signEncrypt();
} finally {
is.close();
os.close();
@@ -257,7 +257,7 @@ public class OpenPgpService extends RemoteService {
builder.signatureKeyId(Id.key.none);
}
// execute PGP operation!
- builder.build().signAndEncrypt();
+ builder.build().signEncrypt();
} finally {
is.close();
os.close();
@@ -297,7 +297,7 @@ public class OpenPgpService extends RemoteService {
// checked if it is text with BEGIN and END tags
// String message = new String(inputBytes);
// Log.d(Constants.TAG, "in: " + message);
- boolean signedOnly = false;
+// boolean signedOnly = false;
// Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message);
// if (matcher.matches()) {
// Log.d(Constants.TAG, "PGP_MESSAGE matched");
@@ -386,35 +386,37 @@ public class OpenPgpService extends RemoteService {
Bundle outputBundle;
PgpOperationIncoming.Builder builder = new PgpOperationIncoming.Builder(this, inputData, os);
- if (signedOnly) {
- outputBundle = builder.build().verifyText();
- } else {
- builder.assumeSymmetric(false)
- .passphrase(passphrase);
+// if (signedOnly) {
+// outputBundle = builder.build().verifyText();
+// } else {
+ builder.assumeSymmetric(false)
+ .passphrase(passphrase);
- // Do we want to do this: instead of trying to get the passphrase before
- // pause stream when passphrase is missing and then resume???
+ // Do we want to do this: instead of trying to get the passphrase before
+ // pause stream when passphrase is missing and then resume???
- // TODO: this also decrypts with other secret keys without passphrase!!!
- outputBundle = builder.build().decryptAndVerify();
- }
+ // TODO: this also decrypts with other secret keys without passphrase!!!
+ outputBundle = builder.build().decryptVerify();
+// }
// outputStream.close();
// byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
// get signature informations from bundle
- boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE);
+ boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE, false);
if (signature) {
long signatureKeyId = outputBundle
- .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);
+ .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, 0);
String signatureUserId = outputBundle
.getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
boolean signatureSuccess = outputBundle
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS);
+ .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
boolean signatureUnknown = outputBundle
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN);
+ .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, false);
+ boolean signatureOnly = outputBundle
+ .getBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false);
int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
if (signatureSuccess) {
@@ -423,8 +425,9 @@ public class OpenPgpService extends RemoteService {
signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
}
+ // TODO: signed only?!?!?!
sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId,
- signedOnly, signatureKeyId);
+ signatureOnly, signatureKeyId);
}
} finally {
is.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 1f3280af3..7df416417 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
@@ -83,6 +83,9 @@ public class DecryptActivity extends DrawerActivity {
private long mSignatureKeyId = 0;
private boolean mReturnResult = false;
+
+ // TODO: replace signed only checks with something more intelligent
+ // PgpOperationIncoming should handle all automatically!!!
private boolean mSignedOnly = false;
private boolean mAssumeSymmetricEncryption = false;
@@ -456,7 +459,7 @@ public class DecryptActivity extends DrawerActivity {
} else {
if (mDecryptTarget == Id.target.file) {
askForOutputFilename();
- } else {
+ } else { // mDecryptTarget == Id.target.message
decryptStart();
}
}
@@ -633,7 +636,6 @@ public class DecryptActivity extends DrawerActivity {
data.putLong(KeychainIntentService.ENCRYPT_SECRET_KEY_ID, mSecretKeyId);
- data.putBoolean(KeychainIntentService.DECRYPT_SIGNED_ONLY, mSignedOnly);
data.putBoolean(KeychainIntentService.DECRYPT_RETURN_BYTES, mReturnBinary);
data.putBoolean(KeychainIntentService.DECRYPT_ASSUME_SYMMETRIC, mAssumeSymmetricEncryption);