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/KeyRing.java25
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java65
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java277
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java79
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java235
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java117
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java85
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java60
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java140
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java26
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java19
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java81
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java62
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java179
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java189
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java123
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java3
17 files changed, 1048 insertions, 717 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
new file mode 100644
index 000000000..cfbad89b7
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
@@ -0,0 +1,25 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+
+public abstract class KeyRing {
+
+ abstract public long getMasterKeyId() throws PgpGeneralException;
+
+ abstract public String getPrimaryUserId() throws PgpGeneralException;
+
+ abstract public boolean isRevoked() throws PgpGeneralException;
+
+ abstract public boolean canCertify() throws PgpGeneralException;
+
+ abstract public long getEncryptId() throws PgpGeneralException;
+
+ abstract public boolean hasEncrypt() throws PgpGeneralException;
+
+ abstract public long getSignId() throws PgpGeneralException;
+
+ abstract public boolean hasSign() throws PgpGeneralException;
+
+ abstract public int getVerified() throws PgpGeneralException;
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java
index 86fba979c..63e2ff2f2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java
@@ -26,12 +26,10 @@ import org.spongycastle.openpgp.PGPSignatureList;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
-
public class PgpConversionHelper {
/**
@@ -60,10 +58,10 @@ public class PgpConversionHelper {
* @param keysBytes
* @return
*/
- public static ArrayList<PGPSecretKey> BytesToPGPSecretKeyList(byte[] keysBytes) {
+ public static ArrayList<UncachedSecretKey> BytesToPGPSecretKeyList(byte[] keysBytes) {
PGPObjectFactory factory = new PGPObjectFactory(keysBytes);
Object obj = null;
- ArrayList<PGPSecretKey> keys = new ArrayList<PGPSecretKey>();
+ ArrayList<UncachedSecretKey> keys = new ArrayList<UncachedSecretKey>();
try {
while ((obj = factory.nextObject()) != null) {
PGPSecretKey secKey = null;
@@ -72,7 +70,7 @@ public class PgpConversionHelper {
if (secKey == null) {
Log.e(Constants.TAG, "No keys given!");
}
- keys.add(secKey);
+ keys.add(new UncachedSecretKey(secKey));
} else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings
PGPSecretKeyRing keyRing = null;
keyRing = (PGPSecretKeyRing) obj;
@@ -82,7 +80,7 @@ public class PgpConversionHelper {
@SuppressWarnings("unchecked")
Iterator<PGPSecretKey> itr = keyRing.getSecretKeys();
while (itr.hasNext()) {
- keys.add(itr.next());
+ keys.add(new UncachedSecretKey(itr.next()));
}
}
}
@@ -100,7 +98,7 @@ public class PgpConversionHelper {
* @param keyBytes
* @return
*/
- public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) {
+ public static UncachedSecretKey BytesToPGPSecretKey(byte[] keyBytes) {
PGPObjectFactory factory = new PGPObjectFactory(keyBytes);
Object obj = null;
try {
@@ -121,7 +119,7 @@ public class PgpConversionHelper {
secKey = keyRing.getSecretKey();
}
- return secKey;
+ return new UncachedSecretKey(secKey);
}
/**
@@ -146,55 +144,4 @@ public class PgpConversionHelper {
return signatures.get(0);
}
- /**
- * Convert from ArrayList<PGPSecretKey> to byte[]
- *
- * @param keys
- * @return
- */
- public static byte[] PGPSecretKeyArrayListToBytes(ArrayList<PGPSecretKey> keys) {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- for (PGPSecretKey key : keys) {
- try {
- key.encode(os);
- } catch (IOException e) {
- Log.e(Constants.TAG, "Error while converting ArrayList<PGPSecretKey> to byte[]!", e);
- }
- }
-
- return os.toByteArray();
- }
-
- /**
- * Convert from PGPSecretKey to byte[]
- *
- * @param key
- * @return
- */
- public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) {
- try {
- return key.getEncoded();
- } catch (IOException e) {
- Log.e(Constants.TAG, "Encoding failed", e);
-
- return null;
- }
- }
-
- /**
- * Convert from PGPSecretKeyRing to byte[]
- *
- * @param keyRing
- * @return
- */
- public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) {
- try {
- return keyRing.getEncoded();
- } catch (IOException e) {
- Log.e(Constants.TAG, "Encoding failed", e);
-
- return null;
- }
- }
-
}
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 506c161ba..abe7d0fb1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -18,10 +18,7 @@
package org.sufficientlysecure.keychain.pgp;
-import android.net.Uri;
-
import org.spongycastle.bcpg.ArmoredInputStream;
-import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.openpgp.PGPCompressedData;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPEncryptedDataList;
@@ -31,29 +28,18 @@ import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPOnePassSignature;
import org.spongycastle.openpgp.PGPOnePassSignatureList;
import org.spongycastle.openpgp.PGPPBEEncryptedData;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureList;
-import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
-import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.Progressable;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.InputData;
@@ -67,7 +53,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.security.SignatureException;
import java.util.Iterator;
-import java.util.Map;
import java.util.Set;
/**
@@ -248,7 +233,7 @@ public class PgpDecryptVerify {
PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
PGPPBEEncryptedData encryptedDataSymmetric = null;
- PGPSecretKey secretEncryptionKey = null;
+ WrappedSecretKey secretEncryptionKey = null;
Iterator<?> it = enc.getEncryptedDataObjects();
boolean asymmetricPacketFound = false;
boolean symmetricPacketFound = false;
@@ -260,15 +245,12 @@ public class PgpDecryptVerify {
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
- long masterKeyId;
- PGPSecretKeyRing secretKeyRing;
+ WrappedSecretKeyRing secretKeyRing;
try {
- // get master key id for this encryption key id
- masterKeyId = mProviderHelper.getMasterKeyId(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(encData.getKeyID()))
- );
// get actual keyring object based on master key id
- secretKeyRing = mProviderHelper.getPGPSecretKeyRing(masterKeyId);
+ secretKeyRing = mProviderHelper.getWrappedSecretKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(encData.getKeyID())
+ );
} catch (ProviderHelper.NotFoundException e) {
// continue with the next packet in the while loop
continue;
@@ -278,13 +260,14 @@ public class PgpDecryptVerify {
continue;
}
// get subkey which has been used for this encryption packet
- secretEncryptionKey = secretKeyRing.getSecretKey(encData.getKeyID());
+ secretEncryptionKey = secretKeyRing.getSubKey(encData.getKeyID());
if (secretEncryptionKey == null) {
// continue with the next packet in the while loop
continue;
}
/* secret key exists in database! */
+ long masterKeyId = secretEncryptionKey.getRing().getMasterKeyId();
// allow only specific keys for decryption?
if (mAllowedKeyIds != null) {
@@ -359,23 +342,17 @@ public class PgpDecryptVerify {
} else if (asymmetricPacketFound) {
currentProgress += 5;
updateProgress(R.string.progress_extracting_key, currentProgress, 100);
- PGPPrivateKey privateKey;
try {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- mPassphrase.toCharArray());
- privateKey = secretEncryptionKey.extractPrivateKey(keyDecryptor);
- } catch (PGPException e) {
- throw new WrongPassphraseException();
- }
- if (privateKey == null) {
+ if (!secretEncryptionKey.unlock(mPassphrase)) {
+ throw new WrongPassphraseException();
+ }
+ } catch(PgpGeneralException e) {
throw new KeyExtractionException();
}
currentProgress += 5;
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
- PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey);
+ PublicKeyDataDecryptorFactory decryptorFactory = secretEncryptionKey.getDecryptorFactory();
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
@@ -388,10 +365,10 @@ public class PgpDecryptVerify {
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
Object dataChunk = plainFact.nextObject();
- PGPOnePassSignature signature = null;
OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
- PGPPublicKey signatureKey = null;
int signatureIndex = -1;
+ WrappedPublicKeyRing signingRing = null;
+ WrappedPublicKey signingKey = null;
if (dataChunk instanceof PGPCompressedData) {
updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
@@ -403,6 +380,8 @@ public class PgpDecryptVerify {
currentProgress += 10;
}
+ PGPOnePassSignature signature = null;
+
if (dataChunk instanceof PGPOnePassSignatureList) {
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
@@ -410,19 +389,13 @@ public class PgpDecryptVerify {
// go through all signatures
// and find out for which signature we have a key in our database
- Long masterKeyId = null;
- String primaryUserId = null;
for (int i = 0; i < sigList.size(); ++i) {
try {
- Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
- Long.toString(sigList.get(i).getKeyID()));
- Map<String, Object> data = mProviderHelper.getGenericData(uri,
- new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
- new int[] { ProviderHelper.FIELD_TYPE_INTEGER,
- ProviderHelper.FIELD_TYPE_STRING }
+ long sigKeyId = sigList.get(i).getKeyID();
+ signingRing = mProviderHelper.getWrappedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
);
- masterKeyId = (Long) data.get(KeyRings.MASTER_KEY_ID);
- primaryUserId = (String) data.get(KeyRings.USER_ID);
+ signingKey = signingRing.getSubkey(sigKeyId);
signatureIndex = i;
} catch (ProviderHelper.NotFoundException e) {
Log.d(Constants.TAG, "key not found!");
@@ -430,43 +403,21 @@ public class PgpDecryptVerify {
}
}
- if (masterKeyId != null) {
+ if (signingKey != null) {
// key found in our database!
signature = sigList.get(signatureIndex);
- PGPPublicKeyRing publicKeyRing = null;
- try {
- publicKeyRing = mProviderHelper
- .getPGPPublicKeyRing(masterKeyId);
- } catch (ProviderHelper.NotFoundException e) {
- // can't happen
- }
-
- // get the subkey which has been used to generate this signature
- signatureKey = publicKeyRing.getPublicKey(signature.getKeyID());
-
signatureResultBuilder.signatureAvailable(true);
signatureResultBuilder.knownKey(true);
- signatureResultBuilder.userId(primaryUserId);
- signatureResultBuilder.keyId(masterKeyId);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- signature.init(contentVerifierBuilderProvider, signatureKey);
-
- // get certification status of this key
- boolean isSignatureKeyCertified;
+ signatureResultBuilder.keyId(signingRing.getMasterKeyId());
try {
- Object data = mProviderHelper.getGenericData(
- KeychainContract.KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)),
- KeyRings.VERIFIED,
- ProviderHelper.FIELD_TYPE_INTEGER);
- isSignatureKeyCertified = ((Long) data > 0);
- } catch (ProviderHelper.NotFoundException e) {
- isSignatureKeyCertified = false;
+ signatureResultBuilder.userId(signingRing.getPrimaryUserId());
+ } catch(PgpGeneralException e) {
+ Log.d(Constants.TAG, "No primary user id in key " + signingRing.getMasterKeyId());
}
- signatureResultBuilder.signatureKeyCertified(isSignatureKeyCertified);
+ signatureResultBuilder.signatureKeyCertified(signingRing.getVerified() > 0);
+
+ signingKey.initSignature(signature);
} else {
// no key in our database -> return "unknown pub key" status including the first key id
if (!sigList.isEmpty()) {
@@ -541,7 +492,7 @@ public class PgpDecryptVerify {
// Verify signature and check binding signatures
boolean validSignature = signature.verify(messageSignature);
- boolean validKeyBinding = verifyKeyBinding(messageSignature, signatureKey);
+ boolean validKeyBinding = signingRing.verifySubkeyBinding(signingKey);
signatureResultBuilder.validSignature(validSignature);
signatureResultBuilder.validKeyBinding(validKeyBinding);
@@ -617,22 +568,19 @@ public class PgpDecryptVerify {
throw new InvalidDataException();
}
+ WrappedPublicKeyRing signingRing = null;
+ WrappedPublicKey signingKey = null;
+ int signatureIndex = -1;
+
// go through all signatures
// and find out for which signature we have a key in our database
- Long masterKeyId = null;
- String primaryUserId = null;
- int signatureIndex = 0;
for (int i = 0; i < sigList.size(); ++i) {
try {
- Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
- Long.toString(sigList.get(i).getKeyID()));
- Map<String, Object> data = mProviderHelper.getGenericData(uri,
- new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
- new int[] { ProviderHelper.FIELD_TYPE_INTEGER,
- ProviderHelper.FIELD_TYPE_STRING }
+ long sigKeyId = sigList.get(i).getKeyID();
+ signingRing = mProviderHelper.getWrappedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
);
- masterKeyId = (Long) data.get(KeyRings.MASTER_KEY_ID);
- primaryUserId = (String) data.get(KeyRings.USER_ID);
+ signingKey = signingRing.getSubkey(sigKeyId);
signatureIndex = i;
} catch (ProviderHelper.NotFoundException e) {
Log.d(Constants.TAG, "key not found!");
@@ -641,44 +589,22 @@ public class PgpDecryptVerify {
}
PGPSignature signature = null;
- PGPPublicKey signatureKey = null;
- if (masterKeyId != null) {
+
+ if (signingKey != null) {
// key found in our database!
signature = sigList.get(signatureIndex);
- PGPPublicKeyRing publicKeyRing = null;
- try {
- publicKeyRing = mProviderHelper
- .getPGPPublicKeyRing(masterKeyId);
- } catch (ProviderHelper.NotFoundException e) {
- // can't happen
- }
-
- // get the subkey which has been used to generate this signature
- signatureKey = publicKeyRing.getPublicKey(signature.getKeyID());
-
signatureResultBuilder.signatureAvailable(true);
signatureResultBuilder.knownKey(true);
- signatureResultBuilder.userId(primaryUserId);
- signatureResultBuilder.keyId(masterKeyId);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- signature.init(contentVerifierBuilderProvider, signatureKey);
-
- // get certification status of this key
- boolean isSignatureKeyCertified;
+ signatureResultBuilder.keyId(signingRing.getMasterKeyId());
try {
- Object data = mProviderHelper.getGenericData(
- KeychainContract.KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)),
- KeyRings.VERIFIED,
- ProviderHelper.FIELD_TYPE_INTEGER);
- isSignatureKeyCertified = ((Long) data > 0);
- } catch (ProviderHelper.NotFoundException e) {
- isSignatureKeyCertified = false;
+ signatureResultBuilder.userId(signingRing.getPrimaryUserId());
+ } catch(PgpGeneralException e) {
+ Log.d(Constants.TAG, "No primary user id in key " + signingRing.getMasterKeyId());
}
- signatureResultBuilder.signatureKeyCertified(isSignatureKeyCertified);
+ signatureResultBuilder.signatureKeyCertified(signingRing.getVerified() > 0);
+
+ signingKey.initSignature(signature);
} else {
// no key in our database -> return "unknown pub key" status including the first key id
if (!sigList.isEmpty()) {
@@ -710,7 +636,7 @@ public class PgpDecryptVerify {
// Verify signature and check binding signatures
boolean validSignature = signature.verify();
- boolean validKeyBinding = verifyKeyBinding(signature, signatureKey);
+ boolean validKeyBinding = signingRing.verifySubkeyBinding(signingKey);
signatureResultBuilder.validSignature(validSignature);
signatureResultBuilder.validKeyBinding(validKeyBinding);
@@ -722,113 +648,6 @@ public class PgpDecryptVerify {
return result;
}
- private boolean verifyKeyBinding(PGPSignature signature, PGPPublicKey signatureKey) {
- long signatureKeyId = signature.getKeyID();
- boolean validKeyBinding = false;
-
- PGPPublicKey mKey = null;
- try {
- PGPPublicKeyRing signKeyRing = mProviderHelper.getPGPPublicKeyRingWithKeyId(
- signatureKeyId);
- mKey = signKeyRing.getPublicKey();
- } catch (ProviderHelper.NotFoundException e) {
- Log.d(Constants.TAG, "key not found");
- }
-
- if (signature.getKeyID() != mKey.getKeyID()) {
- validKeyBinding = verifyKeyBinding(mKey, signatureKey);
- } else { //if the key used to make the signature was the master key, no need to check binding sigs
- validKeyBinding = true;
- }
- return validKeyBinding;
- }
-
- private boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
- boolean validSubkeyBinding = false;
- boolean validTempSubkeyBinding = false;
- boolean validPrimaryKeyBinding = false;
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- Iterator<PGPSignature> itr = signingPublicKey.getSignatures();
-
- while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong?
- //gpg has an invalid subkey binding error on key import I think, but doesn't shout
- //about keys without subkey signing. Can't get it to import a slightly broken one
- //either, so we will err on bad subkey binding here.
- PGPSignature sig = itr.next();
- if (sig.getKeyID() == masterPublicKey.getKeyID() &&
- sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
- //check and if ok, check primary key binding.
- try {
- sig.init(contentVerifierBuilderProvider, masterPublicKey);
- validTempSubkeyBinding = sig.verifyCertification(masterPublicKey, signingPublicKey);
- } catch (PGPException e) {
- continue;
- } catch (SignatureException e) {
- continue;
- }
-
- if (validTempSubkeyBinding) {
- validSubkeyBinding = true;
- }
- if (validTempSubkeyBinding) {
- validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(),
- masterPublicKey, signingPublicKey);
- if (validPrimaryKeyBinding) {
- break;
- }
- validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(),
- masterPublicKey, signingPublicKey);
- if (validPrimaryKeyBinding) {
- break;
- }
- }
- }
- }
- return (validSubkeyBinding & validPrimaryKeyBinding);
- }
-
- private boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts,
- PGPPublicKey masterPublicKey,
- PGPPublicKey signingPublicKey) {
- boolean validPrimaryKeyBinding = false;
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureList eSigList;
-
- if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
- try {
- eSigList = pkts.getEmbeddedSignatures();
- } catch (IOException e) {
- return false;
- } catch (PGPException e) {
- return false;
- }
- for (int j = 0; j < eSigList.size(); ++j) {
- PGPSignature emSig = eSigList.get(j);
- if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
- try {
- emSig.init(contentVerifierBuilderProvider, signingPublicKey);
- validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey);
- if (validPrimaryKeyBinding) {
- break;
- }
- } catch (PGPException e) {
- continue;
- } catch (SignatureException e) {
- continue;
- }
- }
- }
- }
-
- return validPrimaryKeyBinding;
- }
-
/**
* Mostly taken from ClearSignedFileProcessor in Bouncy Castle
*
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 f64282f5f..a55765542 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -27,12 +27,12 @@ import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyRing;
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.jcajce.JcaKeyFingerprintCalculator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
@@ -100,12 +100,12 @@ public class PgpImportExport {
}
}
- public boolean uploadKeyRingToServer(HkpKeyserver server, PGPPublicKeyRing keyring) {
+ public boolean uploadKeyRingToServer(HkpKeyserver server, WrappedPublicKeyRing keyring) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = null;
try {
aos = new ArmoredOutputStream(bos);
- aos.write(keyring.getEncoded());
+ keyring.encode(aos);
aos.close();
String armoredKey = bos.toString("UTF-8");
@@ -150,8 +150,25 @@ public class PgpImportExport {
if (obj instanceof PGPKeyRing) {
PGPKeyRing keyring = (PGPKeyRing) obj;
-
- int status = storeKeyRingInCache(keyring);
+ int status;
+ // TODO Better try to get this one from the db first!
+ if(keyring instanceof PGPSecretKeyRing) {
+ PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring;
+ // TODO: preserve certifications
+ // (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?)
+ PGPPublicKeyRing newPubRing = null;
+ for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(
+ secretKeyRing.getPublicKeys())) {
+ if (newPubRing == null) {
+ newPubRing = new PGPPublicKeyRing(key.getEncoded(),
+ new JcaKeyFingerprintCalculator());
+ }
+ newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key);
+ }
+ status = storeKeyRingInCache(new UncachedKeyRing(newPubRing ,secretKeyRing));
+ } else {
+ status = storeKeyRingInCache(new UncachedKeyRing((PGPPublicKeyRing) keyring));
+ }
if (status == RETURN_ERROR) {
throw new PgpGeneralException(
@@ -211,9 +228,11 @@ public class PgpImportExport {
updateProgress(progress * 100 / masterKeyIdsSize, 100);
try {
- PGPPublicKeyRing publicKeyRing = mProviderHelper.getPGPPublicKeyRing(pubKeyMasterId);
+ WrappedPublicKeyRing ring = mProviderHelper.getWrappedPublicKeyRing(
+ KeychainContract.KeyRings.buildGenericKeyRingUri(pubKeyMasterId)
+ );
- publicKeyRing.encode(arOutStream);
+ ring.encode(arOutStream);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
// TODO: inform user?
@@ -260,44 +279,16 @@ public class PgpImportExport {
}
@SuppressWarnings("unchecked")
- public int storeKeyRingInCache(PGPKeyRing keyring) {
- int status = RETURN_ERROR;
+ public int storeKeyRingInCache(UncachedKeyRing keyring) {
+ int status;
try {
- if (keyring instanceof PGPSecretKeyRing) {
- PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring;
- boolean save = true;
-
- for (PGPSecretKey testSecretKey : new IterableIterator<PGPSecretKey>(
- secretKeyRing.getSecretKeys())) {
- if (!testSecretKey.isMasterKey()) {
- if (testSecretKey.isPrivateKeyEmpty()) {
- // this is bad, something is very wrong...
- save = false;
- status = RETURN_BAD;
- }
- }
- }
-
- if (save) {
- // TODO: preserve certifications
- // (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?)
- PGPPublicKeyRing newPubRing = null;
- for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(
- secretKeyRing.getPublicKeys())) {
- if (newPubRing == null) {
- newPubRing = new PGPPublicKeyRing(key.getEncoded(),
- new JcaKeyFingerprintCalculator());
- }
- newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key);
- }
- if (newPubRing != null) {
- mProviderHelper.saveKeyRing(newPubRing);
- }
- mProviderHelper.saveKeyRing(secretKeyRing);
- status = RETURN_OK;
- }
- } else if (keyring instanceof PGPPublicKeyRing) {
- PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring;
+ PGPSecretKeyRing secretKeyRing = keyring.getSecretRing();
+ PGPPublicKeyRing publicKeyRing = keyring.getPublicRing();
+ // see what type we have. we can either have a secret + public keyring, or just public
+ if (secretKeyRing != null) {
+ mProviderHelper.saveKeyRing(publicKeyRing, secretKeyRing);
+ status = RETURN_OK;
+ } else {
mProviderHelper.saveKeyRing(publicKeyRing);
status = RETURN_OK;
}
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 f90250f57..b25c38f1a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
@@ -52,14 +52,12 @@ public class PgpKeyHelper {
private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$");
+ @Deprecated
public static Date getCreationDate(PGPPublicKey key) {
return key.getCreationTime();
}
- public static Date getCreationDate(PGPSecretKey key) {
- return key.getPublicKey().getCreationTime();
- }
-
+ @Deprecated
public static Date getExpiryDate(PGPPublicKey key) {
Date creationDate = getCreationDate(key);
if (key.getValidDays() == 0) {
@@ -73,185 +71,6 @@ public class PgpKeyHelper {
return calendar.getTime();
}
- public static Date getExpiryDate(PGPSecretKey key) {
- return getExpiryDate(key.getPublicKey());
- }
-
- public static boolean isExpired(PGPPublicKey key) {
- Date creationDate = getCreationDate(key);
- Date expiryDate = getExpiryDate(key);
- Date now = new Date();
- if (now.compareTo(creationDate) >= 0
- && (expiryDate == null || now.compareTo(expiryDate) <= 0)) {
- return false;
- }
- return true;
- }
-
- @SuppressWarnings("unchecked")
- public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
- long cnt = 0;
- if (keyRing == null) {
- return null;
- }
- for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
- if (cnt == num) {
- return key;
- }
- cnt++;
- }
-
- return null;
- }
-
- @SuppressWarnings("unchecked")
- private static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) {
- Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>();
-
- for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) {
- if (isEncryptionKey(key)) {
- encryptKeys.add(key);
- }
- }
-
- return encryptKeys;
- }
-
- @SuppressWarnings("unchecked")
- private static Vector<PGPSecretKey> getSigningKeys(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
-
- for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
- if (isSigningKey(key)) {
- signingKeys.add(key);
- }
- }
-
- return signingKeys;
- }
-
- @SuppressWarnings("unchecked")
- private static Vector<PGPSecretKey> getCertificationKeys(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
-
- for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
- if (isCertificationKey(key)) {
- signingKeys.add(key);
- }
- }
-
- return signingKeys;
- }
-
- private static Vector<PGPPublicKey> getUsableEncryptKeys(PGPPublicKeyRing keyRing) {
- Vector<PGPPublicKey> usableKeys = new Vector<PGPPublicKey>();
- Vector<PGPPublicKey> encryptKeys = getEncryptKeys(keyRing);
- PGPPublicKey masterKey = null;
- for (int i = 0; i < encryptKeys.size(); ++i) {
- PGPPublicKey key = encryptKeys.get(i);
- if (!isExpired(key) && !key.isRevoked()) {
- if (key.isMasterKey()) {
- masterKey = key;
- } else {
- usableKeys.add(key);
- }
- }
- }
- if (masterKey != null) {
- usableKeys.add(masterKey);
- }
- return usableKeys;
- }
-
- private static Vector<PGPSecretKey> getUsableCertificationKeys(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
- Vector<PGPSecretKey> signingKeys = getCertificationKeys(keyRing);
- PGPSecretKey masterKey = null;
- for (int i = 0; i < signingKeys.size(); ++i) {
- PGPSecretKey key = signingKeys.get(i);
- if (key.isMasterKey()) {
- masterKey = key;
- } else {
- usableKeys.add(key);
- }
- }
- if (masterKey != null) {
- usableKeys.add(masterKey);
- }
- return usableKeys;
- }
-
- private static Vector<PGPSecretKey> getUsableSigningKeys(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
- Vector<PGPSecretKey> signingKeys = getSigningKeys(keyRing);
- PGPSecretKey masterKey = null;
- for (int i = 0; i < signingKeys.size(); ++i) {
- PGPSecretKey key = signingKeys.get(i);
- if (key.isMasterKey()) {
- masterKey = key;
- } else {
- usableKeys.add(key);
- }
- }
- if (masterKey != null) {
- usableKeys.add(masterKey);
- }
- return usableKeys;
- }
-
-
- public static PGPPublicKey getFirstEncryptSubkey(PGPPublicKeyRing keyRing) {
- Vector<PGPPublicKey> encryptKeys = getUsableEncryptKeys(keyRing);
- if (encryptKeys.size() == 0) {
- Log.e(Constants.TAG, "encryptKeys is null!");
- return null;
- }
- return encryptKeys.get(0);
- }
-
- public static PGPSecretKey getFirstCertificationSubkey(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> signingKeys = getUsableCertificationKeys(keyRing);
- if (signingKeys.size() == 0) {
- return null;
- }
- return signingKeys.get(0);
- }
-
- public static PGPSecretKey getFirstSigningSubkey(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> signingKeys = getUsableSigningKeys(keyRing);
- if (signingKeys.size() == 0) {
- return null;
- }
- return signingKeys.get(0);
- }
-
- public static int getKeyUsage(PGPSecretKey key) {
- return getKeyUsage(key.getPublicKey());
- }
-
- @SuppressWarnings("unchecked")
- private static int getKeyUsage(PGPPublicKey key) {
- int usage = 0;
- if (key.getVersion() >= 4) {
- for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
- continue;
- }
-
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
- if (hashed != null) {
- usage |= hashed.getKeyFlags();
- }
-
- PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
- if (unhashed != null) {
- usage |= unhashed.getKeyFlags();
- }
- }
- }
- return usage;
- }
-
@SuppressWarnings("unchecked")
public static boolean isEncryptionKey(PGPPublicKey key) {
if (!key.isEncryptionKey()) {
@@ -293,10 +112,6 @@ public class PgpKeyHelper {
return false;
}
- public static boolean isEncryptionKey(PGPSecretKey key) {
- return isEncryptionKey(key.getPublicKey());
- }
-
@SuppressWarnings("unchecked")
public static boolean isSigningKey(PGPPublicKey key) {
if (key.getVersion() <= 3) {
@@ -328,10 +143,6 @@ public class PgpKeyHelper {
return false;
}
- public static boolean isSigningKey(PGPSecretKey key) {
- return isSigningKey(key.getPublicKey());
- }
-
@SuppressWarnings("unchecked")
public static boolean isCertificationKey(PGPPublicKey key) {
if (key.getVersion() <= 3) {
@@ -358,48 +169,6 @@ public class PgpKeyHelper {
return false;
}
- public static boolean isAuthenticationKey(PGPSecretKey key) {
- return isAuthenticationKey(key.getPublicKey());
- }
-
- @SuppressWarnings("unchecked")
- public static boolean isAuthenticationKey(PGPPublicKey key) {
- if (key.getVersion() <= 3) {
- return true;
- }
-
- for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
- continue;
- }
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
-
- if (hashed != null && (hashed.getKeyFlags() & KeyFlags.AUTHENTICATION) != 0) {
- return true;
- }
-
- PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
-
- if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.AUTHENTICATION) != 0) {
- return true;
- }
- }
-
- return false;
- }
-
- public static boolean isCertificationKey(PGPSecretKey key) {
- return isCertificationKey(key.getPublicKey());
- }
-
- public static String getAlgorithmInfo(Context context, PGPPublicKey key) {
- return getAlgorithmInfo(context, key.getAlgorithm(), key.getBitStrength());
- }
-
- public static String getAlgorithmInfo(Context context, PGPSecretKey key) {
- return getAlgorithmInfo(context, key.getPublicKey());
- }
-
/**
* TODO: Only used in HkpKeyServer. Get rid of this one!
*/
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 9dd9f660b..b9634c34a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -35,7 +35,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.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
@@ -48,10 +47,8 @@ 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.Progressable;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
-import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Primes;
import java.io.IOException;
@@ -66,7 +63,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
-import java.util.List;
import java.util.TimeZone;
/**
@@ -124,7 +120,7 @@ public class PgpKeyOperation {
*/
// TODO: key flags?
- public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase,
+ public byte[] createKey(int algorithmChoice, int keySize, String passphrase,
boolean isMasterKey)
throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
PgpGeneralMsgIdException, InvalidAlgorithmParameterException {
@@ -188,35 +184,15 @@ public class PgpKeyOperation {
PGPEncryptedData.CAST5, sha1Calc)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
- sha1Calc, isMasterKey, keyEncryptor);
- }
-
- public PGPSecretKeyRing changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassphrase,
- String newPassphrase)
- throws IOException, PGPException, NoSuchProviderException {
-
- updateProgress(R.string.progress_building_key, 0, 100);
- if (oldPassphrase == null) {
- oldPassphrase = "";
+ try {
+ return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
+ sha1Calc, isMasterKey, keyEncryptor).getEncoded();
+ } catch(IOException e) {
+ throw new PgpGeneralMsgIdException(R.string.error_encoding);
}
- if (newPassphrase == null) {
- newPassphrase = "";
- }
-
- PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword(
- keyRing,
- new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()),
- new JcePBESecretKeyEncryptorBuilder(keyRing.getSecretKey()
- .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray()));
-
- return newKeyRing;
-
}
- public Pair<PGPSecretKeyRing, PGPPublicKeyRing> buildNewSecretKey(
+ public UncachedKeyRing buildNewSecretKey(
SaveKeyringParcel saveParcel)
throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException {
@@ -224,7 +200,7 @@ public class PgpKeyOperation {
boolean canSign;
String mainUserId = saveParcel.userIds.get(0);
- PGPSecretKey masterKey = saveParcel.keys.get(0);
+ PGPSecretKey masterKey = saveParcel.keys.get(0).getSecretKeyExternal();
// this removes all userIds and certifications previously attached to the masterPublicKey
PGPPublicKey masterPublicKey = masterKey.getPublicKey();
@@ -299,7 +275,7 @@ public class PgpKeyOperation {
for (int i = 1; i < saveParcel.keys.size(); ++i) {
updateProgress(40 + 40 * (i - 1) / (saveParcel.keys.size() - 1), 100);
- PGPSecretKey subKey = saveParcel.keys.get(i);
+ PGPSecretKey subKey = saveParcel.keys.get(i).getSecretKeyExternal();
PGPPublicKey subPublicKey = subKey.getPublicKey();
PBESecretKeyDecryptor keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder()
@@ -357,17 +333,19 @@ public class PgpKeyOperation {
PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing();
PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing();
- return new Pair<PGPSecretKeyRing, PGPPublicKeyRing>(secretKeyRing, publicKeyRing);
+ return new UncachedKeyRing(publicKeyRing, secretKeyRing);
}
- public Pair<PGPSecretKeyRing, PGPPublicKeyRing> buildSecretKey(PGPSecretKeyRing mKR,
- PGPPublicKeyRing pKR,
- SaveKeyringParcel saveParcel)
+ public UncachedKeyRing buildSecretKey(WrappedSecretKeyRing wmKR,
+ WrappedPublicKeyRing wpKR,
+ SaveKeyringParcel saveParcel)
throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException {
+ PGPSecretKeyRing mKR = wmKR.getRing();
+ PGPPublicKeyRing pKR = wpKR.getRing();
+
updateProgress(R.string.progress_building_key, 0, 100);
- PGPSecretKey masterKey = saveParcel.keys.get(0);
if (saveParcel.oldPassphrase == null) {
saveParcel.oldPassphrase = "";
@@ -399,12 +377,12 @@ public class PgpKeyOperation {
*/
if (saveParcel.deletedKeys != null) {
- for (PGPSecretKey dKey : saveParcel.deletedKeys) {
- mKR = PGPSecretKeyRing.removeSecretKey(mKR, dKey);
+ for (UncachedSecretKey dKey : saveParcel.deletedKeys) {
+ mKR = PGPSecretKeyRing.removeSecretKey(mKR, dKey.getSecretKeyExternal());
}
}
- masterKey = mKR.getSecretKey();
+ PGPSecretKey masterKey = mKR.getSecretKey();
PGPPublicKey masterPublicKey = masterKey.getPublicKey();
int usageId = saveParcel.keysUsages.get(0);
@@ -564,7 +542,7 @@ public class PgpKeyOperation {
for (int i = 1; i < saveParcel.keys.size(); ++i) {
updateProgress(40 + 50 * i / saveParcel.keys.size(), 100);
if (saveParcel.moddedKeys[i]) {
- PGPSecretKey subKey = saveParcel.keys.get(i);
+ PGPSecretKey subKey = saveParcel.keys.get(i).getSecretKeyExternal();
PGPPublicKey subPublicKey = subKey.getPublicKey();
PBESecretKeyDecryptor keyDecryptor2;
@@ -686,61 +664,8 @@ public class PgpKeyOperation {
*/
- return new Pair<PGPSecretKeyRing, PGPPublicKeyRing>(mKR, pKR);
-
- }
-
- /**
- * Certify the given pubkeyid with the given masterkeyid.
- *
- * @param certificationKey Certifying key
- * @param publicKey public key to certify
- * @param userIds User IDs to certify, must not be null or empty
- * @param passphrase Passphrase of the secret key
- * @return A keyring with added certifications
- */
- public PGPPublicKey certifyKey(PGPSecretKey certificationKey, PGPPublicKey publicKey,
- List<String> userIds, String passphrase)
- throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException,
- PGPException, SignatureException {
-
- // create a signatureGenerator from the supplied masterKeyId and passphrase
- PGPSignatureGenerator signatureGenerator;
- {
-
- if (certificationKey == null) {
- throw new PgpGeneralMsgIdException(R.string.error_no_signature_key);
- }
-
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
- PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- throw new PgpGeneralMsgIdException(R.string.error_could_not_extract_private_key);
- }
-
- // TODO: SHA256 fixed?
- JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
- certificationKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, signaturePrivateKey);
- }
-
- { // supply signatureGenerator with a SubpacketVector
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- PGPSignatureSubpacketVector packetVector = spGen.generate();
- signatureGenerator.setHashedSubpackets(packetVector);
- }
-
- // fetch public key ring, add the certification and return it
- for (String userId : new IterableIterator<String>(userIds.iterator())) {
- PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey);
- publicKey = PGPPublicKey.addCertification(publicKey, userId, sig);
- }
+ return new UncachedKeyRing(pKR, mKR);
- return publicKey;
}
/**
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 665dc82cc..4cb92c368 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -25,25 +25,14 @@ import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPLiteralData;
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
-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.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureGenerator;
-import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPV3SignatureGenerator;
-import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.Progressable;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -277,20 +266,17 @@ public class PgpSignEncrypt {
}
/* Get keys for signature generation for later usage */
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
- String signingUserId = null;
+ WrappedSecretKey signingKey = null;
if (enableSignature) {
+ WrappedSecretKeyRing signingKeyRing;
try {
- signingKeyRing = mProviderHelper.getPGPSecretKeyRing(mSignatureMasterKeyId);
- signingUserId = (String) mProviderHelper.getUnifiedData(mSignatureMasterKeyId,
- KeychainContract.KeyRings.USER_ID, ProviderHelper.FIELD_TYPE_STRING);
+ signingKeyRing = mProviderHelper.getWrappedSecretKeyRing(mSignatureMasterKeyId);
} catch (ProviderHelper.NotFoundException e) {
throw new NoSigningKeyException();
}
- signingKey = PgpKeyHelper.getFirstSigningSubkey(signingKeyRing);
- if (signingKey == null) {
+ try {
+ signingKey = signingKeyRing.getSigningSubKey();
+ } catch(PgpGeneralException e) {
throw new NoSigningKeyException();
}
@@ -300,10 +286,9 @@ public class PgpSignEncrypt {
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
- signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
+ try {
+ signingKey.unlock(mSignaturePassphrase);
+ } catch (PgpGeneralException e) {
throw new KeyExtractionException();
}
}
@@ -331,13 +316,12 @@ public class PgpSignEncrypt {
// Asymmetric encryption
for (long id : mEncryptionMasterKeyIds) {
try {
- PGPPublicKeyRing keyRing = mProviderHelper.getPGPPublicKeyRing(id);
- PGPPublicKey key = PgpKeyHelper.getFirstEncryptSubkey(keyRing);
- if (key != null) {
- JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
- new JcePublicKeyKeyEncryptionMethodGenerator(key);
- cPk.addMethod(pubKeyEncryptionGenerator);
- }
+ WrappedPublicKeyRing keyRing = mProviderHelper.getWrappedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingUri(id));
+ WrappedPublicKey key = keyRing.getEncryptionSubKey();
+ cPk.addMethod(key.getPubKeyEncryptionGenerator());
+ } catch (PgpGeneralException e) {
+ Log.e(Constants.TAG, "key not found!", e);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
}
@@ -351,29 +335,18 @@ public class PgpSignEncrypt {
if (enableSignature) {
updateProgress(R.string.progress_preparing_signature, 10, 100);
- // content signer based on signing key algorithm and chosen hash algorithm
- JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
- signingKey.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- int signatureType;
- if (mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption) {
- // for sign-only ascii text
- signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
- } else {
- signatureType = PGPSignature.BINARY_DOCUMENT;
- }
-
- if (mSignatureForceV3) {
- signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
- signatureV3Generator.init(signatureType, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- signatureGenerator.init(signatureType, signaturePrivateKey);
-
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- spGen.setSignerUserID(false, signingUserId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
+ try {
+ boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption;
+ if (mSignatureForceV3) {
+ signatureV3Generator = signingKey.getV3SignatureGenerator(
+ mSignatureHashAlgorithm,cleartext);
+ } else {
+ signatureGenerator = signingKey.getSignatureGenerator(
+ mSignatureHashAlgorithm, cleartext);
+ }
+ } catch (PgpGeneralException e) {
+ // TODO throw correct type of exception (which shouldn't be PGPException)
+ throw new KeyExtractionException();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
new file mode 100644
index 000000000..58601c49a
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -0,0 +1,60 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.openpgp.PGPObjectFactory;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
+import org.spongycastle.openpgp.PGPUtil;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class UncachedKeyRing {
+
+ final PGPPublicKeyRing mPublicRing;
+ final PGPSecretKeyRing mSecretRing;
+
+ UncachedKeyRing(PGPPublicKeyRing publicRing, PGPSecretKeyRing secretRing) {
+ mPublicRing = publicRing;
+ mSecretRing = secretRing;
+ }
+
+ UncachedKeyRing(PGPPublicKeyRing publicRing) {
+ this(publicRing, null);
+ }
+
+ public PGPPublicKeyRing getPublicRing() {
+ return mPublicRing;
+ }
+
+ public PGPSecretKeyRing getSecretRing() {
+ return mSecretRing;
+ }
+
+ public byte[] getFingerprint() {
+ return mPublicRing.getPublicKey().getFingerprint();
+ }
+
+ public static UncachedKeyRing decodePubkeyFromData(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 PGPPublicKeyRing) {
+ return new UncachedKeyRing((PGPPublicKeyRing) obj);
+ } else {
+ throw new PgpGeneralException("Object not recognized as PGPPublicKeyRing!");
+ }
+ } else {
+ throw new PgpGeneralException("Object not recognized as PGPPublicKeyRing!");
+ }
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
new file mode 100644
index 000000000..bc37f6201
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
@@ -0,0 +1,140 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.bcpg.sig.KeyFlags;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+public class UncachedPublicKey {
+ protected final PGPPublicKey mPublicKey;
+ private Integer mCacheUsage = null;
+
+ public UncachedPublicKey(PGPPublicKey key) {
+ mPublicKey = key;
+ }
+
+ public long getKeyId() {
+ return mPublicKey.getKeyID();
+ }
+
+ public boolean isRevoked() {
+ return mPublicKey.isRevoked();
+ }
+
+ public Date getCreationTime() {
+ return mPublicKey.getCreationTime();
+ }
+
+ public Date getExpiryTime() {
+ Date creationDate = getCreationTime();
+ if (mPublicKey.getValidDays() == 0) {
+ // no expiry
+ return null;
+ }
+ Calendar calendar = GregorianCalendar.getInstance();
+ calendar.setTime(creationDate);
+ calendar.add(Calendar.DATE, mPublicKey.getValidDays());
+
+ return calendar.getTime();
+ }
+
+ public boolean isExpired() {
+ Date creationDate = mPublicKey.getCreationTime();
+ Date expiryDate = mPublicKey.getValidSeconds() > 0
+ ? new Date(creationDate.getTime() + mPublicKey.getValidSeconds() * 1000) : null;
+
+ Date now = new Date();
+ return creationDate.after(now) || (expiryDate != null && expiryDate.before(now));
+ }
+
+ public boolean isMasterKey() {
+ return mPublicKey.isMasterKey();
+ }
+
+ public int getAlgorithm() {
+ return mPublicKey.getAlgorithm();
+ }
+
+ public boolean isElGamalEncrypt() {
+ return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT;
+ }
+
+ public boolean isDSA() {
+ return getAlgorithm() == PGPPublicKey.DSA;
+ }
+
+ @SuppressWarnings("unchecked")
+ public int getKeyUsage() {
+ if(mCacheUsage == null) {
+ mCacheUsage = 0;
+ if (mPublicKey.getVersion() >= 4) {
+ for (PGPSignature sig : new IterableIterator<PGPSignature>(mPublicKey.getSignatures())) {
+ if (mPublicKey.isMasterKey() && sig.getKeyID() != mPublicKey.getKeyID()) {
+ continue;
+ }
+
+ PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
+ if (hashed != null) {
+ mCacheUsage |= hashed.getKeyFlags();
+ }
+
+ PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
+ if (unhashed != null) {
+ mCacheUsage |= unhashed.getKeyFlags();
+ }
+ }
+ }
+ }
+ return mCacheUsage;
+ }
+
+ public boolean canAuthenticate() {
+ return mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.AUTHENTICATION) != 0;
+ }
+
+ public boolean canCertify() {
+ return mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.CERTIFY_OTHER) != 0;
+ }
+
+ public boolean canEncrypt() {
+ if (!mPublicKey.isEncryptionKey()) {
+ return false;
+ }
+
+ // special cases
+ if (mPublicKey.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) {
+ return true;
+ }
+
+ if (mPublicKey.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) {
+ return true;
+ }
+
+ return mPublicKey.getVersion() <= 3 ||
+ (getKeyUsage() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0;
+
+ }
+
+ public boolean canSign() {
+ // special case
+ if (mPublicKey.getAlgorithm() == PGPPublicKey.RSA_SIGN) {
+ return true;
+ }
+
+ return mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.SIGN_DATA) != 0;
+ }
+
+ public byte[] getFingerprint() {
+ return mPublicKey.getFingerprint();
+ }
+
+ // Note that this method has package visibility - no access outside the pgp package!
+ PGPPublicKey getPublicKey() {
+ return mPublicKey;
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java
new file mode 100644
index 000000000..82224c6cf
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java
@@ -0,0 +1,26 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.openpgp.PGPSecretKey;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class UncachedSecretKey extends UncachedPublicKey {
+
+ final PGPSecretKey mSecretKey;
+
+ public UncachedSecretKey(PGPSecretKey secretKey) {
+ super(secretKey.getPublicKey());
+ mSecretKey = secretKey;
+ }
+
+ @Deprecated
+ public PGPSecretKey getSecretKeyExternal() {
+ return mSecretKey;
+ }
+
+ public void encodeSecretKey(OutputStream os) throws IOException {
+ mSecretKey.encode(os);
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java
new file mode 100644
index 000000000..bda9ebbcf
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java
@@ -0,0 +1,19 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.openpgp.PGPSecretKeyRing;
+
+public class UncachedSecretKeyRing {
+
+ final PGPSecretKeyRing mSecretRing;
+
+ UncachedSecretKeyRing(PGPSecretKeyRing secretRing) {
+ mSecretRing = secretRing;
+ }
+
+ // Breaking the pattern here, for key import!
+ // TODO reduce this from public to default visibility!
+ public PGPSecretKeyRing getSecretKeyRing() {
+ return mSecretRing;
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
new file mode 100644
index 000000000..94eb91420
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
@@ -0,0 +1,81 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.openpgp.PGPKeyRing;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+
+public abstract class WrappedKeyRing extends KeyRing {
+
+ private final boolean mHasAnySecret;
+ private final int mVerified;
+
+ WrappedKeyRing(boolean hasAnySecret, int verified) {
+ mHasAnySecret = hasAnySecret;
+ mVerified = verified;
+ }
+
+ public long getMasterKeyId() {
+ return getRing().getPublicKey().getKeyID();
+ }
+
+ public boolean hasAnySecret() {
+ return mHasAnySecret;
+ }
+
+ public int getVerified() {
+ return mVerified;
+ }
+
+ public String getPrimaryUserId() throws PgpGeneralException {
+ return (String) getRing().getPublicKey().getUserIDs().next();
+ };
+
+ public boolean isRevoked() throws PgpGeneralException {
+ // Is the master key revoked?
+ return getRing().getPublicKey().isRevoked();
+ }
+
+ public boolean canCertify() throws PgpGeneralException {
+ return getRing().getPublicKey().isEncryptionKey();
+ }
+
+ public long getEncryptId() throws PgpGeneralException {
+ for(PGPPublicKey key : new IterableIterator<PGPPublicKey>(getRing().getPublicKeys())) {
+ if(PgpKeyHelper.isEncryptionKey(key)) {
+ return key.getKeyID();
+ }
+ }
+ throw new PgpGeneralException("No valid encryption key found!");
+ }
+
+ public boolean hasEncrypt() throws PgpGeneralException {
+ try {
+ getEncryptId();
+ return true;
+ } catch(PgpGeneralException e) {
+ return false;
+ }
+ }
+
+ public long getSignId() throws PgpGeneralException {
+ for(PGPPublicKey key : new IterableIterator<PGPPublicKey>(getRing().getPublicKeys())) {
+ if(PgpKeyHelper.isSigningKey(key)) {
+ return key.getKeyID();
+ }
+ }
+ throw new PgpGeneralException("No valid signing key found!");
+ }
+
+ public boolean hasSign() throws PgpGeneralException {
+ try {
+ getSignId();
+ return true;
+ } catch (PgpGeneralException e) {
+ return false;
+ }
+ }
+
+ abstract PGPKeyRing getRing();
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java
new file mode 100644
index 000000000..72352a451
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java
@@ -0,0 +1,62 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPOnePassSignature;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+
+import java.security.SignatureException;
+
+public class WrappedPublicKey extends UncachedPublicKey {
+
+ // this is the parent key ring
+ final KeyRing mRing;
+
+ WrappedPublicKey(KeyRing ring, PGPPublicKey key) {
+ super(key);
+ mRing = ring;
+ }
+
+ public IterableIterator<String> getUserIds() {
+ return new IterableIterator<String>(mPublicKey.getUserIDs());
+ }
+
+ public KeyRing getKeyRing() {
+ return mRing;
+ }
+
+ JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() {
+ return new JcePublicKeyKeyEncryptionMethodGenerator(mPublicKey);
+ }
+
+ public void initSignature(PGPSignature sig) throws PGPException {
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ sig.init(contentVerifierBuilderProvider, mPublicKey);
+ }
+
+ public void initSignature(PGPOnePassSignature sig) throws PGPException {
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ sig.init(contentVerifierBuilderProvider, mPublicKey);
+ }
+
+ /** Verify a signature for this pubkey, after it has been initialized by the signer using
+ * initSignature(). This method should probably move into a wrapped PGPSignature class
+ * at some point.
+ */
+ public boolean verifySignature(PGPSignature sig, String uid) throws PGPException {
+ try {
+ return sig.verifyCertification(uid, mPublicKey);
+ } catch (SignatureException e) {
+ throw new PGPException("Error!", e);
+ }
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java
new file mode 100644
index 000000000..624382165
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java
@@ -0,0 +1,179 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.bcpg.ArmoredOutputStream;
+import org.spongycastle.bcpg.SignatureSubpacketTags;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureList;
+import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+
+import java.io.IOException;
+import java.security.SignatureException;
+import java.util.Arrays;
+import java.util.Iterator;
+
+public class WrappedPublicKeyRing extends WrappedKeyRing {
+
+ private PGPPublicKeyRing mRing;
+ private final byte[] mPubKey;
+
+ public WrappedPublicKeyRing(byte[] blob, boolean hasAnySecret, int verified) {
+ super(hasAnySecret, verified);
+ mPubKey = blob;
+ }
+
+ PGPPublicKeyRing getRing() {
+ if(mRing == null) {
+ mRing = (PGPPublicKeyRing) PgpConversionHelper.BytesToPGPKeyRing(mPubKey);
+ }
+ return mRing;
+ }
+
+ public void encode(ArmoredOutputStream stream) throws IOException {
+ getRing().encode(stream);
+ }
+
+ public WrappedPublicKey getSubkey() {
+ return new WrappedPublicKey(this, getRing().getPublicKey());
+ }
+
+ public WrappedPublicKey getSubkey(long id) {
+ return new WrappedPublicKey(this, getRing().getPublicKey(id));
+ }
+
+ /** Getter that returns the subkey that should be used for signing. */
+ WrappedPublicKey getEncryptionSubKey() throws PgpGeneralException {
+ PGPPublicKey key = getRing().getPublicKey(getEncryptId());
+ if(key != null) {
+ WrappedPublicKey cKey = new WrappedPublicKey(this, key);
+ if(!cKey.canEncrypt()) {
+ throw new PgpGeneralException("key error");
+ }
+ return cKey;
+ }
+ // TODO handle with proper exception
+ throw new PgpGeneralException("no encryption key available");
+ }
+
+ public boolean verifySubkeyBinding(WrappedPublicKey cachedSubkey) {
+ boolean validSubkeyBinding = false;
+ boolean validTempSubkeyBinding = false;
+ boolean validPrimaryKeyBinding = false;
+
+ PGPPublicKey masterKey = getRing().getPublicKey();
+ PGPPublicKey subKey = cachedSubkey.getPublicKey();
+
+ // Is this the master key? Match automatically, then.
+ if(Arrays.equals(masterKey.getFingerprint(), subKey.getFingerprint())) {
+ return true;
+ }
+
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ Iterator<PGPSignature> itr = subKey.getSignatures();
+
+ while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong?
+ //gpg has an invalid subkey binding error on key import I think, but doesn't shout
+ //about keys without subkey signing. Can't get it to import a slightly broken one
+ //either, so we will err on bad subkey binding here.
+ PGPSignature sig = itr.next();
+ if (sig.getKeyID() == masterKey.getKeyID() &&
+ sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
+ //check and if ok, check primary key binding.
+ try {
+ sig.init(contentVerifierBuilderProvider, masterKey);
+ validTempSubkeyBinding = sig.verifyCertification(masterKey, subKey);
+ } catch (PGPException e) {
+ continue;
+ } catch (SignatureException e) {
+ continue;
+ }
+
+ if (validTempSubkeyBinding) {
+ validSubkeyBinding = true;
+ }
+ if (validTempSubkeyBinding) {
+ validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(),
+ masterKey, subKey);
+ if (validPrimaryKeyBinding) {
+ break;
+ }
+ validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(),
+ masterKey, subKey);
+ if (validPrimaryKeyBinding) {
+ break;
+ }
+ }
+ }
+ }
+ return validSubkeyBinding && validPrimaryKeyBinding;
+
+ }
+
+ static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts,
+ PGPPublicKey masterPublicKey,
+ PGPPublicKey signingPublicKey) {
+ boolean validPrimaryKeyBinding = false;
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ PGPSignatureList eSigList;
+
+ if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
+ try {
+ eSigList = pkts.getEmbeddedSignatures();
+ } catch (IOException e) {
+ return false;
+ } catch (PGPException e) {
+ return false;
+ }
+ for (int j = 0; j < eSigList.size(); ++j) {
+ PGPSignature emSig = eSigList.get(j);
+ if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
+ try {
+ emSig.init(contentVerifierBuilderProvider, signingPublicKey);
+ validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey);
+ if (validPrimaryKeyBinding) {
+ break;
+ }
+ } catch (PGPException e) {
+ continue;
+ } catch (SignatureException e) {
+ continue;
+ }
+ }
+ }
+ }
+
+ return validPrimaryKeyBinding;
+ }
+
+ public IterableIterator<WrappedPublicKey> iterator() {
+ final Iterator<PGPPublicKey> it = getRing().getPublicKeys();
+ return new IterableIterator<WrappedPublicKey>(new Iterator<WrappedPublicKey>() {
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public WrappedPublicKey next() {
+ return new WrappedPublicKey(WrappedPublicKeyRing.this, it.next());
+ }
+
+ @Override
+ public void remove() {
+ it.remove();
+ }
+ });
+ }
+
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java
new file mode 100644
index 000000000..a03e10098
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java
@@ -0,0 +1,189 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPPrivateKey;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureGenerator;
+import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
+import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.PGPUtil;
+import org.spongycastle.openpgp.PGPV3SignatureGenerator;
+import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SignatureException;
+import java.util.List;
+
+public class WrappedSecretKey extends WrappedPublicKey {
+
+ private final PGPSecretKey mSecretKey;
+ private PGPPrivateKey mPrivateKey = null;
+
+ WrappedSecretKey(WrappedSecretKeyRing 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 boolean unlock(String passphrase) throws PgpGeneralException {
+ try {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
+ mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor);
+ } catch (PGPException e) {
+ return false;
+ }
+ if(mPrivateKey == null) {
+ throw new PgpGeneralException("error extracting key");
+ }
+ return true;
+ }
+
+ public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext)
+ throws PgpGeneralException {
+ if(mPrivateKey == null) {
+ throw new PrivateKeyNotUnlockedException();
+ }
+
+ // content signer based on signing key algorithm and chosen hash algorithm
+ JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
+ mSecretKey.getPublicKey().getAlgorithm(), hashAlgo)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ int signatureType;
+ if (cleartext) {
+ // for sign-only ascii text
+ signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
+ } else {
+ signatureType = PGPSignature.BINARY_DOCUMENT;
+ }
+
+ try {
+ PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ signatureGenerator.init(signatureType, mPrivateKey);
+
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ spGen.setSignerUserID(false, mRing.getPrimaryUserId());
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ return signatureGenerator;
+ } catch(PGPException e) {
+ throw new PgpGeneralException("Error initializing signature!", e);
+ }
+ }
+
+ public PGPV3SignatureGenerator getV3SignatureGenerator(int hashAlgo, boolean cleartext)
+ throws PgpGeneralException {
+ if(mPrivateKey == null) {
+ throw new PrivateKeyNotUnlockedException();
+ }
+
+ // content signer based on signing key algorithm and chosen hash algorithm
+ JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
+ mSecretKey.getPublicKey().getAlgorithm(), hashAlgo)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ int signatureType;
+ if (cleartext) {
+ // for sign-only ascii text
+ signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
+ } else {
+ signatureType = PGPSignature.BINARY_DOCUMENT;
+ }
+
+ try {
+ PGPV3SignatureGenerator signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
+ signatureV3Generator.init(signatureType, mPrivateKey);
+ return signatureV3Generator;
+ } catch(PGPException e) {
+ throw new PgpGeneralException("Error initializing signature!", e);
+ }
+ }
+
+ public PublicKeyDataDecryptorFactory getDecryptorFactory() {
+ if(mPrivateKey == null) {
+ throw new PrivateKeyNotUnlockedException();
+ }
+ return new JcePublicKeyDataDecryptorFactoryBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey);
+ }
+
+ /**
+ * Certify the given pubkeyid with the given masterkeyid.
+ *
+ * @param publicKeyRing Keyring to add certification to.
+ * @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)
+ throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException,
+ PGPException, SignatureException {
+
+ if(mPrivateKey == null) {
+ throw new PrivateKeyNotUnlockedException();
+ }
+
+ // create a signatureGenerator from the supplied masterKeyId and passphrase
+ PGPSignatureGenerator signatureGenerator;
+ {
+ // TODO: SHA256 fixed?
+ JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
+ mSecretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
+ }
+
+ { // supply signatureGenerator with a SubpacketVector
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ PGPSignatureSubpacketVector packetVector = spGen.generate();
+ signatureGenerator.setHashedSubpackets(packetVector);
+ }
+
+ // get the master subkey (which we certify for)
+ PGPPublicKey publicKey = publicKeyRing.getSubkey().getPublicKey();
+
+ // fetch public key ring, add the certification and return it
+ for (String userId : new IterableIterator<String>(userIds.iterator())) {
+ PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey);
+ publicKey = PGPPublicKey.addCertification(publicKey, userId, sig);
+ }
+
+ PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey);
+
+ return new UncachedKeyRing(ring);
+ }
+
+ static class PrivateKeyNotUnlockedException extends RuntimeException {
+ // this exception is a programming error which happens when an operation which requires
+ // the private key is called without a previous call to unlock()
+ }
+
+ public UncachedSecretKey getUncached() {
+ return new UncachedSecretKey(mSecretKey);
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
new file mode 100644
index 000000000..c94b7dfba
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
@@ -0,0 +1,123 @@
+package org.sufficientlysecure.keychain.pgp;
+
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPPrivateKey;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
+import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+
+import java.io.IOException;
+import java.security.NoSuchProviderException;
+import java.util.Iterator;
+
+public class WrappedSecretKeyRing extends WrappedKeyRing {
+
+ private PGPSecretKeyRing mRing;
+
+ public WrappedSecretKeyRing(byte[] blob, boolean isRevoked, int verified)
+ {
+ super(isRevoked, verified);
+ mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob);
+ }
+
+ PGPSecretKeyRing getRing() {
+ return mRing;
+ }
+
+ public WrappedSecretKey getSubKey() {
+ return new WrappedSecretKey(this, mRing.getSecretKey());
+ }
+
+ public WrappedSecretKey getSubKey(long id) {
+ return new WrappedSecretKey(this, mRing.getSecretKey(id));
+ }
+
+ /** Getter that returns the subkey that should be used for signing. */
+ WrappedSecretKey getSigningSubKey() throws PgpGeneralException {
+ PGPSecretKey key = mRing.getSecretKey(getSignId());
+ if(key != null) {
+ WrappedSecretKey cKey = new WrappedSecretKey(this, key);
+ if(!cKey.canSign()) {
+ throw new PgpGeneralException("key error");
+ }
+ return cKey;
+ }
+ // TODO handle with proper exception
+ throw new PgpGeneralException("no signing key available");
+ }
+
+ public boolean hasPassphrase() {
+ PGPSecretKey secretKey = null;
+ boolean foundValidKey = false;
+ for (Iterator keys = mRing.getSecretKeys(); keys.hasNext(); ) {
+ secretKey = (PGPSecretKey) keys.next();
+ if (!secretKey.isPrivateKeyEmpty()) {
+ foundValidKey = true;
+ break;
+ }
+ }
+ if(!foundValidKey) {
+ return false;
+ }
+
+ try {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider("SC").build("".toCharArray());
+ PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor);
+ return testKey == null;
+ } catch(PGPException e) {
+ // this means the crc check failed -> passphrase required
+ return true;
+ }
+ }
+
+ public UncachedSecretKeyRing changeSecretKeyPassphrase(String oldPassphrase,
+ String newPassphrase)
+ throws IOException, PGPException, NoSuchProviderException {
+
+ if (oldPassphrase == null) {
+ oldPassphrase = "";
+ }
+ if (newPassphrase == null) {
+ newPassphrase = "";
+ }
+
+ PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword(
+ mRing,
+ new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()),
+ new JcePBESecretKeyEncryptorBuilder(mRing.getSecretKey()
+ .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray()));
+
+ return new UncachedSecretKeyRing(newKeyRing);
+
+ }
+
+ public IterableIterator<WrappedSecretKey> iterator() {
+ final Iterator<PGPSecretKey> it = mRing.getSecretKeys();
+ return new IterableIterator<WrappedSecretKey>(new Iterator<WrappedSecretKey>() {
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public WrappedSecretKey next() {
+ return new WrappedSecretKey(WrappedSecretKeyRing.this, it.next());
+ }
+
+ @Override
+ public void remove() {
+ it.remove();
+ }
+ });
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java
index 37d21eea4..f37a61852 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java
@@ -27,4 +27,7 @@ public class PgpGeneralException extends Exception {
public PgpGeneralException(String message, Throwable cause) {
super(message, cause);
}
+ public PgpGeneralException(Throwable cause) {
+ super(cause);
+ }
}