aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-08-28 11:00:18 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2014-08-28 11:00:18 +0200
commitc0ebc926117d3e444c7c32bf3251880852000df6 (patch)
treeb84926b3eee5cf1cfd6d38a2c3bec23e8f0b6779 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp
parentad69e47cec58287d82978b28416db50f6c3feb77 (diff)
parentb193965e585d0d492cf2744e3c86ecc9e45b71d4 (diff)
downloadopen-keychain-c0ebc926117d3e444c7c32bf3251880852000df6.tar.gz
open-keychain-c0ebc926117d3e444c7c32bf3251880852000df6.tar.bz2
open-keychain-c0ebc926117d3e444c7c32bf3251880852000df6.zip
Merge branch 'master' into yubikey
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java71
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java40
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java131
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java751
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java92
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java28
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java2
17 files changed, 784 insertions, 394 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
index 1da66872d..8076a14f3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
index ce6498df1..7a63a7a42 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
index 972e45c2e..2c27c5c37 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -60,10 +61,6 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing {
return mRing;
}
- public void encode(ArmoredOutputStream stream) throws IOException {
- getRing().encode(stream);
- }
-
/** Getter that returns the subkey that should be used for signing. */
CanonicalizedPublicKey getEncryptionSubKey() throws PgpGeneralException {
PGPPublicKey key = getRing().getPublicKey(getEncryptId());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
index 877857553..c79dc45c3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
index 4f74a2336..d8b873d31 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
index 35020b815..3ef4b336e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
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 7d113241b..828bee848 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -523,13 +523,7 @@ public class PgpDecryptVerify {
// update signature buffer if signature is also present
if (signature != null) {
- try {
- signature.update(buffer, 0, length);
- } catch (SignatureException e) {
- Log.e(Constants.TAG, "SignatureException -> Not a valid signature!", e);
- signatureResultBuilder.validSignature(false);
- signature = null;
- }
+ signature.update(buffer, 0, length);
}
alreadyWritten += length;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
index 1cf027721..db360f810 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
@@ -29,7 +29,6 @@ import org.sufficientlysecure.keychain.util.Log;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.io.RandomAccessFile;
import java.security.SecureRandom;
import java.util.regex.Pattern;
@@ -68,76 +67,6 @@ public class PgpHelper {
}
}
-// public static final class content {
-// public static final int unknown = 0;
-// public static final int encrypted_data = 1;
-// public static final int keys = 2;
-// }
-//
-// public static int getStreamContent(Context context, InputStream inStream) throws IOException {
-//
-// InputStream in = PGPUtil.getDecoderStream(inStream);
-// PGPObjectFactory pgpF = new PGPObjectFactory(in);
-// Object object = pgpF.nextObject();
-// while (object != null) {
-// if (object instanceof PGPPublicKeyRing || object instanceof PGPSecretKeyRing) {
-// return Id.content.keys;
-// } else if (object instanceof PGPEncryptedDataList) {
-// return Id.content.encrypted_data;
-// }
-// object = pgpF.nextObject();
-// }
-//
-// return Id.content.unknown;
-// }
-
- /**
- * Generate a random filename
- *
- * @param length
- * @return
- */
- public static String generateRandomFilename(int length) {
- SecureRandom random = new SecureRandom();
-
- byte bytes[] = new byte[length];
- random.nextBytes(bytes);
- String result = "";
- for (int i = 0; i < length; ++i) {
- int v = (bytes[i] + 256) % 64;
- if (v < 10) {
- result += (char) ('0' + v);
- } else if (v < 36) {
- result += (char) ('A' + v - 10);
- } else if (v < 62) {
- result += (char) ('a' + v - 36);
- } else if (v == 62) {
- result += '_';
- } else if (v == 63) {
- result += '.';
- }
- }
- return result;
- }
-
- /**
- * Go once through stream to get length of stream. The length is later used to display progress
- * when encrypting/decrypting
- *
- * @param in
- * @return
- * @throws IOException
- */
- public static long getLengthOfStream(InputStream in) throws IOException {
- long size = 0;
- long n = 0;
- byte dummy[] = new byte[0x10000];
- while ((n = in.read(dummy)) > 0) {
- size += n;
- }
- return size;
- }
-
/**
* Deletes file securely by overwriting it with random data before deleting it.
* <p/>
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index f14eacda2..0bc3ac0ab 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
+import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -43,6 +44,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
public class PgpImportExport {
@@ -60,10 +62,14 @@ public class PgpImportExport {
private ProviderHelper mProviderHelper;
public PgpImportExport(Context context, Progressable progressable) {
+ this(context, new ProviderHelper(context), progressable);
+ }
+
+ public PgpImportExport(Context context, ProviderHelper providerHelper, Progressable progressable) {
super();
this.mContext = context;
this.mProgressable = progressable;
- this.mProviderHelper = new ProviderHelper(context);
+ this.mProviderHelper = providerHelper;
}
public PgpImportExport(Context context,
@@ -93,7 +99,7 @@ public class PgpImportExport {
}
}
- public boolean uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) {
+ public void uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) throws AddKeyException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = null;
try {
@@ -103,13 +109,9 @@ public class PgpImportExport {
String armoredKey = bos.toString("UTF-8");
server.add(armoredKey);
-
- return true;
} catch (IOException e) {
- return false;
- } catch (AddKeyException e) {
- // TODO: tell the user?
- return false;
+ Log.e(Constants.TAG, "IOException", e);
+ throw new AddKeyException();
} finally {
try {
if (aos != null) {
@@ -124,20 +126,23 @@ public class PgpImportExport {
/** Imports keys from given data. If keyIds is given only those are imported */
public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries) {
+ return importKeyRings(entries.iterator(), entries.size());
+ }
+ public ImportKeyResult importKeyRings(Iterator<ParcelableKeyRing> entries, int num) {
updateProgress(R.string.progress_importing, 0, 100);
// If there aren't even any keys, do nothing here.
- if (entries == null || entries.size() == 0) {
+ if (entries == null || !entries.hasNext()) {
return new ImportKeyResult(
- ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0);
+ ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0, 0);
}
- int newKeys = 0, oldKeys = 0, badKeys = 0;
+ int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0;
int position = 0;
- int progSteps = 100 / entries.size();
- for (ParcelableKeyRing entry : entries) {
+ double progSteps = 100.0 / num;
+ for (ParcelableKeyRing entry : new IterableIterator<ParcelableKeyRing>(entries)) {
try {
UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes());
@@ -157,10 +162,10 @@ public class PgpImportExport {
SaveKeyringResult result;
if (key.isSecret()) {
result = mProviderHelper.saveSecretKeyRing(key,
- new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
+ new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
} else {
result = mProviderHelper.savePublicKeyRing(key,
- new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
+ new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
}
if (!result.success()) {
badKeys += 1;
@@ -168,6 +173,9 @@ public class PgpImportExport {
oldKeys += 1;
} else {
newKeys += 1;
+ if (key.isSecret()) {
+ secret += 1;
+ }
}
} catch (IOException e) {
@@ -204,7 +212,7 @@ public class PgpImportExport {
}
}
- return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys);
+ return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
index 459b80be2..05acb86df 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
@@ -24,10 +24,16 @@ import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.bcpg.ECPublicBCPGKey;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.util.Log;
import java.security.DigestException;
@@ -37,18 +43,14 @@ import java.util.Locale;
public class PgpKeyHelper {
- public static String getAlgorithmInfo(int algorithm) {
- return getAlgorithmInfo(null, algorithm, 0);
- }
-
- public static String getAlgorithmInfo(Context context, int algorithm) {
- return getAlgorithmInfo(context, algorithm, 0);
+ public static String getAlgorithmInfo(int algorithm, Integer keySize, String oid) {
+ return getAlgorithmInfo(null, algorithm, keySize, oid);
}
/**
* Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
*/
- public static String getAlgorithmInfo(Context context, int algorithm, int keySize) {
+ public static String getAlgorithmInfo(Context context, int algorithm, Integer keySize, String oid) {
String algorithmStr;
switch (algorithm) {
@@ -69,10 +71,19 @@ public class PgpKeyHelper {
break;
}
- case PublicKeyAlgorithmTags.ECDSA:
+ case PublicKeyAlgorithmTags.ECDSA: {
+ if (oid == null) {
+ return "ECDSA";
+ }
+ String oidName = PgpKeyHelper.getCurveInfo(context, oid);
+ return "ECDSA (" + oidName + ")";
+ }
case PublicKeyAlgorithmTags.ECDH: {
- algorithmStr = "ECC";
- break;
+ if (oid == null) {
+ return "ECDH";
+ }
+ String oidName = PgpKeyHelper.getCurveInfo(context, oid);
+ return "ECDH (" + oidName + ")";
}
default: {
@@ -90,6 +101,106 @@ public class PgpKeyHelper {
return algorithmStr;
}
+ public static String getAlgorithmInfo(Algorithm algorithm, Integer keySize, Curve curve) {
+ return getAlgorithmInfo(null, algorithm, keySize, curve);
+ }
+
+ /**
+ * Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
+ */
+ public static String getAlgorithmInfo(Context context, Algorithm algorithm, Integer keySize, Curve curve) {
+ String algorithmStr;
+
+ switch (algorithm) {
+ case RSA: {
+ algorithmStr = "RSA";
+ break;
+ }
+ case DSA: {
+ algorithmStr = "DSA";
+ break;
+ }
+
+ case ELGAMAL: {
+ algorithmStr = "ElGamal";
+ break;
+ }
+
+ case ECDSA: {
+ algorithmStr = "ECDSA";
+ if (curve != null) {
+ algorithmStr += " (" + getCurveInfo(context, curve) + ")";
+ }
+ return algorithmStr;
+ }
+ case ECDH: {
+ algorithmStr = "ECDH";
+ if (curve != null) {
+ algorithmStr += " (" + getCurveInfo(context, curve) + ")";
+ }
+ return algorithmStr;
+ }
+
+ default: {
+ if (context != null) {
+ algorithmStr = context.getResources().getString(R.string.unknown_algorithm);
+ } else {
+ algorithmStr = "unknown";
+ }
+ break;
+ }
+ }
+ if (keySize != null && keySize > 0)
+ return algorithmStr + ", " + keySize + " bit";
+ else
+ return algorithmStr;
+ }
+
+ // Return name of a curve. These are names, no need for translation
+ public static String getCurveInfo(Context context, Curve curve) {
+ switch(curve) {
+ case NIST_P256:
+ return "NIST P-256";
+ case NIST_P384:
+ return "NIST P-384";
+ case NIST_P521:
+ return "NIST P-521";
+
+ /* see SaveKeyringParcel
+ case BRAINPOOL_P256:
+ return "Brainpool P-256";
+ case BRAINPOOL_P384:
+ return "Brainpool P-384";
+ case BRAINPOOL_P512:
+ return "Brainpool P-512";
+ */
+ }
+ if (context != null) {
+ return context.getResources().getString(R.string.unknown_algorithm);
+ } else {
+ return "unknown";
+ }
+ }
+
+ public static String getCurveInfo(Context context, String oidStr) {
+ ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(oidStr);
+
+ String name;
+ name = NISTNamedCurves.getName(oid);
+ if (name != null) {
+ return name;
+ }
+ name = TeleTrusTNamedCurves.getName(oid);
+ if (name != null) {
+ return name;
+ }
+ if (context != null) {
+ return context.getResources().getString(R.string.unknown_algorithm);
+ } else {
+ return "unknown";
+ }
+ }
+
/**
* Converts fingerprint to hex
* <p/>
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index bb692555e..967a7caa9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -20,12 +20,12 @@ package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.spongycastle.bcpg.HashAlgorithmTags;
-import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.spongycastle.bcpg.sig.Features;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.spec.ElGamalParameterSpec;
-import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPKeyFlags;
import org.spongycastle.openpgp.PGPKeyPair;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
@@ -34,7 +34,6 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
-import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
@@ -53,6 +52,8 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
@@ -67,6 +68,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.SignatureException;
+import java.security.spec.ECGenParameterSpec;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
@@ -84,15 +86,45 @@ import java.util.Stack;
public class PgpKeyOperation {
private Stack<Progressable> mProgress;
+ // most preferred is first
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
- SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
- SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5,
- SymmetricKeyAlgorithmTags.TRIPLE_DES};
- private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{HashAlgorithmTags.SHA1,
- HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160};
+ SymmetricKeyAlgorithmTags.AES_256,
+ SymmetricKeyAlgorithmTags.AES_192,
+ SymmetricKeyAlgorithmTags.AES_128,
+ SymmetricKeyAlgorithmTags.CAST5
+ };
+ private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{
+ HashAlgorithmTags.SHA512,
+ HashAlgorithmTags.SHA384,
+ HashAlgorithmTags.SHA224,
+ HashAlgorithmTags.SHA256,
+ HashAlgorithmTags.RIPEMD160
+ };
private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{
- CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2,
- CompressionAlgorithmTags.ZIP};
+ CompressionAlgorithmTags.ZLIB,
+ CompressionAlgorithmTags.BZIP2,
+ CompressionAlgorithmTags.ZIP
+ };
+
+ /*
+ * Note: s2kcount is a number between 0 and 0xff that controls the
+ * number of times to iterate the password hash before use. More
+ * iterations are useful against offline attacks, as it takes more
+ * time to check each password. The actual number of iterations is
+ * rather complex, and also depends on the hash function in use.
+ * Refer to Section 3.7.1.3 in rfc4880.txt. Bigger numbers give
+ * you more iterations. As a rough rule of thumb, when using
+ * SHA256 as the hashing function, 0x10 gives you about 64
+ * iterations, 0x20 about 128, 0x30 about 256 and so on till 0xf0,
+ * or about 1 million iterations. The maximum you can go to is
+ * 0xff, or about 2 million iterations. I'll use 0xc0 as a
+ * default -- about 130,000 iterations.
+ *
+ * http://kbsriram.com/2013/01/generating-rsa-keys-with-bouncycastle.html
+ */
+ private static final int SECRET_KEY_ENCRYPTOR_HASH_ALGO = HashAlgorithmTags.SHA512;
+ private static final int SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO = SymmetricKeyAlgorithmTags.AES_256;
+ private static final int SECRET_KEY_ENCRYPTOR_S2K_COUNT = 0x60;
public PgpKeyOperation(Progressable progress) {
super();
@@ -126,31 +158,65 @@ public class PgpKeyOperation {
mProgress.peek().setProgress(message, current, 100);
}
+ private ECGenParameterSpec getEccParameterSpec(Curve curve) {
+ switch (curve) {
+ case NIST_P256: return new ECGenParameterSpec("P-256");
+ case NIST_P384: return new ECGenParameterSpec("P-384");
+ case NIST_P521: return new ECGenParameterSpec("P-521");
+
+ // @see SaveKeyringParcel
+ // case BRAINPOOL_P256: return new ECGenParameterSpec("brainpoolp256r1");
+ // case BRAINPOOL_P384: return new ECGenParameterSpec("brainpoolp384r1");
+ // case BRAINPOOL_P512: return new ECGenParameterSpec("brainpoolp512r1");
+ }
+ throw new RuntimeException("Invalid choice! (can't happen)");
+ }
+
/** Creates new secret key. */
- private PGPKeyPair createKey(int algorithmChoice, int keySize, OperationLog log, int indent) {
+ private PGPKeyPair createKey(SubkeyAdd add, OperationLog log, int indent) {
try {
- if (keySize < 512) {
- log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_KEYSIZE_512, indent);
- return null;
+ // Some safety checks
+ if (add.mAlgorithm == Algorithm.ECDH || add.mAlgorithm == Algorithm.ECDSA) {
+ if (add.mCurve == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_CURVE, indent);
+ return null;
+ }
+ } else {
+ if (add.mKeySize == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_KEYSIZE, indent);
+ return null;
+ }
+ if (add.mKeySize < 512) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_KEYSIZE_512, indent);
+ return null;
+ }
}
int algorithm;
KeyPairGenerator keyGen;
- switch (algorithmChoice) {
- case PublicKeyAlgorithmTags.DSA: {
+ switch (add.mAlgorithm) {
+ case DSA: {
+ if ((add.mFlags & (PGPKeyFlags.CAN_ENCRYPT_COMMS | PGPKeyFlags.CAN_ENCRYPT_STORAGE)) > 0) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_DSA, indent);
+ return null;
+ }
progress(R.string.progress_generating_dsa, 30);
keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- keyGen.initialize(keySize, new SecureRandom());
+ keyGen.initialize(add.mKeySize, new SecureRandom());
algorithm = PGPPublicKey.DSA;
break;
}
- case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: {
+ case ELGAMAL: {
+ if ((add.mFlags & (PGPKeyFlags.CAN_SIGN | PGPKeyFlags.CAN_CERTIFY)) > 0) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ELGAMAL, indent);
+ return null;
+ }
progress(R.string.progress_generating_elgamal, 30);
keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- BigInteger p = Primes.getBestPrime(keySize);
+ BigInteger p = Primes.getBestPrime(add.mKeySize);
BigInteger g = new BigInteger("2");
ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
@@ -160,15 +226,44 @@ public class PgpKeyOperation {
break;
}
- case PublicKeyAlgorithmTags.RSA_GENERAL: {
+ case RSA: {
progress(R.string.progress_generating_rsa, 30);
keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- keyGen.initialize(keySize, new SecureRandom());
+ keyGen.initialize(add.mKeySize, new SecureRandom());
algorithm = PGPPublicKey.RSA_GENERAL;
break;
}
+ case ECDSA: {
+ if ((add.mFlags & (PGPKeyFlags.CAN_ENCRYPT_COMMS | PGPKeyFlags.CAN_ENCRYPT_STORAGE)) > 0) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ECDSA, indent);
+ return null;
+ }
+ progress(R.string.progress_generating_ecdsa, 30);
+ ECGenParameterSpec ecParamSpec = getEccParameterSpec(add.mCurve);
+ keyGen = KeyPairGenerator.getInstance("ECDSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ keyGen.initialize(ecParamSpec, new SecureRandom());
+
+ algorithm = PGPPublicKey.ECDSA;
+ break;
+ }
+
+ case ECDH: {
+ // make sure there are no sign or certify flags set
+ if ((add.mFlags & (PGPKeyFlags.CAN_SIGN | PGPKeyFlags.CAN_CERTIFY)) > 0) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ECDH, indent);
+ return null;
+ }
+ progress(R.string.progress_generating_ecdh, 30);
+ ECGenParameterSpec ecParamSpec = getEccParameterSpec(add.mCurve);
+ keyGen = KeyPairGenerator.getInstance("ECDH", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ keyGen.initialize(ecParamSpec, new SecureRandom());
+
+ algorithm = PGPPublicKey.ECDH;
+ break;
+ }
+
default: {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent);
return null;
@@ -181,7 +276,8 @@ public class PgpKeyOperation {
} catch(NoSuchProviderException e) {
throw new RuntimeException(e);
} catch(NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent);
+ return null;
} catch(InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
} catch(PGPException e) {
@@ -218,13 +314,13 @@ public class PgpKeyOperation {
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- if (add.mAlgorithm == PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT) {
- log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_MASTER_ELGAMAL, indent);
+ if (add.mExpiry == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NULL_EXPIRY, indent);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
subProgressPush(10, 30);
- PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ PGPKeyPair keyPair = createKey(add, log, indent);
subProgressPop();
// return null if this failed (an error will already have been logged by createKey)
@@ -234,13 +330,16 @@ public class PgpKeyOperation {
progress(R.string.progress_building_master_key, 40);
- // define hashing and signing algos
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA1);
// Build key encrypter and decrypter based on passphrase
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+
+ // NOTE: only SHA1 is supported for key checksum calculations.
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA1);
PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
sha1Calc, true, keyEncryptor);
@@ -248,7 +347,7 @@ public class PgpKeyOperation {
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
subProgressPush(50, 100);
- return internal(sKR, masterSecretKey, add.mFlags, saveParcel, "", log);
+ return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, "", log);
} catch (PGPException e) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
@@ -314,14 +413,17 @@ public class PgpKeyOperation {
// read masterKeyFlags, and use the same as before.
// since this is the master key, this contains at least CERTIFY_OTHER
- int masterKeyFlags = readKeyFlags(masterSecretKey.getPublicKey()) | KeyFlags.CERTIFY_OTHER;
+ PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
+ int masterKeyFlags = readKeyFlags(masterPublicKey) | KeyFlags.CERTIFY_OTHER;
+ long masterKeyExpiry = masterPublicKey.getValidSeconds() == 0L ? 0L :
+ masterPublicKey.getCreationTime().getTime() / 1000 + masterPublicKey.getValidSeconds();
- return internal(sKR, masterSecretKey, masterKeyFlags, saveParcel, passphrase, log);
+ return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, passphrase, log);
}
private EditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
- int masterKeyFlags,
+ int masterKeyFlags, long masterKeyExpiry,
SaveKeyringParcel saveParcel, String passphrase,
OperationLog log) {
@@ -346,177 +448,196 @@ public class PgpKeyOperation {
}
}
- // work on master secret key
try {
- PGPPublicKey modifiedPublicKey = masterPublicKey;
+ { // work on master secret key
- // 2a. Add certificates for new user ids
- subProgressPush(15, 25);
- for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
+ PGPPublicKey modifiedPublicKey = masterPublicKey;
- progress(R.string.progress_modify_adduid, (i-1) * (100 / saveParcel.mAddUserIds.size()));
- String userId = saveParcel.mAddUserIds.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent, userId);
+ // 2a. Add certificates for new user ids
+ subProgressPush(15, 25);
+ for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
- if (userId.equals("")) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_UID_ERROR_EMPTY, indent+1);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
+ progress(R.string.progress_modify_adduid, (i - 1) * (100 / saveParcel.mAddUserIds.size()));
+ String userId = saveParcel.mAddUserIds.get(i);
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent, userId);
- // this operation supersedes all previous binding and revocation certificates,
- // so remove those to retain assertions from canonicalization for later operations
- @SuppressWarnings("unchecked")
- Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId);
- if (it != null) {
- for (PGPSignature cert : new IterableIterator<PGPSignature>(it)) {
- if (cert.getKeyID() != masterPublicKey.getKeyID()) {
- // foreign certificate?! error error error
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
- if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
- || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
- || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, cert);
- }
+ if (userId.equals("")) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_UID_ERROR_EMPTY, indent + 1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- }
- // if it's supposed to be primary, we can do that here as well
- boolean isPrimary = saveParcel.mChangePrimaryUserId != null
- && userId.equals(saveParcel.mChangePrimaryUserId);
- // generate and add new certificate
- PGPSignature cert = generateUserIdSignature(masterPrivateKey,
- masterPublicKey, userId, isPrimary, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
- }
- subProgressPop();
+ // this operation supersedes all previous binding and revocation certificates,
+ // so remove those to retain assertions from canonicalization for later operations
+ @SuppressWarnings("unchecked")
+ Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId);
+ if (it != null) {
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(it)) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
+ || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, cert);
+ }
+ }
+ }
- // 2b. Add revocations for revoked user ids
- subProgressPush(25, 40);
- for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {
+ // if it's supposed to be primary, we can do that here as well
+ boolean isPrimary = saveParcel.mChangePrimaryUserId != null
+ && userId.equals(saveParcel.mChangePrimaryUserId);
+ // generate and add new certificate
+ PGPSignature cert = generateUserIdSignature(masterPrivateKey,
+ masterPublicKey, userId, isPrimary, masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ }
+ subProgressPop();
- progress(R.string.progress_modify_revokeuid, (i-1) * (100 / saveParcel.mRevokeUserIds.size()));
- String userId = saveParcel.mRevokeUserIds.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent, userId);
+ // 2b. Add revocations for revoked user ids
+ subProgressPush(25, 40);
+ for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) {
+
+ progress(R.string.progress_modify_revokeuid, (i - 1) * (100 / saveParcel.mRevokeUserIds.size()));
+ String userId = saveParcel.mRevokeUserIds.get(i);
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent, userId);
+
+ // Make sure the user id exists (yes these are 10 LoC in Java!)
+ boolean exists = false;
+ //noinspection unchecked
+ for (String uid : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
+ if (userId.equals(uid)) {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_REVOKE, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
- // a duplicate revocation will be removed during canonicalization, so no need to
- // take care of that here.
- PGPSignature cert = generateRevocationSignature(masterPrivateKey,
- masterPublicKey, userId);
- modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
- }
- subProgressPop();
+ // a duplicate revocation will be removed during canonicalization, so no need to
+ // take care of that here.
+ PGPSignature cert = generateRevocationSignature(masterPrivateKey,
+ masterPublicKey, userId);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
+ }
+ subProgressPop();
- // 3. If primary user id changed, generate new certificates for both old and new
- if (saveParcel.mChangePrimaryUserId != null) {
- progress(R.string.progress_modify_primaryuid, 40);
+ // 3. If primary user id changed, generate new certificates for both old and new
+ if (saveParcel.mChangePrimaryUserId != null) {
+ progress(R.string.progress_modify_primaryuid, 40);
- // keep track if we actually changed one
- boolean ok = false;
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent);
- indent += 1;
+ // keep track if we actually changed one
+ boolean ok = false;
+ log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent);
+ indent += 1;
- // we work on the modifiedPublicKey here, to respect new or newly revoked uids
- // noinspection unchecked
- for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
- boolean isRevoked = false;
- PGPSignature currentCert = null;
+ // we work on the modifiedPublicKey here, to respect new or newly revoked uids
// noinspection unchecked
- for (PGPSignature cert : new IterableIterator<PGPSignature>(
- modifiedPublicKey.getSignaturesForID(userId))) {
- if (cert.getKeyID() != masterPublicKey.getKeyID()) {
- // foreign certificate?! error error error
+ for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
+ boolean isRevoked = false;
+ PGPSignature currentCert = null;
+ // noinspection unchecked
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(
+ modifiedPublicKey.getSignaturesForID(userId))) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ // we know from canonicalization that if there is any revocation here, it
+ // is valid and not superseded by a newer certification.
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
+ isRevoked = true;
+ continue;
+ }
+ // we know from canonicalization that there is only one binding
+ // certification here, so we can just work with the first one.
+ if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ currentCert = cert;
+ }
+ }
+
+ if (currentCert == null) {
+ // no certificate found?! error error error
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- // we know from canonicalization that if there is any revocation here, it
- // is valid and not superseded by a newer certification.
- if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
- isRevoked = true;
+
+ // we definitely should not update certifications of revoked keys, so just leave it.
+ if (isRevoked) {
+ // revoked user ids cannot be primary!
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
continue;
}
- // we know from canonicalization that there is only one binding
- // certification here, so we can just work with the first one.
- if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
- cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
- currentCert = cert;
- }
- }
- if (currentCert == null) {
- // no certificate found?! error error error
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
-
- // we definitely should not update certifications of revoked keys, so just leave it.
- if (isRevoked) {
- // revoked user ids cannot be primary!
- if (userId.equals(saveParcel.mChangePrimaryUserId)) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ // if this is~ the/a primary user id
+ if (currentCert.getHashedSubPackets() != null
+ && currentCert.getHashedSubPackets().isPrimaryUserID()) {
+ // if it's the one we want, just leave it as is
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ ok = true;
+ continue;
+ }
+ // otherwise, generate new non-primary certification
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, false,
+ masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ continue;
}
- continue;
- }
- // if this is~ the/a primary user id
- if (currentCert.getHashedSubPackets() != null
- && currentCert.getHashedSubPackets().isPrimaryUserID()) {
- // if it's the one we want, just leave it as is
+ // if we are here, this is not currently a primary user id
+
+ // if it should be
if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ // add shiny new primary user id certificate
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_NEW, indent);
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, true,
+ masterKeyFlags, masterKeyExpiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
ok = true;
- continue;
}
- // otherwise, generate new non-primary certification
- log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, false, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
- continue;
- }
- // if we are here, this is not currently a primary user id
-
- // if it should be
- if (userId.equals(saveParcel.mChangePrimaryUserId)) {
- // add shiny new primary user id certificate
- log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_NEW, indent);
- modifiedPublicKey = PGPPublicKey.removeCertification(
- modifiedPublicKey, userId, currentCert);
- PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, true, masterKeyFlags);
- modifiedPublicKey = PGPPublicKey.addCertification(
- modifiedPublicKey, userId, newCert);
- ok = true;
+ // user id is not primary and is not supposed to be - nothing to do here.
+
}
- // user id is not primary and is not supposed to be - nothing to do here.
+ indent -= 1;
+ if (!ok) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
}
- indent -= 1;
-
- if (!ok) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ // Update the secret key ring
+ if (modifiedPublicKey != masterPublicKey) {
+ masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, modifiedPublicKey);
+ masterPublicKey = modifiedPublicKey;
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
}
- }
- // Update the secret key ring
- if (modifiedPublicKey != masterPublicKey) {
- masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, modifiedPublicKey);
- masterPublicKey = modifiedPublicKey;
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
}
// 4a. For each subkey change, generate new subkey binding certificate
@@ -528,27 +649,47 @@ public class PgpKeyOperation {
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE,
indent, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
- // TODO allow changes in master key? this implies generating new user id certs...
- if (change.mKeyId == masterPublicKey.getKeyID()) {
- Log.e(Constants.TAG, "changing the master key not supported");
- return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
- }
-
PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
if (sKey == null) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SUBKEY_MISSING,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- PGPPublicKey pKey = sKey.getPublicKey();
// expiry must not be in the past
- if (change.mExpiry != null && new Date(change.mExpiry*1000).before(new Date())) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY,
+ if (change.mExpiry != null && change.mExpiry != 0 &&
+ new Date(change.mExpiry*1000).before(new Date())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PAST_EXPIRY,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ // if this is the master key, update uid certificates instead
+ if (change.mKeyId == masterPublicKey.getKeyID()) {
+ int flags = change.mFlags == null ? masterKeyFlags : change.mFlags;
+ long expiry = change.mExpiry == null ? masterKeyExpiry : change.mExpiry;
+
+ if ((flags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NO_CERTIFY, indent + 1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ PGPPublicKey pKey =
+ updateMasterCertificates(masterPrivateKey, masterPublicKey,
+ flags, expiry, indent, log);
+ if (pKey == null) {
+ // error log entry has already been added by updateMasterCertificates itself
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+ masterSecretKey = PGPSecretKey.replacePublicKey(masterSecretKey, pKey);
+ masterPublicKey = pKey;
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
+ continue;
+ }
+
+ // otherwise, continue working on the public key
+ PGPPublicKey pKey = sKey.getPublicKey();
+
// keep old flags, or replace with new ones
int flags = change.mFlags == null ? readKeyFlags(pKey) : change.mFlags;
long expiry;
@@ -565,7 +706,7 @@ public class PgpKeyOperation {
//noinspection unchecked
for (PGPSignature sig : new IterableIterator<PGPSignature>(pKey.getSignatures())) {
// special case: if there is a revocation, don't use expiry from before
- if (change.mExpiry == null
+ if ( (change.mExpiry == null || change.mExpiry == 0L)
&& sig.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) {
expiry = 0;
}
@@ -591,7 +732,7 @@ public class PgpKeyOperation {
PGPSecretKey sKey = sKR.getSecretKey(revocation);
if (sKey == null) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SUBKEY_MISSING,
indent+1, PgpKeyHelper.convertKeyIdToHex(revocation));
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -611,10 +752,16 @@ public class PgpKeyOperation {
progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
- log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
+ log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent,
+ PgpKeyHelper.getAlgorithmInfo(add.mAlgorithm, add.mKeySize, add.mCurve) );
+
+ if (add.mExpiry == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
- if (add.mExpiry != null && new Date(add.mExpiry*1000).before(new Date())) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY, indent +1);
+ if (add.mExpiry > 0L && new Date(add.mExpiry*1000).before(new Date())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PAST_EXPIRY, indent +1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -623,9 +770,10 @@ public class PgpKeyOperation {
(i-1) * (100 / saveParcel.mAddSubKeys.size()),
i * (100 / saveParcel.mAddSubKeys.size())
);
- PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ PGPKeyPair keyPair = createKey(add, log, indent);
subProgressPop();
- if(keyPair == null) {
+ if (keyPair == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent +1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -633,21 +781,21 @@ public class PgpKeyOperation {
PGPPublicKey pKey = keyPair.getPublicKey();
PGPSignature cert = generateSubkeyBindingSignature(
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
- add.mFlags, add.mExpiry == null ? 0 : add.mExpiry);
+ add.mFlags, add.mExpiry);
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
PGPSecretKey sKey; {
- // define hashing and signing algos
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA1);
-
// Build key encrypter and decrypter based on passphrase
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey,
- sha1Calc, false, keyEncryptor);
+ // NOTE: only SHA1 is supported for key checksum calculations.
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA1);
+ sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, sha1Calc, false, keyEncryptor);
}
log.add(LogLevel.DEBUG, LogType.MSG_MF_SUBKEY_NEW_ID,
@@ -662,21 +810,67 @@ public class PgpKeyOperation {
if (saveParcel.mNewPassphrase != null) {
progress(R.string.progress_modify_passphrase, 90);
log.add(LogLevel.INFO, LogType.MSG_MF_PASSPHRASE, indent);
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
- .get(HashAlgorithmTags.SHA1);
+ indent += 1;
+
+ PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
+ .get(SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
// Build key encryptor based on new passphrase
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
+ SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
saveParcel.mNewPassphrase.toCharArray());
- sKR = PGPSecretKeyRing.copyWithNewPassword(sKR, keyDecryptor, keyEncryptorNew);
+ // noinspection unchecked
+ for (PGPSecretKey sKey : new IterableIterator<PGPSecretKey>(sKR.getSecretKeys())) {
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PASSPHRASE_KEY, indent,
+ PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
+
+ boolean ok = false;
+
+ try {
+ // try to set new passphrase
+ sKey = PGPSecretKey.copyWithNewPassword(sKey, keyDecryptor, keyEncryptorNew);
+ ok = true;
+ } catch (PGPException e) {
+
+ // if this is the master key, error!
+ if (sKey.getKeyID() == masterPublicKey.getKeyID()) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PASSPHRASE_MASTER, indent+1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
+ // being in here means decrypt failed, likely due to a bad passphrase try
+ // again with an empty passphrase, maybe we can salvage this
+ try {
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PASSPHRASE_EMPTY_RETRY, indent+1);
+ PBESecretKeyDecryptor emptyDecryptor =
+ new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+ sKey = PGPSecretKey.copyWithNewPassword(sKey, emptyDecryptor, keyEncryptorNew);
+ ok = true;
+ } catch (PGPException e2) {
+ // non-fatal but not ok, handled below
+ }
+ }
+
+ if (!ok) {
+ // for a subkey, it's merely a warning
+ log.add(LogLevel.WARN, LogType.MSG_MF_PASSPHRASE_FAIL, indent+1,
+ PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
+ continue;
+ }
+
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
+
+ }
+
+ indent -= 1;
}
- // This one must only be thrown by
} catch (IOException e) {
+ Log.e(Constants.TAG, "encountered IOException while modifying key", e);
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_ENCODE, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (PGPException e) {
@@ -684,6 +878,7 @@ public class PgpKeyOperation {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (SignatureException e) {
+ Log.e(Constants.TAG, "encountered SignatureException while modifying key", e);
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SIG, indent+1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
@@ -694,21 +889,121 @@ public class PgpKeyOperation {
}
+ /** Update all (non-revoked) uid signatures with new flags and expiry time. */
+ private static PGPPublicKey updateMasterCertificates(
+ PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey,
+ int flags, long expiry, int indent, OperationLog log)
+ throws PGPException, IOException, SignatureException {
+
+ // keep track if we actually changed one
+ boolean ok = false;
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_MASTER, indent);
+ indent += 1;
+
+ PGPPublicKey modifiedPublicKey = masterPublicKey;
+
+ // we work on the modifiedPublicKey here, to respect new or newly revoked uids
+ // noinspection unchecked
+ for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
+ boolean isRevoked = false;
+ PGPSignature currentCert = null;
+ // noinspection unchecked
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(
+ modifiedPublicKey.getSignaturesForID(userId))) {
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
+ }
+ // we know from canonicalization that if there is any revocation here, it
+ // is valid and not superseded by a newer certification.
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
+ isRevoked = true;
+ continue;
+ }
+ // we know from canonicalization that there is only one binding
+ // certification here, so we can just work with the first one.
+ if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ currentCert = cert;
+ }
+ }
+
+ if (currentCert == null) {
+ // no certificate found?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
+ }
+
+ // we definitely should not update certifications of revoked keys, so just leave it.
+ if (isRevoked) {
+ continue;
+ }
+
+ // add shiny new user id certificate
+ boolean isPrimary = currentCert.getHashedSubPackets() != null &&
+ currentCert.getHashedSubPackets().isPrimaryUserID();
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ ok = true;
+
+ }
+
+ if (!ok) {
+ // might happen, theoretically, if there is a key with no uid..
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_MASTER_NONE, indent);
+ return null;
+ }
+
+ return modifiedPublicKey;
+
+ }
+
private static PGPSignature generateUserIdSignature(
- PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary, int flags)
+ PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary,
+ int flags, long expiry)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
- PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
- subHashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS);
- subHashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
- subHashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
- subHashedPacketsGen.setPrimaryUserID(false, primary);
- subHashedPacketsGen.setKeyFlags(false, flags);
- sGen.setHashedSubpackets(subHashedPacketsGen.generate());
+
+ PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
+ {
+ /*
+ * From RFC about critical subpackets:
+ * If a subpacket is encountered that is
+ * marked critical but is unknown to the evaluating software, the
+ * evaluator SHOULD consider the signature to be in error.
+ * An evaluator may "recognize" a subpacket, but not implement it. The
+ * purpose of the critical bit is to allow the signer to tell an
+ * evaluator that it would prefer a new, unknown feature to generate an
+ * error than be ignored.
+ */
+ /* non-critical subpackets: */
+ hashedPacketsGen.setPreferredSymmetricAlgorithms(false, PREFERRED_SYMMETRIC_ALGORITHMS);
+ hashedPacketsGen.setPreferredHashAlgorithms(false, PREFERRED_HASH_ALGORITHMS);
+ hashedPacketsGen.setPreferredCompressionAlgorithms(false, PREFERRED_COMPRESSION_ALGORITHMS);
+ hashedPacketsGen.setPrimaryUserID(false, primary);
+
+ /* critical subpackets: we consider those important for a modern pgp implementation */
+ hashedPacketsGen.setSignatureCreationTime(true, new Date());
+ // Request that senders add the MDC to the message (authenticate unsigned messages)
+ hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
+ hashedPacketsGen.setKeyFlags(true, flags);
+ if (expiry > 0) {
+ hashedPacketsGen.setKeyExpirationTime(
+ true, expiry - pKey.getCreationTime().getTime() / 1000);
+ }
+ }
+
+ sGen.setHashedSubpackets(hashedPacketsGen.generate());
sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
}
@@ -717,11 +1012,11 @@ public class PgpKeyOperation {
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
+ subHashedPacketsGen.setSignatureCreationTime(true, new Date());
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
@@ -731,11 +1026,11 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, new Date());
+ subHashedPacketsGen.setSignatureCreationTime(true, new Date());
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
// Generate key revocation or subkey revocation, depending on master/subkey-ness
if (masterPublicKey.getKeyID() == pKey.getKeyID()) {
@@ -765,38 +1060,38 @@ public class PgpKeyOperation {
throws IOException, PGPException, SignatureException {
// date for signing
- Date todayDate = new Date();
+ Date creationTime = new Date();
+
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
// If this key can sign, we need a primary key binding signature
if ((flags & KeyFlags.SIGN_DATA) > 0) {
// cross-certify signing keys
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
- subHashedPacketsGen.setSignatureCreationTime(false, todayDate);
+ subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ pKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
PGPSignature certification = sGen.generateCertification(masterPublicKey, pKey);
- unhashedPacketsGen.setEmbeddedSignature(false, certification);
+ unhashedPacketsGen.setEmbeddedSignature(true, certification);
}
PGPSignatureSubpacketGenerator hashedPacketsGen;
{
hashedPacketsGen = new PGPSignatureSubpacketGenerator();
- hashedPacketsGen.setSignatureCreationTime(false, todayDate);
- hashedPacketsGen.setKeyFlags(false, flags);
- }
-
- if (expiry > 0) {
- long creationTime = pKey.getCreationTime().getTime() / 1000;
- hashedPacketsGen.setKeyExpirationTime(false, expiry - creationTime);
+ hashedPacketsGen.setSignatureCreationTime(true, creationTime);
+ hashedPacketsGen.setKeyFlags(true, flags);
+ if (expiry > 0) {
+ hashedPacketsGen.setKeyExpirationTime(true,
+ expiry - pKey.getCreationTime().getTime() / 1000);
+ }
}
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PGPUtil.SHA1)
+ masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA512)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
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 3fe535f65..2e4eafe41 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -70,7 +70,7 @@ public class PgpSignEncrypt {
private long mSignatureMasterKeyId;
private int mSignatureHashAlgorithm;
private String mSignaturePassphrase;
- private boolean mEncryptToSigner;
+ private long mAdditionalEncryptId;
private boolean mCleartextInput;
private String mOriginalFilename;
@@ -103,7 +103,7 @@ public class PgpSignEncrypt {
this.mSignatureMasterKeyId = builder.mSignatureMasterKeyId;
this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
this.mSignaturePassphrase = builder.mSignaturePassphrase;
- this.mEncryptToSigner = builder.mEncryptToSigner;
+ this.mAdditionalEncryptId = builder.mAdditionalEncryptId;
this.mCleartextInput = builder.mCleartextInput;
this.mNfcSignedHash = builder.mNfcSignedHash;
this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp;
@@ -127,7 +127,7 @@ public class PgpSignEncrypt {
private long mSignatureMasterKeyId = Constants.key.none;
private int mSignatureHashAlgorithm = 0;
private String mSignaturePassphrase = null;
- private boolean mEncryptToSigner = false;
+ private long mAdditionalEncryptId = Constants.key.none;
private boolean mCleartextInput = false;
private String mOriginalFilename = "";
private byte[] mNfcSignedHash = null;
@@ -175,7 +175,7 @@ public class PgpSignEncrypt {
}
public Builder setSignatureMasterKeyId(long signatureMasterKeyId) {
- this.mSignatureMasterKeyId = signatureMasterKeyId;
+ mSignatureMasterKeyId = signatureMasterKeyId;
return this;
}
@@ -192,11 +192,11 @@ public class PgpSignEncrypt {
/**
* Also encrypt with the signing keyring
*
- * @param encryptToSigner
+ * @param additionalEncryptId
* @return
*/
- public Builder setEncryptToSigner(boolean encryptToSigner) {
- mEncryptToSigner = encryptToSigner;
+ public Builder setAdditionalEncryptId(long additionalEncryptId) {
+ mAdditionalEncryptId = additionalEncryptId;
return this;
}
@@ -288,10 +288,10 @@ public class PgpSignEncrypt {
+ "\nenableCompression:" + enableCompression
+ "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput);
- // add signature key id to encryption ids (self-encrypt)
- if (enableEncryption && enableSignature && mEncryptToSigner) {
+ // add additional key id to encryption ids (mostly to do self-encryption)
+ if (enableEncryption && mAdditionalEncryptId != Constants.key.none) {
mEncryptionMasterKeyIds = Arrays.copyOf(mEncryptionMasterKeyIds, mEncryptionMasterKeyIds.length + 1);
- mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mSignatureMasterKeyId;
+ mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mAdditionalEncryptId;
}
ArmoredOutputStream armorOut = null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 73a51942d..f00383e0f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -44,6 +45,8 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
@@ -55,7 +58,8 @@ import java.util.TreeSet;
* This class and its relatives UncachedPublicKey and UncachedSecretKey are
* used to move around pgp key rings in non crypto related (UI, mostly) code.
* It should be used for simple inspection only until it saved in the database,
- * all actual crypto operations should work with WrappedKeyRings exclusively.
+ * all actual crypto operations should work with CanonicalizedKeyRings
+ * exclusively.
*
* This class is also special in that it can hold either the PGPPublicKeyRing
* or PGPSecretKeyRing derivate of the PGPKeyRing class, since these are
@@ -118,6 +122,10 @@ public class UncachedKeyRing {
return mRing.getPublicKey().getFingerprint();
}
+ public int getVersion() {
+ return mRing.getPublicKey().getVersion();
+ }
+
public static UncachedKeyRing decodeFromData(byte[] data)
throws PgpGeneralException, IOException {
@@ -211,8 +219,7 @@ public class UncachedKeyRing {
aos.close();
}
- /** "Canonicalizes" a public key, removing inconsistencies in the process. This variant can be
- * applied to public keyrings only.
+ /** "Canonicalizes" a public key, removing inconsistencies in the process.
*
* More specifically:
* - Remove all non-verifying self-certificates
@@ -229,9 +236,9 @@ public class UncachedKeyRing {
* - If the key is a secret key, remove all certificates by foreign keys
* - If no valid user id remains, log an error and return null
*
- * This operation writes an OperationLog which can be used as part of a OperationResultParcel.
+ * This operation writes an OperationLog which can be used as part of an OperationResultParcel.
*
- * @return A canonicalized key, or null on fatal error
+ * @return A canonicalized key, or null on fatal error (log will include a message in this case)
*
*/
@SuppressWarnings("ConstantConditions")
@@ -241,6 +248,12 @@ public class UncachedKeyRing {
indent, PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()));
indent += 1;
+ // do not accept v3 keys
+ if (getVersion() <= 3) {
+ log.add(LogLevel.ERROR, LogType.MSG_KC_V3_KEY, indent);
+ return null;
+ }
+
final Date now = new Date();
int redundantCerts = 0, badCerts = 0;
@@ -259,13 +272,12 @@ public class UncachedKeyRing {
for (PGPSignature zert : new IterableIterator<PGPSignature>(masterKey.getKeySignatures())) {
int type = zert.getSignatureType();
- // Disregard certifications on user ids, we will deal with those later
+ // These should most definitely not be here...
if (type == PGPSignature.NO_CERTIFICATION
|| type == PGPSignature.DEFAULT_CERTIFICATION
|| type == PGPSignature.CASUAL_CERTIFICATION
|| type == PGPSignature.POSITIVE_CERTIFICATION
|| type == PGPSignature.CERTIFICATION_REVOCATION) {
- // These should not be here...
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TYPE_UID, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
badCerts += 1;
@@ -328,7 +340,17 @@ public class UncachedKeyRing {
}
}
+ ArrayList<String> processedUserIds = new ArrayList<String>();
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
+ // check for duplicate user ids
+ if (processedUserIds.contains(userId)) {
+ log.add(LogLevel.WARN, LogType.MSG_KC_UID_DUP,
+ indent, userId);
+ // strip out the first found user id with this name
+ modified = PGPPublicKey.removeCertification(modified, userId);
+ }
+ processedUserIds.add(userId);
+
PGPSignature selfCert = null;
revocation = null;
@@ -405,13 +427,13 @@ public class UncachedKeyRing {
if (selfCert == null) {
selfCert = zert;
} else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
- log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_CERT_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
redundantCerts += 1;
selfCert = zert;
} else {
- log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_CERT_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
redundantCerts += 1;
@@ -474,6 +496,10 @@ public class UncachedKeyRing {
// Replace modified key in the keyring
ring = replacePublicKey(ring, modified);
+ if (ring == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
indent -= 1;
}
@@ -580,8 +606,8 @@ public class UncachedKeyRing {
}
- // if we already have a cert, and this one is not newer: skip it
- if (selfCert != null && selfCert.getCreationTime().before(cert.getCreationTime())) {
+ // if we already have a cert, and this one is older: skip it
+ if (selfCert != null && cert.getCreationTime().before(selfCert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_DUP, indent);
redundantCerts += 1;
continue;
@@ -641,6 +667,10 @@ public class UncachedKeyRing {
}
// replace pubkey in keyring
ring = replacePublicKey(ring, modified);
+ if (ring == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
indent -= 1;
}
@@ -681,8 +711,9 @@ public class UncachedKeyRing {
long masterKeyId = other.getMasterKeyId();
- if (getMasterKeyId() != masterKeyId) {
- log.add(LogLevel.ERROR, LogType.MSG_MG_HETEROGENEOUS, indent);
+ if (getMasterKeyId() != masterKeyId
+ || !Arrays.equals(getFingerprint(), other.getFingerprint())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_HETEROGENEOUS, indent);
return null;
}
@@ -729,6 +760,10 @@ public class UncachedKeyRing {
} else {
// otherwise, just insert the public key
result = replacePublicKey(result, key);
+ if (result == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
}
continue;
}
@@ -757,6 +792,10 @@ public class UncachedKeyRing {
if (!key.isMasterKey()) {
if (modified != resultKey) {
result = replacePublicKey(result, modified);
+ if (result == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
}
continue;
}
@@ -781,6 +820,10 @@ public class UncachedKeyRing {
// If anything changed, save the updated (sub)key
if (modified != resultKey) {
result = replacePublicKey(result, modified);
+ if (result == null) {
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
+ return null;
+ }
}
}
@@ -795,7 +838,7 @@ public class UncachedKeyRing {
return new UncachedKeyRing(result);
} catch (IOException e) {
- log.add(LogLevel.ERROR, LogType.MSG_MG_FATAL_ENCODE, indent);
+ log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_ENCODE, indent);
return null;
}
@@ -826,16 +869,19 @@ public class UncachedKeyRing {
*/
private static PGPKeyRing replacePublicKey(PGPKeyRing ring, PGPPublicKey key) {
if (ring instanceof PGPPublicKeyRing) {
- return PGPPublicKeyRing.insertPublicKey((PGPPublicKeyRing) ring, key);
- }
- PGPSecretKeyRing secRing = (PGPSecretKeyRing) ring;
- PGPSecretKey sKey = secRing.getSecretKey(key.getKeyID());
- // TODO generate secret key with S2K dummy, if none exists! for now, just die.
- if (sKey == null) {
- throw new RuntimeException("dummy secret key generation not yet implemented");
+ PGPPublicKeyRing pubRing = (PGPPublicKeyRing) ring;
+ return PGPPublicKeyRing.insertPublicKey(pubRing, key);
+ } else {
+ PGPSecretKeyRing secRing = (PGPSecretKeyRing) ring;
+ PGPSecretKey sKey = secRing.getSecretKey(key.getKeyID());
+ // TODO generate secret key with S2K dummy, if none exists!
+ if (sKey == null) {
+ Log.e(Constants.TAG, "dummy secret key generation not yet implemented");
+ return null;
+ }
+ sKey = PGPSecretKey.replacePublicKey(sKey, key);
+ return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
- sKey = PGPSecretKey.replacePublicKey(sKey, key);
- return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
/** This method removes a subkey in a keyring.
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
index 341ca6d04..c7a8bb1d0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -17,6 +18,10 @@
package org.sufficientlysecure.keychain.pgp;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.bcpg.ECPublicBCPGKey;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSignature;
@@ -93,10 +98,23 @@ public class UncachedPublicKey {
return mPublicKey.getAlgorithm();
}
- public int getBitStrength() {
+ public Integer getBitStrength() {
+ if (isEC()) {
+ return null;
+ }
return mPublicKey.getBitStrength();
}
+ public String getCurveOid() {
+ if ( ! isEC()) {
+ return null;
+ }
+ if ( ! (mPublicKey.getPublicKeyPacket().getKey() instanceof ECPublicBCPGKey)) {
+ return null;
+ }
+ return ((ECPublicBCPGKey) mPublicKey.getPublicKeyPacket().getKey()).getCurveOID().getId();
+ }
+
/** Returns the primary user id, as indicated by the public key's self certificates.
*
* This is an expensive operation, since potentially a lot of certificates (and revocations)
@@ -185,6 +203,10 @@ public class UncachedPublicKey {
return getAlgorithm() == PGPPublicKey.DSA;
}
+ public boolean isEC() {
+ return getAlgorithm() == PGPPublicKey.ECDH || getAlgorithm() == PGPPublicKey.ECDSA;
+ }
+
@SuppressWarnings("unchecked")
// TODO make this safe
public int getKeyUsage() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java
index 8dc28c2b3..4dfd93289 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
index ebd110dc5..f24259ba7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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
@@ -95,9 +96,6 @@ public class WrappedSignature {
} catch (PGPException e) {
// no matter
Log.e(Constants.TAG, "exception reading embedded signatures", e);
- } catch (IOException e) {
- // no matter
- Log.e(Constants.TAG, "exception reading embedded signatures", e);
}
return sigs;
}
@@ -149,27 +147,17 @@ public class WrappedSignature {
}
}
- public void update(byte[] data, int offset, int length) throws PgpGeneralException {
- try {
- mSig.update(data, offset, length);
- } catch(SignatureException e) {
- throw new PgpGeneralException(e);
- }
+ public void update(byte[] data, int offset, int length) {
+ mSig.update(data, offset, length);
}
- public void update(byte data) throws PgpGeneralException {
- try {
- mSig.update(data);
- } catch(SignatureException e) {
- throw new PgpGeneralException(e);
- }
+ public void update(byte data) {
+ mSig.update(data);
}
public boolean verify() throws PgpGeneralException {
try {
return mSig.verify();
- } catch(SignatureException e) {
- throw new PgpGeneralException(e);
} catch(PGPException e) {
throw new PgpGeneralException(e);
}
@@ -178,8 +166,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey key) throws PgpGeneralException {
try {
return mSig.verifyCertification(key);
- } catch (SignatureException e) {
- throw new PgpGeneralException("Sign!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
@@ -188,8 +174,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey masterKey, PGPPublicKey subKey) throws PgpGeneralException {
try {
return mSig.verifyCertification(masterKey, subKey);
- } catch (SignatureException e) {
- throw new PgpGeneralException("Sign!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
@@ -198,8 +182,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey key, String uid) throws PgpGeneralException {
try {
return mSig.verifyCertification(uid, key);
- } catch (SignatureException e) {
- throw new PgpGeneralException("Error!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java
index 3700b4c34..aa0d86bb3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* 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