aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java)24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java)4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java)47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java)18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java)55
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java30
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java187
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java265
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java25
12 files changed, 406 insertions, 279 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
index a054255dc..ee0dfefa4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
@@ -16,13 +16,11 @@ import java.io.OutputStream;
* getter method.
*
*/
-public abstract class WrappedKeyRing extends KeyRing {
+public abstract class CanonicalizedKeyRing extends KeyRing {
- private final boolean mHasAnySecret;
private final int mVerified;
- WrappedKeyRing(boolean hasAnySecret, int verified) {
- mHasAnySecret = hasAnySecret;
+ CanonicalizedKeyRing(int verified) {
mVerified = verified;
}
@@ -30,10 +28,6 @@ public abstract class WrappedKeyRing extends KeyRing {
return getRing().getPublicKey().getKeyID();
}
- public boolean hasAnySecret() {
- return mHasAnySecret;
- }
-
public int getVerified() {
return mVerified;
}
@@ -56,7 +50,7 @@ public abstract class WrappedKeyRing extends KeyRing {
}
public long getEncryptId() throws PgpGeneralException {
- for(WrappedPublicKey key : publicKeyIterator()) {
+ for(CanonicalizedPublicKey key : publicKeyIterator()) {
if(key.canEncrypt()) {
return key.getKeyId();
}
@@ -74,7 +68,7 @@ public abstract class WrappedKeyRing extends KeyRing {
}
public long getSignId() throws PgpGeneralException {
- for(WrappedPublicKey key : publicKeyIterator()) {
+ for(CanonicalizedPublicKey key : publicKeyIterator()) {
if(key.canSign()) {
return key.getKeyId();
}
@@ -103,14 +97,14 @@ public abstract class WrappedKeyRing extends KeyRing {
abstract PGPKeyRing getRing();
- abstract public IterableIterator<WrappedPublicKey> publicKeyIterator();
+ abstract public IterableIterator<CanonicalizedPublicKey> publicKeyIterator();
- public WrappedPublicKey getPublicKey() {
- return new WrappedPublicKey(this, getRing().getPublicKey());
+ public CanonicalizedPublicKey getPublicKey() {
+ return new CanonicalizedPublicKey(this, getRing().getPublicKey());
}
- public WrappedPublicKey getPublicKey(long id) {
- return new WrappedPublicKey(this, getRing().getPublicKey(id));
+ public CanonicalizedPublicKey getPublicKey(long id) {
+ return new CanonicalizedPublicKey(this, getRing().getPublicKey(id));
}
public byte[] getEncoded() throws IOException {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
index 69a4fbdee..981caad49 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
@@ -14,12 +14,12 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
* stored in the database.
*
*/
-public class WrappedPublicKey extends UncachedPublicKey {
+public class CanonicalizedPublicKey extends UncachedPublicKey {
// this is the parent key ring
final KeyRing mRing;
- WrappedPublicKey(KeyRing ring, PGPPublicKey key) {
+ CanonicalizedPublicKey(KeyRing ring, PGPPublicKey key) {
super(key);
mRing = ring;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
index 57d84072a..70288dceb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java
@@ -1,42 +1,45 @@
package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.util.IterableIterator;
-import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
import java.util.Iterator;
-public class WrappedPublicKeyRing extends WrappedKeyRing {
+public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing {
private PGPPublicKeyRing mRing;
- private final byte[] mPubKey;
- public WrappedPublicKeyRing(byte[] blob, boolean hasAnySecret, int verified) {
- super(hasAnySecret, verified);
- mPubKey = blob;
+ CanonicalizedPublicKeyRing(PGPPublicKeyRing ring, int verified) {
+ super(verified);
+ mRing = ring;
}
- PGPPublicKeyRing getRing() {
+ public CanonicalizedPublicKeyRing(byte[] blob, int verified) {
+ super(verified);
if(mRing == null) {
- PGPObjectFactory factory = new PGPObjectFactory(mPubKey);
- PGPKeyRing keyRing = null;
+ // get first object in block
+ PGPObjectFactory factory = new PGPObjectFactory(blob);
try {
- if ((keyRing = (PGPKeyRing) factory.nextObject()) == null) {
- Log.e(Constants.TAG, "No keys given!");
+ Object obj = factory.nextObject();
+ if (! (obj instanceof PGPPublicKeyRing)) {
+ throw new RuntimeException("Error constructing CanonicalizedPublicKeyRing, should never happen!");
+ }
+ mRing = (PGPPublicKeyRing) obj;
+ if (factory.nextObject() != null) {
+ throw new RuntimeException("Encountered trailing data after keyring, should never happen!");
}
} catch (IOException e) {
- Log.e(Constants.TAG, "Error while converting to PGPKeyRing!", e);
+ throw new RuntimeException("IO Error constructing CanonicalizedPublicKeyRing, should never happen!");
}
-
- mRing = (PGPPublicKeyRing) keyRing;
}
+ }
+
+ PGPPublicKeyRing getRing() {
return mRing;
}
@@ -45,10 +48,10 @@ public class WrappedPublicKeyRing extends WrappedKeyRing {
}
/** Getter that returns the subkey that should be used for signing. */
- WrappedPublicKey getEncryptionSubKey() throws PgpGeneralException {
+ CanonicalizedPublicKey getEncryptionSubKey() throws PgpGeneralException {
PGPPublicKey key = getRing().getPublicKey(getEncryptId());
if(key != null) {
- WrappedPublicKey cKey = new WrappedPublicKey(this, key);
+ CanonicalizedPublicKey cKey = new CanonicalizedPublicKey(this, key);
if(!cKey.canEncrypt()) {
throw new PgpGeneralException("key error");
}
@@ -57,18 +60,18 @@ public class WrappedPublicKeyRing extends WrappedKeyRing {
throw new PgpGeneralException("no encryption key available");
}
- public IterableIterator<WrappedPublicKey> publicKeyIterator() {
+ public IterableIterator<CanonicalizedPublicKey> publicKeyIterator() {
@SuppressWarnings("unchecked")
final Iterator<PGPPublicKey> it = getRing().getPublicKeys();
- return new IterableIterator<WrappedPublicKey>(new Iterator<WrappedPublicKey>() {
+ return new IterableIterator<CanonicalizedPublicKey>(new Iterator<CanonicalizedPublicKey>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
- public WrappedPublicKey next() {
- return new WrappedPublicKey(WrappedPublicKeyRing.this, it.next());
+ public CanonicalizedPublicKey next() {
+ return new CanonicalizedPublicKey(CanonicalizedPublicKeyRing.this, it.next());
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
index cc6313b32..ff82da07a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -43,7 +43,7 @@ import java.util.List;
* properly imported secret keys only.
*
*/
-public class WrappedSecretKey extends WrappedPublicKey {
+public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
private final PGPSecretKey mSecretKey;
private PGPPrivateKey mPrivateKey = null;
@@ -53,21 +53,13 @@ public class WrappedSecretKey extends WrappedPublicKey {
private static int PRIVATE_KEY_STATE_UNLOCKED = 1;
private static int PRIVATE_KEY_STATE_DIVERT_TO_CARD = 2;
- WrappedSecretKey(WrappedSecretKeyRing ring, PGPSecretKey key) {
+ CanonicalizedSecretKey(CanonicalizedSecretKeyRing ring, PGPSecretKey key) {
super(ring, key.getPublicKey());
mSecretKey = key;
}
- public WrappedSecretKeyRing getRing() {
- return (WrappedSecretKeyRing) mRing;
- }
-
- /** Returns the wrapped PGPSecretKeyRing.
- * This function is for compatibility only, should not be used anymore and will be removed
- */
- @Deprecated
- public PGPSecretKey getKeyExternal() {
- return mSecretKey;
+ public CanonicalizedSecretKeyRing getRing() {
+ return (CanonicalizedSecretKeyRing) mRing;
}
/**
@@ -189,7 +181,7 @@ public class WrappedSecretKey extends WrappedPublicKey {
* @param userIds User IDs to certify, must not be null or empty
* @return A keyring with added certifications
*/
- public UncachedKeyRing certifyUserIds(WrappedPublicKeyRing publicKeyRing, List<String> userIds)
+ public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds)
throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException,
PGPException, SignatureException {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
index 5cb24cf88..7d3e26000 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java
@@ -1,10 +1,12 @@
package org.sufficientlysecure.keychain.pgp;
+import org.spongycastle.bcpg.S2K;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
@@ -15,15 +17,21 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
+import java.util.HashSet;
import java.util.Iterator;
-public class WrappedSecretKeyRing extends WrappedKeyRing {
+public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing {
private PGPSecretKeyRing mRing;
- public WrappedSecretKeyRing(byte[] blob, boolean isRevoked, int verified)
+ CanonicalizedSecretKeyRing(PGPSecretKeyRing ring, int verified) {
+ super(verified);
+ mRing = ring;
+ }
+
+ public CanonicalizedSecretKeyRing(byte[] blob, boolean isRevoked, int verified)
{
- super(isRevoked, verified);
+ super(verified);
PGPObjectFactory factory = new PGPObjectFactory(blob);
PGPKeyRing keyRing = null;
try {
@@ -41,19 +49,32 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
return mRing;
}
- public WrappedSecretKey getSecretKey() {
- return new WrappedSecretKey(this, mRing.getSecretKey());
+ public CanonicalizedSecretKey getSecretKey() {
+ return new CanonicalizedSecretKey(this, mRing.getSecretKey());
+ }
+
+ public CanonicalizedSecretKey getSecretKey(long id) {
+ return new CanonicalizedSecretKey(this, mRing.getSecretKey(id));
}
- public WrappedSecretKey getSecretKey(long id) {
- return new WrappedSecretKey(this, mRing.getSecretKey(id));
+ public HashSet<Long> getAvailableSubkeys() {
+ HashSet<Long> result = new HashSet<Long>();
+ // then, mark exactly the keys we have available
+ for (PGPSecretKey sub : new IterableIterator<PGPSecretKey>(getRing().getSecretKeys())) {
+ S2K s2k = sub.getS2K();
+ // add key, except if the private key has been stripped (GNU extension)
+ if(s2k == null || (s2k.getProtectionMode() != S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY)) {
+ result.add(sub.getKeyID());
+ }
+ }
+ return result;
}
/** Getter that returns the subkey that should be used for signing. */
- WrappedSecretKey getSigningSubKey() throws PgpGeneralException {
+ CanonicalizedSecretKey getSigningSubKey() throws PgpGeneralException {
PGPSecretKey key = mRing.getSecretKey(getSignId());
if(key != null) {
- WrappedSecretKey cKey = new WrappedSecretKey(this, key);
+ CanonicalizedSecretKey cKey = new CanonicalizedSecretKey(this, key);
if(!cKey.canSign()) {
throw new PgpGeneralException("key error");
}
@@ -88,17 +109,17 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
}
}
- public IterableIterator<WrappedSecretKey> secretKeyIterator() {
+ public IterableIterator<CanonicalizedSecretKey> secretKeyIterator() {
final Iterator<PGPSecretKey> it = mRing.getSecretKeys();
- return new IterableIterator<WrappedSecretKey>(new Iterator<WrappedSecretKey>() {
+ return new IterableIterator<CanonicalizedSecretKey>(new Iterator<CanonicalizedSecretKey>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
- public WrappedSecretKey next() {
- return new WrappedSecretKey(WrappedSecretKeyRing.this, it.next());
+ public CanonicalizedSecretKey next() {
+ return new CanonicalizedSecretKey(CanonicalizedSecretKeyRing.this, it.next());
}
@Override
@@ -108,17 +129,17 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
});
}
- public IterableIterator<WrappedPublicKey> publicKeyIterator() {
+ public IterableIterator<CanonicalizedPublicKey> publicKeyIterator() {
final Iterator<PGPPublicKey> it = getRing().getPublicKeys();
- return new IterableIterator<WrappedPublicKey>(new Iterator<WrappedPublicKey>() {
+ return new IterableIterator<CanonicalizedPublicKey>(new Iterator<CanonicalizedPublicKey>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
- public WrappedPublicKey next() {
- return new WrappedPublicKey(WrappedSecretKeyRing.this, it.next());
+ public CanonicalizedPublicKey next() {
+ return new CanonicalizedPublicKey(CanonicalizedSecretKeyRing.this, it.next());
}
@Override
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 129ffba3e..ebc49ab05 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
@@ -12,7 +12,7 @@ import java.util.regex.Pattern;
* keyring should in all cases agree on the output of all methods described
* here.
*
- * @see org.sufficientlysecure.keychain.pgp.WrappedKeyRing
+ * @see CanonicalizedKeyRing
* @see org.sufficientlysecure.keychain.provider.CachedPublicKeyRing
*
*/
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 db9e2c6c6..7f2d971ed 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -231,7 +231,7 @@ public class PgpDecryptVerify {
PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
PGPPBEEncryptedData encryptedDataSymmetric = null;
- WrappedSecretKey secretEncryptionKey = null;
+ CanonicalizedSecretKey secretEncryptionKey = null;
Iterator<?> it = enc.getEncryptedDataObjects();
boolean asymmetricPacketFound = false;
boolean symmetricPacketFound = false;
@@ -243,10 +243,10 @@ public class PgpDecryptVerify {
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
- WrappedSecretKeyRing secretKeyRing;
+ CanonicalizedSecretKeyRing secretKeyRing;
try {
// get actual keyring object based on master key id
- secretKeyRing = mProviderHelper.getWrappedSecretKeyRing(
+ secretKeyRing = mProviderHelper.getCanonicalizedSecretKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(encData.getKeyID())
);
} catch (ProviderHelper.NotFoundException e) {
@@ -365,8 +365,8 @@ public class PgpDecryptVerify {
Object dataChunk = plainFact.nextObject();
OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
int signatureIndex = -1;
- WrappedPublicKeyRing signingRing = null;
- WrappedPublicKey signingKey = null;
+ CanonicalizedPublicKeyRing signingRing = null;
+ CanonicalizedPublicKey signingKey = null;
if (dataChunk instanceof PGPCompressedData) {
updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
@@ -390,7 +390,7 @@ public class PgpDecryptVerify {
for (int i = 0; i < sigList.size(); ++i) {
try {
long sigKeyId = sigList.get(i).getKeyID();
- signingRing = mProviderHelper.getWrappedPublicKeyRing(
+ signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
);
signingKey = signingRing.getPublicKey(sigKeyId);
@@ -566,8 +566,8 @@ public class PgpDecryptVerify {
throw new InvalidDataException();
}
- WrappedPublicKeyRing signingRing = null;
- WrappedPublicKey signingKey = null;
+ CanonicalizedPublicKeyRing signingRing = null;
+ CanonicalizedPublicKey signingKey = null;
int signatureIndex = -1;
// go through all signatures
@@ -575,7 +575,7 @@ public class PgpDecryptVerify {
for (int i = 0; i < sigList.size(); ++i) {
try {
long sigKeyId = sigList.get(i).getKeyID();
- signingRing = mProviderHelper.getWrappedPublicKeyRing(
+ signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
);
signingKey = signingRing.getPublicKey(sigKeyId);
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 6fc55cfb8..846b00ef2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -34,7 +34,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
-import org.sufficientlysecure.keychain.service.OperationResults.ImportResult;
+import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -93,7 +93,7 @@ public class PgpImportExport {
}
}
- public boolean uploadKeyRingToServer(HkpKeyserver server, WrappedPublicKeyRing keyring) {
+ public boolean uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = null;
try {
@@ -123,14 +123,14 @@ public class PgpImportExport {
}
/** Imports keys from given data. If keyIds is given only those are imported */
- public ImportResult importKeyRings(List<ParcelableKeyRing> entries) {
+ public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries) {
updateProgress(R.string.progress_importing, 0, 100);
// If there aren't even any keys, do nothing here.
if (entries == null || entries.size() == 0) {
- return new ImportResult(
- ImportResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0);
+ return new ImportKeyResult(
+ ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0);
}
int newKeys = 0, oldKeys = 0, badKeys = 0;
@@ -185,26 +185,26 @@ public class PgpImportExport {
int resultType = 0;
// special return case: no new keys at all
if (badKeys == 0 && newKeys == 0 && oldKeys == 0) {
- resultType = ImportResult.RESULT_FAIL_NOTHING;
+ resultType = ImportKeyResult.RESULT_FAIL_NOTHING;
} else {
if (newKeys > 0) {
- resultType |= ImportResult.RESULT_OK_NEWKEYS;
+ resultType |= ImportKeyResult.RESULT_OK_NEWKEYS;
}
if (oldKeys > 0) {
- resultType |= ImportResult.RESULT_OK_UPDATED;
+ resultType |= ImportKeyResult.RESULT_OK_UPDATED;
}
if (badKeys > 0) {
- resultType |= ImportResult.RESULT_WITH_ERRORS;
+ resultType |= ImportKeyResult.RESULT_WITH_ERRORS;
if (newKeys == 0 && oldKeys == 0) {
- resultType |= ImportResult.RESULT_ERROR;
+ resultType |= ImportKeyResult.RESULT_ERROR;
}
}
if (log.containsWarnings()) {
- resultType |= ImportResult.RESULT_WITH_WARNINGS;
+ resultType |= ImportKeyResult.RESULT_WITH_WARNINGS;
}
}
- return new ImportResult(resultType, log, newKeys, oldKeys, badKeys);
+ return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys);
}
@@ -235,7 +235,7 @@ public class PgpImportExport {
updateProgress(progress * 100 / masterKeyIdsSize, 100);
try {
- WrappedPublicKeyRing ring = mProviderHelper.getWrappedPublicKeyRing(
+ CanonicalizedPublicKeyRing ring = mProviderHelper.getCanonicalizedPublicKeyRing(
KeychainContract.KeyRings.buildUnifiedKeyRingUri(pubKeyMasterId)
);
@@ -263,8 +263,8 @@ public class PgpImportExport {
updateProgress(progress * 100 / masterKeyIdsSize, 100);
try {
- WrappedSecretKeyRing secretKeyRing =
- mProviderHelper.getWrappedSecretKeyRing(secretKeyMasterId);
+ CanonicalizedSecretKeyRing secretKeyRing =
+ mProviderHelper.getCanonicalizedSecretKeyRing(secretKeyMasterId);
secretKeyRing.encode(arOutStream);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
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 00f73a5b0..861f93446 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -46,15 +46,17 @@ import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
+import org.sufficientlysecure.keychain.service.OperationResultParcel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
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.SubkeyAdd;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Primes;
+import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.IOException;
import java.math.BigInteger;
@@ -67,6 +69,7 @@ import java.security.SignatureException;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
+import java.util.Stack;
/**
* This class is the single place where ALL operations that actually modify a PGP public or secret
@@ -78,7 +81,7 @@ import java.util.Iterator;
* This indicator may be null.
*/
public class PgpKeyOperation {
- private Progressable mProgress;
+ private Stack<Progressable> mProgress;
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
@@ -92,13 +95,34 @@ public class PgpKeyOperation {
public PgpKeyOperation(Progressable progress) {
super();
- this.mProgress = progress;
+ if (progress != null) {
+ mProgress = new Stack<Progressable>();
+ mProgress.push(progress);
+ }
}
- void updateProgress(int message, int current, int total) {
- if (mProgress != null) {
- mProgress.setProgress(message, current, total);
+ private void subProgressPush(int from, int to) {
+ if (mProgress == null) {
+ return;
+ }
+ mProgress.push(new ProgressScaler(mProgress.peek(), from, to, 100));
+ }
+ private void subProgressPop() {
+ if (mProgress == null) {
+ return;
}
+ if (mProgress.size() == 1) {
+ throw new RuntimeException("Tried to pop progressable without prior push! "
+ + "This is a programming error, please file a bug report.");
+ }
+ mProgress.pop();
+ }
+
+ private void progress(int message, int current) {
+ if (mProgress == null) {
+ return;
+ }
+ mProgress.peek().setProgress(message, current, 100);
}
/** Creates new secret key. */
@@ -115,6 +139,7 @@ public class PgpKeyOperation {
switch (algorithmChoice) {
case Constants.choice.algorithm.dsa: {
+ progress(R.string.progress_generating_dsa, 30);
keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
keyGen.initialize(keySize, new SecureRandom());
algorithm = PGPPublicKey.DSA;
@@ -122,6 +147,7 @@ public class PgpKeyOperation {
}
case Constants.choice.algorithm.elgamal: {
+ progress(R.string.progress_generating_elgamal, 30);
keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
BigInteger p = Primes.getBestPrime(keySize);
BigInteger g = new BigInteger("2");
@@ -134,6 +160,7 @@ public class PgpKeyOperation {
}
case Constants.choice.algorithm.rsa: {
+ progress(R.string.progress_generating_rsa, 30);
keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
keyGen.initialize(keySize, new SecureRandom());
@@ -163,43 +190,49 @@ public class PgpKeyOperation {
}
}
- public UncachedKeyRing createSecretKeyRing(SaveKeyringParcel saveParcel, OperationLog log,
- int indent) {
+ public EditKeyResult createSecretKeyRing(SaveKeyringParcel saveParcel) {
+
+ OperationLog log = new OperationLog();
+ int indent = 0;
try {
log.add(LogLevel.START, LogType.MSG_CR, indent);
+ progress(R.string.progress_building_key, 0);
indent += 1;
- updateProgress(R.string.progress_building_key, 0, 100);
if (saveParcel.mAddSubKeys.isEmpty()) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_MASTER, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
if (saveParcel.mAddUserIds.isEmpty()) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_USER_ID, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
SubkeyAdd add = saveParcel.mAddSubKeys.remove(0);
if ((add.mFlags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_CERTIFY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
if (add.mAlgorithm == Constants.choice.algorithm.elgamal) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_MASTER_ELGAMAL, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ subProgressPush(10, 30);
PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ subProgressPop();
// return null if this failed (an error will already have been logged by createKey)
if (keyPair == null) {
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ progress(R.string.progress_building_master_key, 40);
+
// define hashing and signing algos
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
.build().get(HashAlgorithmTags.SHA1);
@@ -213,15 +246,16 @@ public class PgpKeyOperation {
PGPSecretKeyRing sKR = new PGPSecretKeyRing(
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
- return internal(sKR, masterSecretKey, add.mFlags, saveParcel, "", log, indent);
+ subProgressPush(50, 100);
+ return internal(sKR, masterSecretKey, add.mFlags, saveParcel, "", log);
} catch (PGPException e) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
Log.e(Constants.TAG, "pgp error encoding key", e);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (IOException e) {
Log.e(Constants.TAG, "io error encoding key", e);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
}
@@ -237,8 +271,11 @@ public class PgpKeyOperation {
* are changed by adding new certificates, which implicitly override older certificates.
*
*/
- public UncachedKeyRing modifySecretKeyRing(WrappedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
- String passphrase, OperationLog log, int indent) {
+ public EditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
+ String passphrase) {
+
+ OperationLog log = new OperationLog();
+ int indent = 0;
/*
* 1. Unlock private key
@@ -251,14 +288,15 @@ public class PgpKeyOperation {
* 6. If requested, change passphrase
*/
- log.add(LogLevel.START, LogType.MSG_MF, indent);
+ log.add(LogLevel.START, LogType.MSG_MF, indent,
+ PgpKeyHelper.convertKeyIdToHex(wsKR.getMasterKeyId()));
indent += 1;
- updateProgress(R.string.progress_building_key, 0, 100);
+ progress(R.string.progress_building_key, 0);
// Make sure this is called with a proper SaveKeyringParcel
if (saveParcel.mMasterKeyId == null || saveParcel.mMasterKeyId != wsKR.getMasterKeyId()) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_KEYID, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// We work on bouncycastle object level here
@@ -270,27 +308,30 @@ public class PgpKeyOperation {
|| !Arrays.equals(saveParcel.mFingerprint,
masterSecretKey.getPublicKey().getFingerprint())) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_FINGERPRINT, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// 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;
- return internal(sKR, masterSecretKey, masterKeyFlags, saveParcel, passphrase, log, indent);
+ return internal(sKR, masterSecretKey, masterKeyFlags, saveParcel, passphrase, log);
}
- private UncachedKeyRing internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
+ private EditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
int masterKeyFlags,
SaveKeyringParcel saveParcel, String passphrase,
- OperationLog log, int indent) {
+ OperationLog log) {
+
+ int indent = 1;
- updateProgress(R.string.progress_certifying_master_key, 20, 100);
+ progress(R.string.progress_modify, 0);
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
// 1. Unlock private key
+ progress(R.string.progress_modify_unlock, 10);
log.add(LogLevel.DEBUG, LogType.MSG_MF_UNLOCK, indent);
PGPPrivateKey masterPrivateKey;
{
@@ -300,7 +341,7 @@ public class PgpKeyOperation {
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) {
log.add(LogLevel.ERROR, LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
}
@@ -310,9 +351,18 @@ public class PgpKeyOperation {
PGPPublicKey modifiedPublicKey = masterPublicKey;
// 2a. Add certificates for new user ids
- for (String userId : saveParcel.mAddUserIds) {
+ subProgressPush(15, 25);
+ for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) {
+
+ 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);
+ if (userId.equals("")) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_UID_ERROR_EMPTY, indent+1);
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
+ }
+
// this operation supersedes all previous binding and revocation certificates,
// so remove those to retain assertions from canonicalization for later operations
@SuppressWarnings("unchecked")
@@ -322,7 +372,7 @@ public class PgpKeyOperation {
if (cert.getKeyID() != masterPublicKey.getKeyID()) {
// foreign certificate?! error error error
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
|| cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
@@ -343,19 +393,27 @@ public class PgpKeyOperation {
masterPublicKey, userId, isPrimary, masterKeyFlags);
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
}
+ subProgressPop();
// 2b. Add revocations for revoked user ids
- for (String userId : saveParcel.mRevokeUserIds) {
- log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent);
+ 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);
+
// 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);
// keep track if we actually changed one
boolean ok = false;
@@ -373,7 +431,7 @@ public class PgpKeyOperation {
if (cert.getKeyID() != masterPublicKey.getKeyID()) {
// foreign certificate?! error error error
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return null;
+ 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.
@@ -394,7 +452,7 @@ public class PgpKeyOperation {
if (currentCert == null) {
// no certificate found?! error error error
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// we definitely should not update certifications of revoked keys, so just leave it.
@@ -402,13 +460,14 @@ public class PgpKeyOperation {
// revoked user ids cannot be primary!
if (userId.equals(saveParcel.mChangePrimaryUserId)) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
continue;
}
// if this is~ the/a primary user id
- if (currentCert.hasSubpackets() && currentCert.getHashedSubPackets().isPrimaryUserID()) {
+ 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;
@@ -448,7 +507,7 @@ public class PgpKeyOperation {
if (!ok) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
}
@@ -460,21 +519,25 @@ public class PgpKeyOperation {
}
// 4a. For each subkey change, generate new subkey binding certificate
- for (SaveKeyringParcel.SubkeyChange change : saveParcel.mChangeSubKeys) {
+ subProgressPush(50, 60);
+ for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) {
+
+ progress(R.string.progress_modify_subkeychange, (i-1) * (100 / saveParcel.mChangeSubKeys.size()));
+ SaveKeyringParcel.SubkeyChange change = saveParcel.mChangeSubKeys.get(i);
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 null;
+ 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,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
PGPPublicKey pKey = sKey.getPublicKey();
@@ -482,7 +545,7 @@ public class PgpKeyOperation {
if (change.mExpiry != null && new Date(change.mExpiry*1000).before(new Date())) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// keep old flags, or replace with new ones
@@ -514,16 +577,22 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
+ subProgressPop();
// 4b. For each subkey revocation, generate new subkey revocation certificate
- for (long revocation : saveParcel.mRevokeSubKeys) {
+ subProgressPush(60, 70);
+ for (int i = 0; i < saveParcel.mRevokeSubKeys.size(); i++) {
+
+ progress(R.string.progress_modify_subkeyrevoke, (i-1) * (100 / saveParcel.mRevokeSubKeys.size()));
+ long revocation = saveParcel.mRevokeSubKeys.get(i);
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_REVOKE,
indent, PgpKeyHelper.convertKeyIdToHex(revocation));
+
PGPSecretKey sKey = sKR.getSecretKey(revocation);
if (sKey == null) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
indent+1, PgpKeyHelper.convertKeyIdToHex(revocation));
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
PGPPublicKey pKey = sKey.getPublicKey();
@@ -533,21 +602,30 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
+ subProgressPop();
// 5. Generate and add new subkeys
- for (SaveKeyringParcel.SubkeyAdd add : saveParcel.mAddSubKeys) {
+ subProgressPush(70, 90);
+ for (int i = 0; i < saveParcel.mAddSubKeys.size(); i++) {
+
+ progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
+ SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(0);
+ log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
if (add.mExpiry != null && new Date(add.mExpiry*1000).before(new Date())) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY, indent +1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
-
// generate a new secret key (privkey only for now)
+ subProgressPush(
+ (i-1) * (100 / saveParcel.mAddSubKeys.size()),
+ i * (100 / saveParcel.mAddSubKeys.size())
+ );
PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ subProgressPop();
if(keyPair == null) {
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
// add subkey binding signature (making this a sub rather than master key)
@@ -577,9 +655,11 @@ public class PgpKeyOperation {
sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
}
+ subProgressPop();
// 6. If requested, change passphrase
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);
@@ -597,18 +677,19 @@ public class PgpKeyOperation {
// This one must only be thrown by
} catch (IOException e) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_ENCODE, indent+1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (PGPException e) {
Log.e(Constants.TAG, "encountered pgp error while modifying key", e);
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent+1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
} catch (SignatureException e) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_SIG, indent+1);
- return null;
+ return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
+ progress(R.string.progress_done, 100);
log.add(LogLevel.OK, LogType.MSG_MF_SUCCESS, indent);
- return new UncachedKeyRing(sKR);
+ return new EditKeyResult(OperationResultParcel.RESULT_OK, log, new UncachedKeyRing(sKR));
}
@@ -735,7 +816,7 @@ public class PgpKeyOperation {
int flags = 0;
//noinspection unchecked
for(PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (!sig.hasSubpackets()) {
+ if (sig.getHashedSubPackets() == null) {
continue;
}
flags |= sig.getHashedSubPackets().getKeyFlags();
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 434b2bf90..09c28e7c5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -278,11 +278,11 @@ public class PgpSignEncrypt {
}
/* Get keys for signature generation for later usage */
- WrappedSecretKey signingKey = null;
+ CanonicalizedSecretKey signingKey = null;
if (enableSignature) {
- WrappedSecretKeyRing signingKeyRing;
+ CanonicalizedSecretKeyRing signingKeyRing;
try {
- signingKeyRing = mProviderHelper.getWrappedSecretKeyRing(mSignatureMasterKeyId);
+ signingKeyRing = mProviderHelper.getCanonicalizedSecretKeyRing(mSignatureMasterKeyId);
} catch (ProviderHelper.NotFoundException e) {
throw new NoSigningKeyException();
}
@@ -337,9 +337,9 @@ public class PgpSignEncrypt {
// Asymmetric encryption
for (long id : mEncryptionMasterKeyIds) {
try {
- WrappedPublicKeyRing keyRing = mProviderHelper.getWrappedPublicKeyRing(
+ CanonicalizedPublicKeyRing keyRing = mProviderHelper.getCanonicalizedPublicKeyRing(
KeyRings.buildUnifiedKeyRingUri(id));
- WrappedPublicKey key = keyRing.getEncryptionSubKey();
+ CanonicalizedPublicKey key = keyRing.getEncryptionSubKey();
cPk.addMethod(key.getPubKeyEncryptionGenerator());
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "key not found!", e);
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 308375a1d..d29f19d67 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -1,7 +1,6 @@
package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.bcpg.S2K;
import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPKeyFlags;
@@ -14,28 +13,25 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureList;
import org.spongycastle.openpgp.PGPUtil;
+import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
+import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
-import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
-import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Set;
import java.util.TreeSet;
-import java.util.Vector;
/** Wrapper around PGPKeyRing class, to be constructed from bytes.
*
@@ -49,7 +45,7 @@ import java.util.Vector;
* treated equally for most purposes in UI code. It is up to the programmer to
* take care of the differences.
*
- * @see org.sufficientlysecure.keychain.pgp.WrappedKeyRing
+ * @see CanonicalizedKeyRing
* @see org.sufficientlysecure.keychain.pgp.UncachedPublicKey
* @see org.sufficientlysecure.keychain.pgp.UncachedSecretKey
*
@@ -59,18 +55,10 @@ public class UncachedKeyRing {
final PGPKeyRing mRing;
final boolean mIsSecret;
- final boolean mIsCanonicalized;
UncachedKeyRing(PGPKeyRing ring) {
mRing = ring;
mIsSecret = ring instanceof PGPSecretKeyRing;
- mIsCanonicalized = false;
- }
-
- private UncachedKeyRing(PGPKeyRing ring, boolean canonicalized) {
- mRing = ring;
- mIsSecret = ring instanceof PGPSecretKeyRing;
- mIsCanonicalized = canonicalized;
}
public long getMasterKeyId() {
@@ -89,7 +77,7 @@ public class UncachedKeyRing {
final Iterator<PGPPublicKey> it = mRing.getPublicKeys();
return new Iterator<UncachedPublicKey>() {
public void remove() {
- it.remove();
+ throw new UnsupportedOperationException();
}
public UncachedPublicKey next() {
return new UncachedPublicKey(it.next());
@@ -105,10 +93,6 @@ public class UncachedKeyRing {
return mIsSecret;
}
- public boolean isCanonicalized() {
- return mIsCanonicalized;
- }
-
public byte[] getEncoded() throws IOException {
return mRing.getEncoded();
}
@@ -119,43 +103,86 @@ public class UncachedKeyRing {
public static UncachedKeyRing decodeFromData(byte[] data)
throws PgpGeneralException, IOException {
- BufferedInputStream bufferedInput =
- new BufferedInputStream(new ByteArrayInputStream(data));
- if (bufferedInput.available() > 0) {
- InputStream in = PGPUtil.getDecoderStream(bufferedInput);
- PGPObjectFactory objectFactory = new PGPObjectFactory(in);
-
- // get first object in block
- Object obj;
- if ((obj = objectFactory.nextObject()) != null && obj instanceof PGPKeyRing) {
- return new UncachedKeyRing((PGPKeyRing) obj);
- } else {
- throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
- }
- } else {
+
+ Iterator<UncachedKeyRing> parsed = fromStream(new ByteArrayInputStream(data));
+
+ if ( ! parsed.hasNext()) {
throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
}
+
+ UncachedKeyRing ring = parsed.next();
+
+ if (parsed.hasNext()) {
+ throw new PgpGeneralException("Expected single keyring in stream, found at least two");
+ }
+
+ return ring;
+
}
- public static List<UncachedKeyRing> fromStream(InputStream stream)
- throws PgpGeneralException, IOException {
+ public static Iterator<UncachedKeyRing> fromStream(final InputStream stream) throws IOException {
- PGPObjectFactory objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(stream));
+ return new Iterator<UncachedKeyRing>() {
- List<UncachedKeyRing> result = new Vector<UncachedKeyRing>();
+ UncachedKeyRing mNext = null;
+ PGPObjectFactory mObjectFactory = null;
- // go through all objects in this block
- Object obj;
- while ((obj = objectFactory.nextObject()) != null) {
- Log.d(Constants.TAG, "Found class: " + obj.getClass());
+ private void cacheNext() {
+ if (mNext != null) {
+ return;
+ }
+
+ try {
+ while(stream.available() > 0) {
+ // if there are no objects left from the last factory, create a new one
+ if (mObjectFactory == null) {
+ mObjectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(stream));
+ }
+
+ // go through all objects in this block
+ Object obj;
+ while ((obj = mObjectFactory.nextObject()) != null) {
+ Log.d(Constants.TAG, "Found class: " + obj.getClass());
+ if (!(obj instanceof PGPKeyRing)) {
+ Log.i(Constants.TAG,
+ "Skipping object of bad type " + obj.getClass().getName() + " in stream");
+ // skip object
+ continue;
+ }
+ mNext = new UncachedKeyRing((PGPKeyRing) obj);
+ return;
+ }
+ // if we are past the while loop, that means the objectFactory had no next
+ mObjectFactory = null;
+ }
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException while processing stream", e);
+ }
- if (obj instanceof PGPKeyRing) {
- result.add(new UncachedKeyRing((PGPKeyRing) obj));
- } else {
- Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!");
}
- }
- return result;
+
+ @Override
+ public boolean hasNext() {
+ cacheNext();
+ return mNext != null;
+ }
+
+ @Override
+ public UncachedKeyRing next() {
+ try {
+ cacheNext();
+ return mNext;
+ } finally {
+ mNext = null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+
}
public void encodeArmored(OutputStream out, String version) throws IOException {
@@ -165,27 +192,6 @@ public class UncachedKeyRing {
aos.close();
}
- public HashSet<Long> getAvailableSubkeys() {
- if(!isSecret()) {
- throw new RuntimeException("Tried to find available subkeys from non-secret keys. " +
- "This is a programming error and should never happen!");
- }
-
- HashSet<Long> result = new HashSet<Long>();
- // then, mark exactly the keys we have available
- for (PGPSecretKey sub : new IterableIterator<PGPSecretKey>(
- ((PGPSecretKeyRing) mRing).getSecretKeys())) {
- S2K s2k = sub.getS2K();
- // add key, except if the private key has been stripped (GNU extension)
- if(s2k == null || (s2k.getProtectionMode() != S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY)) {
- result.add(sub.getKeyID());
- } else {
- Log.d(Constants.TAG, "S2K GNU extension!, mode: " + s2k.getProtectionMode());
- }
- }
- return result;
- }
-
/** "Canonicalizes" a public key, removing inconsistencies in the process. This variant can be
* applied to public keyrings only.
*
@@ -195,7 +201,7 @@ public class UncachedKeyRing {
* - Remove all certificates flagged as "local"
* - Remove all certificates which are superseded by a newer one on the same target,
* including revocations with later re-certifications.
- * - Remove all certificates of unknown type:
+ * - Remove all certificates in other positions if not of known type:
* - key revocation signatures on the master key
* - subkey binding signatures for subkeys
* - certifications and certification revocations for user ids
@@ -210,7 +216,7 @@ public class UncachedKeyRing {
*
*/
@SuppressWarnings("ConstantConditions")
- public UncachedKeyRing canonicalize(OperationLog log, int indent) {
+ public CanonicalizedKeyRing canonicalize(OperationLog log, int indent) {
log.add(LogLevel.START, isSecret() ? LogType.MSG_KC_SECRET : LogType.MSG_KC_PUBLIC,
indent, PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()));
@@ -292,14 +298,14 @@ public class UncachedKeyRing {
revocation = zert;
// more revocations? at least one is superfluous, then.
} else if (revocation.getCreationTime().before(zert.getCreationTime())) {
+ log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);
modified = PGPPublicKey.removeCertification(modified, revocation);
redundantCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);
revocation = zert;
} else {
+ log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
redundantCerts += 1;
- log.add(LogLevel.INFO, LogType.MSG_KC_REVOKE_DUP, indent);
}
}
@@ -323,20 +329,21 @@ public class UncachedKeyRing {
indent, "0x" + Integer.toString(zert.getSignatureType(), 16));
modified = PGPPublicKey.removeCertification(modified, userId, zert);
badCerts += 1;
+ continue;
}
if (cert.getCreationTime().after(now)) {
// Creation date in the future? No way!
- log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TIME, indent);
- modified = PGPPublicKey.removeCertification(modified, zert);
+ log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_TIME, indent);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
badCerts += 1;
continue;
}
if (cert.isLocal()) {
// Creation date in the future? No way!
- log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_LOCAL, indent);
- modified = PGPPublicKey.removeCertification(modified, zert);
+ log.add(LogLevel.WARN, LogType.MSG_KC_UID_BAD_LOCAL, indent);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
badCerts += 1;
continue;
}
@@ -379,35 +386,35 @@ public class UncachedKeyRing {
if (selfCert == null) {
selfCert = zert;
} else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
- modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
+ redundantCerts += 1;
selfCert = zert;
} else {
- modified = PGPPublicKey.removeCertification(modified, userId, zert);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
+ redundantCerts += 1;
}
// If there is a revocation certificate, and it's older than this, drop it
if (revocation != null
&& revocation.getCreationTime().before(selfCert.getCreationTime())) {
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
+ indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, revocation);
revocation = null;
redundantCerts += 1;
- log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
- indent, userId);
}
break;
case PGPSignature.CERTIFICATION_REVOCATION:
// If this is older than the (latest) self cert, drop it
if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) {
- modified = PGPPublicKey.removeCertification(modified, userId, zert);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_OLD,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
+ redundantCerts += 1;
continue;
}
// first revocation? remember it.
@@ -415,16 +422,16 @@ public class UncachedKeyRing {
revocation = zert;
// more revocations? at least one is superfluous, then.
} else if (revocation.getCreationTime().before(cert.getCreationTime())) {
- modified = PGPPublicKey.removeCertification(modified, userId, revocation);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, revocation);
+ redundantCerts += 1;
revocation = zert;
} else {
- modified = PGPPublicKey.removeCertification(modified, userId, zert);
- redundantCerts += 1;
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_REVOKE_DUP,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId, zert);
+ redundantCerts += 1;
}
break;
@@ -434,9 +441,9 @@ public class UncachedKeyRing {
// If no valid certificate (if only a revocation) remains, drop it
if (selfCert == null && revocation == null) {
- modified = PGPPublicKey.removeCertification(modified, userId);
log.add(LogLevel.ERROR, LogType.MSG_KC_UID_REMOVE,
indent, userId);
+ modified = PGPPublicKey.removeCertification(modified, userId);
}
}
@@ -515,14 +522,17 @@ public class UncachedKeyRing {
continue;
}
- if (zert.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) {
+ // if this certificate says it allows signing for the key
+ if (zert.getHashedSubPackets() != null &&
+ zert.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.KEY_FLAGS)) {
+
int flags = ((KeyFlags) zert.getHashedSubPackets()
.getSubpacket(SignatureSubpacketTags.KEY_FLAGS)).getFlags();
- // If this subkey is allowed to sign data,
if ((flags & PGPKeyFlags.CAN_SIGN) == PGPKeyFlags.CAN_SIGN) {
+ boolean ok = false;
+ // it MUST have an embedded primary key binding signature
try {
PGPSignatureList list = zert.getUnhashedSubPackets().getEmbeddedSignatures();
- boolean ok = false;
for (int i = 0; i < list.size(); i++) {
WrappedSignature subsig = new WrappedSignature(list.get(i));
if (subsig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
@@ -536,17 +546,19 @@ public class UncachedKeyRing {
}
}
}
- if (!ok) {
- log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_NONE, indent);
- badCerts += 1;
- continue;
- }
} catch (Exception e) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_BAD_ERR, indent);
badCerts += 1;
continue;
}
+ // if it doesn't, get rid of this!
+ if (!ok) {
+ log.add(LogLevel.WARN, LogType.MSG_KC_SUB_PRIMARY_NONE, indent);
+ badCerts += 1;
+ continue;
+ }
}
+
}
// if we already have a cert, and this one is not newer: skip it
@@ -559,6 +571,8 @@ public class UncachedKeyRing {
selfCert = zert;
// if this is newer than a possibly existing revocation, drop that one
if (revocation != null && selfCert.getCreationTime().after(revocation.getCreationTime())) {
+ log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_REVOKE_DUP, indent);
+ redundantCerts += 1;
revocation = null;
}
@@ -592,7 +606,7 @@ public class UncachedKeyRing {
// it is not properly bound? error!
if (selfCert == null) {
- ring = replacePublicKey(ring, modified);
+ ring = removeSubKey(ring, key);
log.add(LogLevel.ERROR, LogType.MSG_KC_SUB_NO_CERT,
indent, PgpKeyHelper.convertKeyIdToHex(key.getKeyID()));
@@ -625,7 +639,8 @@ public class UncachedKeyRing {
log.add(LogLevel.OK, LogType.MSG_KC_SUCCESS, indent);
}
- return new UncachedKeyRing(ring, true);
+ return isSecret() ? new CanonicalizedSecretKeyRing((PGPSecretKeyRing) ring, 1)
+ : new CanonicalizedPublicKeyRing((PGPPublicKeyRing) ring, 0);
}
/** This operation merges information from a different keyring, returning a combined
@@ -660,7 +675,7 @@ public class UncachedKeyRing {
return left.length - right.length;
}
// compare byte-by-byte
- for (int i = 0; i < left.length && i < right.length; i++) {
+ for (int i = 0; i < left.length; i++) {
if (left[i] != right[i]) {
return (left[i] & 0xff) - (right[i] & 0xff);
}
@@ -688,7 +703,14 @@ public class UncachedKeyRing {
final PGPPublicKey resultKey = result.getPublicKey(key.getKeyID());
if (resultKey == null) {
log.add(LogLevel.DEBUG, LogType.MSG_MG_NEW_SUBKEY, indent);
- result = replacePublicKey(result, key);
+ // special case: if both rings are secret, copy over the secret key
+ if (isSecret() && other.isSecret()) {
+ PGPSecretKey sKey = ((PGPSecretKeyRing) candidate).getSecretKey(key.getKeyID());
+ result = PGPSecretKeyRing.insertSecretKey((PGPSecretKeyRing) result, sKey);
+ } else {
+ // otherwise, just insert the public key
+ result = replacePublicKey(result, key);
+ }
continue;
}
@@ -696,17 +718,7 @@ public class UncachedKeyRing {
PGPPublicKey modified = resultKey;
// Iterate certifications
- for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getSignatures())) {
- int type = cert.getSignatureType();
- // Disregard certifications on user ids, we will deal with those later
- if (type == PGPSignature.NO_CERTIFICATION
- || type == PGPSignature.DEFAULT_CERTIFICATION
- || type == PGPSignature.CASUAL_CERTIFICATION
- || type == PGPSignature.POSITIVE_CERTIFICATION
- || type == PGPSignature.CERTIFICATION_REVOCATION) {
- continue;
- }
-
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(key.getKeySignatures())) {
// Don't merge foreign stuff into secret keys
if (cert.getKeyID() != masterKeyId && isSecret()) {
continue;
@@ -770,19 +782,20 @@ public class UncachedKeyRing {
}
- public UncachedKeyRing extractPublicKeyRing() {
+ public UncachedKeyRing extractPublicKeyRing() throws IOException {
if(!isSecret()) {
throw new RuntimeException("Tried to extract public keyring from non-secret keyring. " +
"This is a programming error and should never happen!");
}
- ArrayList<PGPPublicKey> keys = new ArrayList();
Iterator<PGPPublicKey> it = mRing.getPublicKeys();
+ ByteArrayOutputStream stream = new ByteArrayOutputStream(2048);
while (it.hasNext()) {
- keys.add(it.next());
+ stream.write(it.next().getEncoded());
}
- return new UncachedKeyRing(new PGPPublicKeyRing(keys));
+ return new UncachedKeyRing(
+ new PGPPublicKeyRing(stream.toByteArray(), new JcaKeyFingerprintCalculator()));
}
/** This method replaces a public key in a keyring.
@@ -806,4 +819,20 @@ public class UncachedKeyRing {
return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
+ /** This method removes a subkey in a keyring.
+ *
+ * This method essentially wraps PGP*KeyRing.remove*Key, where the keyring may be of either
+ * the secret or public subclass.
+ *
+ * @return the resulting PGPKeyRing of the same type as the input
+ */
+ private static PGPKeyRing removeSubKey(PGPKeyRing ring, PGPPublicKey key) {
+ if (ring instanceof PGPPublicKeyRing) {
+ return PGPPublicKeyRing.removePublicKey((PGPPublicKeyRing) ring, key);
+ } else {
+ PGPSecretKey sKey = ((PGPSecretKeyRing) ring).getSecretKey(key.getKeyID());
+ return PGPSecretKeyRing.removeSecretKey((PGPSecretKeyRing) ring, sKey);
+ }
+ }
+
}
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 df19930c4..07fb4fb9e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
@@ -63,13 +63,17 @@ public class WrappedSignature {
}
try {
PGPSignatureList list;
- list = mSig.getHashedSubPackets().getEmbeddedSignatures();
- for(int i = 0; i < list.size(); i++) {
- sigs.add(new WrappedSignature(list.get(i)));
+ if (mSig.getHashedSubPackets() != null) {
+ list = mSig.getHashedSubPackets().getEmbeddedSignatures();
+ for (int i = 0; i < list.size(); i++) {
+ sigs.add(new WrappedSignature(list.get(i)));
+ }
}
- list = mSig.getUnhashedSubPackets().getEmbeddedSignatures();
- for(int i = 0; i < list.size(); i++) {
- sigs.add(new WrappedSignature(list.get(i)));
+ if (mSig.getUnhashedSubPackets() != null) {
+ list = mSig.getUnhashedSubPackets().getEmbeddedSignatures();
+ for (int i = 0; i < list.size(); i++) {
+ sigs.add(new WrappedSignature(list.get(i)));
+ }
}
} catch (PGPException e) {
// no matter
@@ -97,6 +101,9 @@ public class WrappedSignature {
if(!isRevocation()) {
throw new PgpGeneralException("Not a revocation signature.");
}
+ if (mSig.getHashedSubPackets() == null) {
+ return null;
+ }
SignatureSubpacket p = mSig.getHashedSubPackets().getSubpacket(
SignatureSubpacketTags.REVOCATION_REASON);
// For some reason, this is missing in SignatureSubpacketInputStream:146
@@ -106,7 +113,7 @@ public class WrappedSignature {
return ((RevocationReason) p).getRevocationDescription();
}
- public void init(WrappedPublicKey key) throws PgpGeneralException {
+ public void init(CanonicalizedPublicKey key) throws PgpGeneralException {
init(key.getPublicKey());
}
@@ -184,7 +191,7 @@ public class WrappedSignature {
public boolean verifySignature(UncachedPublicKey key, String uid) throws PgpGeneralException {
return verifySignature(key.getPublicKey(), uid);
}
- public boolean verifySignature(WrappedPublicKey key, String uid) throws PgpGeneralException {
+ public boolean verifySignature(CanonicalizedPublicKey key, String uid) throws PgpGeneralException {
return verifySignature(key.getPublicKey(), uid);
}
@@ -205,7 +212,7 @@ public class WrappedSignature {
}
public boolean isLocal() {
- if (!mSig.hasSubpackets()
+ if (mSig.getHashedSubPackets() == null
|| !mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.EXPORTABLE)) {
return false;
}