From b156a057e8c5b715f515725ab051087a86ecd547 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 31 Jul 2014 17:08:33 +0200 Subject: rename Wrapped*Key* to Canonicalized*Key* --- .../keychain/pgp/CanonicalizedKeyRing.java | 114 ++++++++++++ .../keychain/pgp/CanonicalizedPublicKey.java | 39 +++++ .../keychain/pgp/CanonicalizedPublicKeyRing.java | 84 +++++++++ .../keychain/pgp/CanonicalizedSecretKey.java | 192 +++++++++++++++++++++ .../keychain/pgp/CanonicalizedSecretKeyRing.java | 152 ++++++++++++++++ .../sufficientlysecure/keychain/pgp/KeyRing.java | 2 +- .../keychain/pgp/PgpDecryptVerify.java | 18 +- .../keychain/pgp/PgpImportExport.java | 8 +- .../keychain/pgp/PgpKeyOperation.java | 3 +- .../keychain/pgp/PgpSignEncrypt.java | 10 +- .../keychain/pgp/UncachedKeyRing.java | 38 +--- .../keychain/pgp/WrappedKeyRing.java | 120 ------------- .../keychain/pgp/WrappedPublicKey.java | 39 ----- .../keychain/pgp/WrappedPublicKeyRing.java | 81 --------- .../keychain/pgp/WrappedSecretKey.java | 192 --------------------- .../keychain/pgp/WrappedSecretKeyRing.java | 131 -------------- .../keychain/pgp/WrappedSignature.java | 4 +- .../keychain/provider/ProviderHelper.java | 131 +++++++------- .../keychain/remote/OpenPgpService.java | 2 +- .../keychain/service/KeychainIntentService.java | 18 +- .../keychain/service/OperationResultParcel.java | 1 - .../keychain/service/PassphraseCacheService.java | 4 +- .../keychain/ui/EditKeyFragment.java | 7 +- .../keychain/ui/LogDisplayFragment.java | 6 +- .../keychain/ui/ViewCertActivity.java | 10 +- .../ui/dialog/PassphraseDialogFragment.java | 14 +- 26 files changed, 702 insertions(+), 718 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java new file mode 100644 index 000000000..ee0dfefa4 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java @@ -0,0 +1,114 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPKeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.io.IOException; +import java.io.OutputStream; + +/** A generic wrapped PGPKeyRing object. + * + * This class provides implementations for all basic getters which both + * PublicKeyRing and SecretKeyRing have in common. To make the wrapped keyring + * class typesafe in implementing subclasses, the field is stored in the + * implementing class, providing properly typed access through the getRing + * getter method. + * + */ +public abstract class CanonicalizedKeyRing extends KeyRing { + + private final int mVerified; + + CanonicalizedKeyRing(int verified) { + mVerified = verified; + } + + public long getMasterKeyId() { + return getRing().getPublicKey().getKeyID(); + } + + public int getVerified() { + return mVerified; + } + + public String getPrimaryUserId() throws PgpGeneralException { + return getPublicKey().getPrimaryUserId(); + } + + public String getPrimaryUserIdWithFallback() throws PgpGeneralException { + return getPublicKey().getPrimaryUserIdWithFallback(); + } + + 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(CanonicalizedPublicKey key : publicKeyIterator()) { + if(key.canEncrypt()) { + 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(CanonicalizedPublicKey key : publicKeyIterator()) { + if(key.canSign()) { + 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; + } + } + + public void encode(OutputStream stream) throws IOException { + getRing().encode(stream); + } + + /** Returns an UncachedKeyRing which wraps the same data as this ring. This method should + * only be used */ + public UncachedKeyRing getUncachedKeyRing() { + return new UncachedKeyRing(getRing()); + } + + abstract PGPKeyRing getRing(); + + abstract public IterableIterator publicKeyIterator(); + + public CanonicalizedPublicKey getPublicKey() { + return new CanonicalizedPublicKey(this, getRing().getPublicKey()); + } + + public CanonicalizedPublicKey getPublicKey(long id) { + return new CanonicalizedPublicKey(this, getRing().getPublicKey(id)); + } + + public byte[] getEncoded() throws IOException { + return getRing().getEncoded(); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java new file mode 100644 index 000000000..981caad49 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java @@ -0,0 +1,39 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.sufficientlysecure.keychain.util.IterableIterator; + +/** Wrapper for a PGPPublicKey. + * + * The methods implemented in this class are a thin layer over + * UncachedPublicKey. The difference between the two classes is that objects of + * this class can only be obtained from a WrappedKeyRing, and that it stores a + * back reference to its parent as well. A method which works with + * WrappedPublicKey is therefore guaranteed to work on a KeyRing which is + * stored in the database. + * + */ +public class CanonicalizedPublicKey extends UncachedPublicKey { + + // this is the parent key ring + final KeyRing mRing; + + CanonicalizedPublicKey(KeyRing ring, PGPPublicKey key) { + super(key); + mRing = ring; + } + + public IterableIterator getUserIds() { + return new IterableIterator(mPublicKey.getUserIDs()); + } + + public KeyRing getKeyRing() { + return mRing; + } + + JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() { + return new JcePublicKeyKeyEncryptionMethodGenerator(mPublicKey); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java new file mode 100644 index 000000000..70288dceb --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java @@ -0,0 +1,84 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.io.IOException; +import java.util.Iterator; + +public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing { + + private PGPPublicKeyRing mRing; + + CanonicalizedPublicKeyRing(PGPPublicKeyRing ring, int verified) { + super(verified); + mRing = ring; + } + + public CanonicalizedPublicKeyRing(byte[] blob, int verified) { + super(verified); + if(mRing == null) { + // get first object in block + PGPObjectFactory factory = new PGPObjectFactory(blob); + try { + 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) { + throw new RuntimeException("IO Error constructing CanonicalizedPublicKeyRing, should never happen!"); + } + } + } + + PGPPublicKeyRing getRing() { + return mRing; + } + + public void encode(ArmoredOutputStream stream) throws IOException { + getRing().encode(stream); + } + + /** Getter that returns the subkey that should be used for signing. */ + CanonicalizedPublicKey getEncryptionSubKey() throws PgpGeneralException { + PGPPublicKey key = getRing().getPublicKey(getEncryptId()); + if(key != null) { + CanonicalizedPublicKey cKey = new CanonicalizedPublicKey(this, key); + if(!cKey.canEncrypt()) { + throw new PgpGeneralException("key error"); + } + return cKey; + } + throw new PgpGeneralException("no encryption key available"); + } + + public IterableIterator publicKeyIterator() { + @SuppressWarnings("unchecked") + final Iterator it = getRing().getPublicKeys(); + return new IterableIterator(new Iterator() { + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public CanonicalizedPublicKey next() { + return new CanonicalizedPublicKey(CanonicalizedPublicKeyRing.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/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java new file mode 100644 index 000000000..2eb517697 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -0,0 +1,192 @@ +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; + +/** Wrapper for a PGPSecretKey. + * + * This object can only be obtained from a WrappedSecretKeyRing, and stores a + * back reference to its parent. + * + * This class represents known secret keys which are stored in the database. + * All "crypto operations using a known secret key" should be implemented in + * this class, to ensure on type level that these operations are performed on + * properly imported secret keys only. + * + */ +public class CanonicalizedSecretKey extends CanonicalizedPublicKey { + + private final PGPSecretKey mSecretKey; + private PGPPrivateKey mPrivateKey = null; + + CanonicalizedSecretKey(CanonicalizedSecretKeyRing ring, PGPSecretKey key) { + super(ring, key.getPublicKey()); + mSecretKey = key; + } + + public CanonicalizedSecretKeyRing getRing() { + return (CanonicalizedSecretKeyRing) mRing; + } + + 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.getPrimaryUserIdWithFallback()); + 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(CanonicalizedPublicKeyRing publicKeyRing, List 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.getPublicKey().getPublicKey(); + + // fetch public key ring, add the certification and return it + for (String userId : new IterableIterator(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/CanonicalizedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java new file mode 100644 index 000000000..e48fe5020 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java @@ -0,0 +1,152 @@ +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; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +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.HashSet; +import java.util.Iterator; + +public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { + + private PGPSecretKeyRing mRing; + + CanonicalizedSecretKeyRing(PGPSecretKeyRing ring, int verified) { + super(verified); + mRing = ring; + } + + public CanonicalizedSecretKeyRing(byte[] blob, boolean isRevoked, int verified) + { + super(verified); + PGPObjectFactory factory = new PGPObjectFactory(blob); + PGPKeyRing keyRing = null; + try { + if ((keyRing = (PGPKeyRing) factory.nextObject()) == null) { + Log.e(Constants.TAG, "No keys given!"); + } + } catch (IOException e) { + Log.e(Constants.TAG, "Error while converting to PGPKeyRing!", e); + } + + mRing = (PGPSecretKeyRing) keyRing; + } + + PGPSecretKeyRing getRing() { + return mRing; + } + + public CanonicalizedSecretKey getSecretKey() { + return new CanonicalizedSecretKey(this, mRing.getSecretKey()); + } + + public CanonicalizedSecretKey getSecretKey(long id) { + return new CanonicalizedSecretKey(this, mRing.getSecretKey(id)); + } + + public HashSet getAvailableSubkeys() { + HashSet result = new HashSet(); + // then, mark exactly the keys we have available + for (PGPSecretKey sub : new IterableIterator(getRing().getSecretKeys())) { + S2K s2k = sub.getS2K(); + // Set to 1, except if the encryption type is GNU_DUMMY_S2K + if(s2k == null || s2k.getType() != S2K.GNU_DUMMY_S2K) { + result.add(sub.getKeyID()); + } + } + return result; + } + + /** Getter that returns the subkey that should be used for signing. */ + CanonicalizedSecretKey getSigningSubKey() throws PgpGeneralException { + PGPSecretKey key = mRing.getSecretKey(getSignId()); + if(key != null) { + CanonicalizedSecretKey cKey = new CanonicalizedSecretKey(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 IterableIterator secretKeyIterator() { + final Iterator it = mRing.getSecretKeys(); + return new IterableIterator(new Iterator() { + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public CanonicalizedSecretKey next() { + return new CanonicalizedSecretKey(CanonicalizedSecretKeyRing.this, it.next()); + } + + @Override + public void remove() { + it.remove(); + } + }); + } + + public IterableIterator publicKeyIterator() { + final Iterator it = getRing().getPublicKeys(); + return new IterableIterator(new Iterator() { + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public CanonicalizedPublicKey next() { + return new CanonicalizedPublicKey(CanonicalizedSecretKeyRing.this, it.next()); + } + + @Override + public void remove() { + it.remove(); + } + }); + } + +} 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 9d334d9bd..846b00ef2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -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 { @@ -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 e9d7e5958..fef15db1e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -46,7 +46,6 @@ 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; @@ -241,7 +240,7 @@ public class PgpKeyOperation { * are changed by adding new certificates, which implicitly override older certificates. * */ - public EditKeyResult modifySecretKeyRing(WrappedSecretKeyRing wsKR, SaveKeyringParcel saveParcel, + public EditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel, String passphrase) { OperationLog log = new OperationLog(); 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 4cb92c368..f0403e625 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -266,11 +266,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(); } @@ -316,9 +316,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 0e59b7fdb..d8a2532f3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -49,7 +49,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 +59,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() { @@ -105,10 +97,6 @@ public class UncachedKeyRing { return mIsSecret; } - public boolean isCanonicalized() { - return mIsCanonicalized; - } - public byte[] getEncoded() throws IOException { return mRing.getEncoded(); } @@ -164,25 +152,6 @@ public class UncachedKeyRing { aos.close(); } - public HashSet 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 result = new HashSet(); - // then, mark exactly the keys we have available - for (PGPSecretKey sub : new IterableIterator( - ((PGPSecretKeyRing) mRing).getSecretKeys())) { - S2K s2k = sub.getS2K(); - // Set to 1, except if the encryption type is GNU_DUMMY_S2K - if(s2k == null || s2k.getType() != S2K.GNU_DUMMY_S2K) { - result.add(sub.getKeyID()); - } - } - return result; - } - /** "Canonicalizes" a public key, removing inconsistencies in the process. This variant can be * applied to public keyrings only. * @@ -207,7 +176,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())); @@ -629,7 +598,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 diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java deleted file mode 100644 index a054255dc..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.openpgp.PGPKeyRing; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.util.IterableIterator; - -import java.io.IOException; -import java.io.OutputStream; - -/** A generic wrapped PGPKeyRing object. - * - * This class provides implementations for all basic getters which both - * PublicKeyRing and SecretKeyRing have in common. To make the wrapped keyring - * class typesafe in implementing subclasses, the field is stored in the - * implementing class, providing properly typed access through the getRing - * getter method. - * - */ -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 getPublicKey().getPrimaryUserId(); - } - - public String getPrimaryUserIdWithFallback() throws PgpGeneralException { - return getPublicKey().getPrimaryUserIdWithFallback(); - } - - 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(WrappedPublicKey key : publicKeyIterator()) { - if(key.canEncrypt()) { - 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(WrappedPublicKey key : publicKeyIterator()) { - if(key.canSign()) { - 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; - } - } - - public void encode(OutputStream stream) throws IOException { - getRing().encode(stream); - } - - /** Returns an UncachedKeyRing which wraps the same data as this ring. This method should - * only be used */ - public UncachedKeyRing getUncachedKeyRing() { - return new UncachedKeyRing(getRing()); - } - - abstract PGPKeyRing getRing(); - - abstract public IterableIterator publicKeyIterator(); - - public WrappedPublicKey getPublicKey() { - return new WrappedPublicKey(this, getRing().getPublicKey()); - } - - public WrappedPublicKey getPublicKey(long id) { - return new WrappedPublicKey(this, getRing().getPublicKey(id)); - } - - public byte[] getEncoded() throws IOException { - return getRing().getEncoded(); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java deleted file mode 100644 index 69a4fbdee..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; -import org.sufficientlysecure.keychain.util.IterableIterator; - -/** Wrapper for a PGPPublicKey. - * - * The methods implemented in this class are a thin layer over - * UncachedPublicKey. The difference between the two classes is that objects of - * this class can only be obtained from a WrappedKeyRing, and that it stores a - * back reference to its parent as well. A method which works with - * WrappedPublicKey is therefore guaranteed to work on a KeyRing which is - * stored in the database. - * - */ -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 getUserIds() { - return new IterableIterator(mPublicKey.getUserIDs()); - } - - public KeyRing getKeyRing() { - return mRing; - } - - JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() { - return new JcePublicKeyKeyEncryptionMethodGenerator(mPublicKey); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java deleted file mode 100644 index bb1f7d778..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.bcpg.ArmoredOutputStream; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.util.IterableIterator; - -import java.io.IOException; -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) { - // get first object in block - PGPObjectFactory factory = new PGPObjectFactory(mPubKey); - try { - Object obj = factory.nextObject(); - if (! (obj instanceof PGPPublicKeyRing)) { - throw new RuntimeException("Error constructing WrappedPublicKeyRing, should never happen!"); - } - mRing = (PGPPublicKeyRing) obj; - if (factory.nextObject() != null) { - throw new RuntimeException("Encountered trailing data after keyring, should never happen!"); - } - } catch (IOException e) { - throw new RuntimeException("IO Error constructing WrappedPublicKeyRing, should never happen!"); - } - } - return mRing; - } - - public void encode(ArmoredOutputStream stream) throws IOException { - getRing().encode(stream); - } - - /** 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; - } - throw new PgpGeneralException("no encryption key available"); - } - - public IterableIterator publicKeyIterator() { - @SuppressWarnings("unchecked") - final Iterator it = getRing().getPublicKeys(); - return new IterableIterator(new Iterator() { - @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 deleted file mode 100644 index f0485d801..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java +++ /dev/null @@ -1,192 +0,0 @@ -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; - -/** Wrapper for a PGPSecretKey. - * - * This object can only be obtained from a WrappedSecretKeyRing, and stores a - * back reference to its parent. - * - * This class represents known secret keys which are stored in the database. - * All "crypto operations using a known secret key" should be implemented in - * this class, to ensure on type level that these operations are performed on - * properly imported secret keys only. - * - */ -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; - } - - 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.getPrimaryUserIdWithFallback()); - 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 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.getPublicKey().getPublicKey(); - - // fetch public key ring, add the certification and return it - for (String userId : new IterableIterator(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 deleted file mode 100644 index 5cb24cf88..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -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.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -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 WrappedSecretKeyRing extends WrappedKeyRing { - - private PGPSecretKeyRing mRing; - - public WrappedSecretKeyRing(byte[] blob, boolean isRevoked, int verified) - { - super(isRevoked, verified); - PGPObjectFactory factory = new PGPObjectFactory(blob); - PGPKeyRing keyRing = null; - try { - if ((keyRing = (PGPKeyRing) factory.nextObject()) == null) { - Log.e(Constants.TAG, "No keys given!"); - } - } catch (IOException e) { - Log.e(Constants.TAG, "Error while converting to PGPKeyRing!", e); - } - - mRing = (PGPSecretKeyRing) keyRing; - } - - PGPSecretKeyRing getRing() { - return mRing; - } - - public WrappedSecretKey getSecretKey() { - return new WrappedSecretKey(this, mRing.getSecretKey()); - } - - public WrappedSecretKey getSecretKey(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 IterableIterator secretKeyIterator() { - final Iterator it = mRing.getSecretKeys(); - return new IterableIterator(new Iterator() { - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public WrappedSecretKey next() { - return new WrappedSecretKey(WrappedSecretKeyRing.this, it.next()); - } - - @Override - public void remove() { - it.remove(); - } - }); - } - - public IterableIterator publicKeyIterator() { - final Iterator it = getRing().getPublicKeys(); - return new IterableIterator(new Iterator() { - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public WrappedPublicKey next() { - return new WrappedPublicKey(WrappedSecretKeyRing.this, it.next()); - } - - @Override - public void remove() { - it.remove(); - } - }); - } - -} 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 28e4c51d6..07fb4fb9e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -113,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()); } @@ -191,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); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 998cf25c3..9b35903f6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -28,10 +28,12 @@ import android.os.RemoteException; import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.NullProgressable; import org.sufficientlysecure.keychain.pgp.Progressable; -import org.sufficientlysecure.keychain.pgp.WrappedPublicKey; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType; import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel; import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog; @@ -39,8 +41,6 @@ import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; -import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; @@ -180,7 +180,7 @@ public class ProviderHelper { return getGenericData(KeyRings.buildUnifiedKeyRingUri(masterKeyId), proj, types); } - private LongSparseArray getTrustedMasterKeys() { + private LongSparseArray getTrustedMasterKeys() { Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] { KeyRings.MASTER_KEY_ID, // we pick from cache only information that is not easily available from keyrings @@ -190,16 +190,15 @@ public class ProviderHelper { }, KeyRings.HAS_ANY_SECRET + " = 1", null, null); try { - LongSparseArray result = new LongSparseArray(); + LongSparseArray result = new LongSparseArray(); if (cursor != null && cursor.moveToFirst()) do { long masterKeyId = cursor.getLong(0); - boolean hasAnySecret = cursor.getInt(1) > 0; int verified = cursor.getInt(2); byte[] blob = cursor.getBlob(3); if (blob != null) { result.put(masterKeyId, - new WrappedPublicKeyRing(blob, hasAnySecret, verified).getPublicKey()); + new CanonicalizedPublicKeyRing(blob, verified).getPublicKey()); } } while (cursor.moveToNext()); @@ -217,23 +216,23 @@ public class ProviderHelper { return new CachedPublicKeyRing(this, queryUri); } - public WrappedPublicKeyRing getWrappedPublicKeyRing(long id) throws NotFoundException { - return (WrappedPublicKeyRing) getWrappedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), false); + public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long id) throws NotFoundException { + return (CanonicalizedPublicKeyRing) getCanonicalizedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), false); } - public WrappedPublicKeyRing getWrappedPublicKeyRing(Uri queryUri) throws NotFoundException { - return (WrappedPublicKeyRing) getWrappedKeyRing(queryUri, false); + public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(Uri queryUri) throws NotFoundException { + return (CanonicalizedPublicKeyRing) getCanonicalizedKeyRing(queryUri, false); } - public WrappedSecretKeyRing getWrappedSecretKeyRing(long id) throws NotFoundException { - return (WrappedSecretKeyRing) getWrappedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), true); + public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long id) throws NotFoundException { + return (CanonicalizedSecretKeyRing) getCanonicalizedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), true); } - public WrappedSecretKeyRing getWrappedSecretKeyRing(Uri queryUri) throws NotFoundException { - return (WrappedSecretKeyRing) getWrappedKeyRing(queryUri, true); + public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(Uri queryUri) throws NotFoundException { + return (CanonicalizedSecretKeyRing) getCanonicalizedKeyRing(queryUri, true); } - private KeyRing getWrappedKeyRing(Uri queryUri, boolean secret) throws NotFoundException { + private KeyRing getCanonicalizedKeyRing(Uri queryUri, boolean secret) throws NotFoundException { Cursor cursor = mContentResolver.query(queryUri, new String[]{ // we pick from cache only information that is not easily available from keyrings @@ -252,8 +251,8 @@ public class ProviderHelper { throw new NotFoundException("Secret key not available!"); } return secret - ? new WrappedSecretKeyRing(blob, true, verified) - : new WrappedPublicKeyRing(blob, hasAnySecret, verified); + ? new CanonicalizedSecretKeyRing(blob, true, verified) + : new CanonicalizedPublicKeyRing(blob, verified); } else { throw new NotFoundException("Key not found!"); } @@ -271,16 +270,8 @@ public class ProviderHelper { * and need to be saved externally to be preserved past the operation. */ @SuppressWarnings("unchecked") - private int internalSavePublicKeyRing(UncachedKeyRing keyRing, - Progressable progress, boolean selfCertsAreTrusted) { - if (keyRing.isSecret()) { - log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET); - return SaveKeyringResult.RESULT_ERROR; - } - if (!keyRing.isCanonicalized()) { - log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET); - return SaveKeyringResult.RESULT_ERROR; - } + private int saveCanonicalizedPublicKeyRing(CanonicalizedPublicKeyRing keyRing, + Progressable progress, boolean selfCertsAreTrusted) { // start with ok result int result = SaveKeyringResult.SAVED_PUBLIC; @@ -318,7 +309,7 @@ public class ProviderHelper { { // insert subkeys Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId)); int rank = 0; - for (UncachedPublicKey key : new IterableIterator(keyRing.getPublicKeys())) { + for (CanonicalizedPublicKey key : keyRing.publicKeyIterator()) { long keyId = key.getKeyId(); log(LogLevel.DEBUG, keyId == masterKeyId ? LogType.MSG_IP_MASTER : LogType.MSG_IP_SUBKEY, PgpKeyHelper.convertKeyIdToHex(keyId) @@ -401,7 +392,7 @@ public class ProviderHelper { mIndent -= 1; // get a list of owned secret keys, for verification filtering - LongSparseArray trustedKeys = getTrustedMasterKeys(); + LongSparseArray trustedKeys = getTrustedMasterKeys(); // classify and order user ids. primary are moved to the front, revoked to the back, // otherwise the order in the keyfile is preserved. @@ -445,7 +436,7 @@ public class ProviderHelper { // verify signatures from known private keys if (trustedKeys.indexOfKey(certId) >= 0) { - WrappedPublicKey trustedKey = trustedKeys.get(certId); + CanonicalizedPublicKey trustedKey = trustedKeys.get(certId); cert.init(trustedKey); if (cert.verifySignature(masterKey, userId)) { item.trustedCerts.add(cert); @@ -559,17 +550,7 @@ public class ProviderHelper { /** Saves an UncachedKeyRing of the secret variant into the db. * This method will fail if no corresponding public keyring is in the database! */ - private int internalSaveSecretKeyRing(UncachedKeyRing keyRing) { - - if (!keyRing.isSecret()) { - log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC); - return SaveKeyringResult.RESULT_ERROR; - } - - if (!keyRing.isCanonicalized()) { - log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_UNCANON); - return SaveKeyringResult.RESULT_ERROR; - } + private int saveCanonicalizedSecretKeyRing(CanonicalizedSecretKeyRing keyRing) { long masterKeyId = keyRing.getMasterKeyId(); log(LogLevel.START, LogType.MSG_IS, PgpKeyHelper.convertKeyIdToHex(masterKeyId)); @@ -610,8 +591,7 @@ public class ProviderHelper { log(LogLevel.INFO, LogType.MSG_IS_IMPORTING_SUBKEYS); mIndent += 1; Set available = keyRing.getAvailableSubkeys(); - for (UncachedPublicKey sub : - new IterableIterator(keyRing.getPublicKeys())) { + for (UncachedPublicKey sub : keyRing.publicKeyIterator()) { long id = sub.getKeyId(); if (available.contains(id)) { int upd = mContentResolver.update(uri, values, Keys.KEY_ID + " = ?", @@ -662,9 +642,16 @@ public class ProviderHelper { log(LogLevel.START, LogType.MSG_IP, PgpKeyHelper.convertKeyIdToHex(masterKeyId)); mIndent += 1; + if (publicRing.isSecret()) { + log(LogLevel.ERROR, LogType.MSG_IP_BAD_TYPE_SECRET); + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); + } + + CanonicalizedPublicKeyRing canPublicRing; + // If there is an old keyring, merge it try { - UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncachedKeyRing(); + UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing(); // Merge data from new public ring into the old one publicRing = oldPublicRing.merge(publicRing, mLog, mIndent); @@ -675,8 +662,8 @@ public class ProviderHelper { } // Canonicalize this keyring, to assert a number of assumptions made about it. - publicRing = publicRing.canonicalize(mLog, mIndent); - if (publicRing == null) { + canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent); + if (canPublicRing == null) { return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); } @@ -690,39 +677,40 @@ public class ProviderHelper { // Not an issue, just means we are dealing with a new keyring. // Canonicalize this keyring, to assert a number of assumptions made about it. - publicRing = publicRing.canonicalize(mLog, mIndent); - if (publicRing == null) { + canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent); + if (canPublicRing == null) { return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); } } // If there is a secret key, merge new data (if any) and save the key for later - UncachedKeyRing secretRing; + CanonicalizedSecretKeyRing canSecretRing; try { - secretRing = getWrappedSecretKeyRing(publicRing.getMasterKeyId()).getUncachedKeyRing(); + UncachedKeyRing secretRing = getCanonicalizedSecretKeyRing(publicRing.getMasterKeyId()).getUncachedKeyRing(); // Merge data from new public ring into secret one secretRing = secretRing.merge(publicRing, mLog, mIndent); if (secretRing == null) { return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); } - secretRing = secretRing.canonicalize(mLog, mIndent); - if (secretRing == null) { + // This has always been a secret key ring, this is a safe cast + canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); + if (canSecretRing == null) { return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); } } catch (NotFoundException e) { // No secret key available (this is what happens most of the time) - secretRing = null; + canSecretRing = null; } - int result = internalSavePublicKeyRing(publicRing, progress, secretRing != null); + int result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, canSecretRing != null); // Save the saved keyring (if any) - if (secretRing != null) { + if (canSecretRing != null) { progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100); - int secretResult = internalSaveSecretKeyRing(secretRing); + int secretResult = saveCanonicalizedSecretKeyRing(canSecretRing); if ((secretResult & SaveKeyringResult.RESULT_ERROR) != SaveKeyringResult.RESULT_ERROR) { result |= SaveKeyringResult.SAVED_SECRET; } @@ -746,9 +734,16 @@ public class ProviderHelper { log(LogLevel.START, LogType.MSG_IS, PgpKeyHelper.convertKeyIdToHex(masterKeyId)); mIndent += 1; + if ( ! secretRing.isSecret()) { + log(LogLevel.ERROR, LogType.MSG_IS_BAD_TYPE_PUBLIC); + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); + } + + CanonicalizedSecretKeyRing canSecretRing; + // If there is an old secret key, merge it. try { - UncachedKeyRing oldSecretRing = getWrappedSecretKeyRing(masterKeyId).getUncachedKeyRing(); + UncachedKeyRing oldSecretRing = getCanonicalizedSecretKeyRing(masterKeyId).getUncachedKeyRing(); // Merge data from new secret ring into old one secretRing = secretRing.merge(oldSecretRing, mLog, mIndent); @@ -759,8 +754,9 @@ public class ProviderHelper { } // Canonicalize this keyring, to assert a number of assumptions made about it. - secretRing = secretRing.canonicalize(mLog, mIndent); - if (secretRing == null) { + // This is a safe cast, because we made sure this is a secret ring above + canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); + if (canSecretRing == null) { return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); } @@ -775,8 +771,9 @@ public class ProviderHelper { // Not an issue, just means we are dealing with a new keyring // Canonicalize this keyring, to assert a number of assumptions made about it. - secretRing = secretRing.canonicalize(mLog, mIndent); - if (secretRing == null) { + // This is a safe cast, because we made sure this is a secret ring above + canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); + if (canSecretRing == null) { return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); } @@ -785,7 +782,7 @@ public class ProviderHelper { // Merge new data into public keyring as well, if there is any UncachedKeyRing publicRing; try { - UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncachedKeyRing(); + UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing(); // Merge data from new secret ring into public one publicRing = oldPublicRing.merge(secretRing, mLog, mIndent); @@ -798,20 +795,20 @@ public class ProviderHelper { publicRing = secretRing.extractPublicKeyRing(); } - publicRing = publicRing.canonicalize(mLog, mIndent); - if (publicRing == null) { + CanonicalizedPublicKeyRing canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent); + if (canPublicRing == null) { return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); } int result; - result = internalSavePublicKeyRing(publicRing, progress, true); + result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, true); if ((result & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) { return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog); } progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100); - result = internalSaveSecretKeyRing(secretRing); + result = saveCanonicalizedSecretKeyRing(canSecretRing); return new SaveKeyringResult(result, mLog); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 62d6b5ad6..5ed95acb3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -425,7 +425,7 @@ public class OpenPgpService extends RemoteService { try { // try to find key, throws NotFoundException if not in db! - mProviderHelper.getWrappedPublicKeyRing(masterKeyId); + mProviderHelper.getCanonicalizedPublicKeyRing(masterKeyId); Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index a764c323c..f69961df6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -36,6 +36,8 @@ import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; @@ -44,9 +46,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; -import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.WrappedSecretKey; -import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -337,8 +337,8 @@ public class KeychainIntentService extends IntentService if (saveParcel.mMasterKeyId != null) { String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE); - WrappedSecretKeyRing secRing = - providerHelper.getWrappedSecretKeyRing(saveParcel.mMasterKeyId); + CanonicalizedSecretKeyRing secRing = + providerHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId); result = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase); } else { @@ -466,7 +466,7 @@ public class KeychainIntentService extends IntentService HkpKeyserver server = new HkpKeyserver(keyServer); ProviderHelper providerHelper = new ProviderHelper(this); - WrappedPublicKeyRing keyring = providerHelper.getWrappedPublicKeyRing(dataUri); + CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri); PgpImportExport pgpImportExport = new PgpImportExport(this, null); boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, keyring); @@ -542,9 +542,9 @@ public class KeychainIntentService extends IntentService } ProviderHelper providerHelper = new ProviderHelper(this); - WrappedPublicKeyRing publicRing = providerHelper.getWrappedPublicKeyRing(pubKeyId); - WrappedSecretKeyRing secretKeyRing = providerHelper.getWrappedSecretKeyRing(masterKeyId); - WrappedSecretKey certificationKey = secretKeyRing.getSecretKey(); + CanonicalizedPublicKeyRing publicRing = providerHelper.getCanonicalizedPublicKeyRing(pubKeyId); + CanonicalizedSecretKeyRing secretKeyRing = providerHelper.getCanonicalizedSecretKeyRing(masterKeyId); + CanonicalizedSecretKey certificationKey = secretKeyRing.getSecretKey(); if(!certificationKey.unlock(signaturePassphrase)) { throw new PgpGeneralException("Error extracting key (bad passphrase?)"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java index bfe06dca7..99cafd3f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java @@ -260,7 +260,6 @@ public class OperationResultParcel implements Parcelable { // import secret MSG_IS(R.string.msg_is), MSG_IS_BAD_TYPE_PUBLIC (R.string.msg_is_bad_type_public), - MSG_IS_BAD_TYPE_UNCANON (R.string.msg_is_bad_type_uncanon), MSG_IS_DB_EXCEPTION (R.string.msg_is_db_exception), MSG_IS_FAIL_IO_EXC (R.string.msg_is_io_exc), MSG_IS_IMPORTING_SUBKEYS (R.string.msg_is_importing_subkeys), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index cfb3d50f4..c4ecfdec5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -41,7 +41,7 @@ import android.support.v4.app.NotificationCompat; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -184,7 +184,7 @@ public class PassphraseCacheService extends Service { // try to get master key id which is used as an identifier for cached passphrases try { Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId " + keyId); - WrappedSecretKeyRing key = new ProviderHelper(this).getWrappedSecretKeyRing( + CanonicalizedSecretKeyRing key = new ProviderHelper(this).getCanonicalizedSecretKeyRing( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId)); // no passphrase needed? just add empty string and return it, then if (!key.hasPassphrase()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 5ff864547..9083d1567 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -42,14 +42,13 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.OperationResults; import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult; -import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; @@ -169,8 +168,8 @@ public class EditKeyFragment extends LoaderFragment implements try { Uri secretUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri); - WrappedSecretKeyRing keyRing = - new ProviderHelper(getActivity()).getWrappedSecretKeyRing(secretUri); + CanonicalizedSecretKeyRing keyRing = + new ProviderHelper(getActivity()).getCanonicalizedSecretKeyRing(secretUri); mSaveKeyringParcel = new SaveKeyringParcel(keyRing.getMasterKeyId(), keyRing.getUncachedKeyRing().getFingerprint()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java index 75c967c60..43de6774b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java @@ -178,9 +178,11 @@ public class LogDisplayFragment extends ListFragment implements OnTouchListener if (entry.mParameters != null && entry.mParameters.length > 0 && entry.mParameters[0] instanceof Integer) { ih.mText.setText(getResources().getQuantityString(entry.mType.getMsgId(), - (Integer) entry.mParameters[0], entry.mParameters)); + (Integer) entry.mParameters[0], + entry.mParameters)); } else { - ih.mText.setText(getResources().getString(entry.mType.getMsgId(), entry.mParameters)); + ih.mText.setText(getResources().getString(entry.mType.getMsgId(), + entry.mParameters)); } ih.mText.setTextColor(entry.mLevel == LogLevel.DEBUG ? Color.GRAY : Color.BLACK); convertView.setPadding((entry.mIndent) * dipFactor, 0, 0, 0); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index cfdea0611..37c583920 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -35,7 +35,7 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; @@ -143,10 +143,10 @@ public class ViewCertActivity extends ActionBarActivity try { ProviderHelper providerHelper = new ProviderHelper(this); - WrappedPublicKeyRing signeeRing = - providerHelper.getWrappedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID)); - WrappedPublicKeyRing signerRing = - providerHelper.getWrappedPublicKeyRing(sig.getKeyId()); + CanonicalizedPublicKeyRing signeeRing = + providerHelper.getCanonicalizedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID)); + CanonicalizedPublicKeyRing signerRing = + providerHelper.getCanonicalizedPublicKeyRing(sig.getKeyId()); try { sig.init(signerRing.getPublicKey()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java index 0a7fd6aee..cce8c9d9f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java @@ -46,8 +46,8 @@ import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.pgp.WrappedSecretKey; -import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.PassphraseCacheService; @@ -103,7 +103,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor // check if secret key has a passphrase if (!(secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none)) { try { - if (!new ProviderHelper(context).getWrappedSecretKeyRing(secretKeyId).hasPassphrase()) { + if (!new ProviderHelper(context).getCanonicalizedSecretKeyRing(secretKeyId).hasPassphrase()) { throw new PgpGeneralException("No passphrase! No passphrase dialog needed!"); } } catch (ProviderHelper.NotFoundException e) { @@ -134,7 +134,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor alert.setTitle(R.string.title_authentication); - final WrappedSecretKeyRing secretRing; + final CanonicalizedSecretKeyRing secretRing; String userId; if (secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none) { @@ -143,7 +143,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor } else { try { ProviderHelper helper = new ProviderHelper(activity); - secretRing = helper.getWrappedSecretKeyRing(secretKeyId); + secretRing = helper.getCanonicalizedSecretKeyRing(secretKeyId); // yes the inner try/catch block is necessary, otherwise the final variable // above can't be statically verified to have been set in all cases because // the catch clause doesn't return. @@ -193,9 +193,9 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor return; } - WrappedSecretKey unlockedSecretKey = null; + CanonicalizedSecretKey unlockedSecretKey = null; - for (WrappedSecretKey clickSecretKey : secretRing.secretKeyIterator()) { + for (CanonicalizedSecretKey clickSecretKey : secretRing.secretKeyIterator()) { try { boolean unlocked = clickSecretKey.unlock(passphrase); if (unlocked) { -- cgit v1.2.3