From 10ad7be46bd44956116c5ac363ea970bcd8082d6 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 23 May 2014 16:44:50 +0200 Subject: wrapped-key-ring: UncachedKeyRing wraps only one ring of dynamic type --- .../keychain/keyimport/ImportKeysListEntry.java | 49 +++++-------------- .../keychain/pgp/PgpImportExport.java | 19 ++++++-- .../keychain/pgp/PgpKeyOperation.java | 12 ++--- .../keychain/pgp/UncachedKeyRing.java | 56 +++++++++++++++++----- .../keychain/pgp/UncachedPublicKey.java | 36 +++++++++++++- .../keychain/pgp/WrappedPublicKey.java | 26 ---------- .../keychain/provider/ProviderHelper.java | 15 +++--- .../keychain/service/KeychainIntentService.java | 14 +++--- 8 files changed, 126 insertions(+), 101 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java index 04b86e295..2d8a97809 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -21,15 +21,10 @@ import android.content.Context; import android.os.Parcel; import android.os.Parcelable; -import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.util.IterableIterator; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; @@ -233,10 +228,12 @@ public class ImportKeysListEntry implements Serializable, Parcelable { * Constructor based on key object, used for import from NFC, QR Codes, files */ @SuppressWarnings("unchecked") - public ImportKeysListEntry(Context context, PGPKeyRing pgpKeyRing) { + public ImportKeysListEntry(Context context, UncachedKeyRing ring) { + // TODO less bouncy castle objects! + // save actual key object into entry, used to import it later try { - this.mBytes = pgpKeyRing.getEncoded(); + this.mBytes = ring.getEncoded(); } catch (IOException e) { Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e); } @@ -244,42 +241,20 @@ public class ImportKeysListEntry implements Serializable, Parcelable { // selected is default this.mSelected = true; - if (pgpKeyRing instanceof PGPSecretKeyRing) { - secretKey = true; - } else { - secretKey = false; - } - PGPPublicKey key = pgpKeyRing.getPublicKey(); + secretKey = ring.isSecret(); + UncachedPublicKey key = ring.getPublicKey(); + + mPrimaryUserId = key.getPrimaryUserId(); - userIds = new ArrayList(); - for (String userId : new IterableIterator(key.getUserIDs())) { - userIds.add(userId); - for (PGPSignature sig : new IterableIterator(key.getSignaturesForID(userId))) { - if (sig.getHashedSubPackets() != null - && sig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.PRIMARY_USER_ID)) { - try { - // make sure it's actually valid - sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), key); - if (sig.verifyCertification(userId, key)) { - mPrimaryUserId = userId; - } - } catch (Exception e) { - // nothing bad happens, the key is just not considered the primary key id - } - } - - } - } // if there was no user id flagged as primary, use the first one if (mPrimaryUserId == null) { mPrimaryUserId = userIds.get(0); } - this.keyId = key.getKeyID(); + this.keyId = key.getKeyId(); this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId); - this.revoked = key.isRevoked(); + this.revoked = key.maybeRevoked(); this.fingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint()); this.bitStrength = key.getBitStrength(); final int algorithm = key.getAlgorithm(); 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 a55765542..e858012f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -165,7 +165,8 @@ public class PgpImportExport { } newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key); } - status = storeKeyRingInCache(new UncachedKeyRing(newPubRing ,secretKeyRing)); + status = storeKeyRingInCache(new UncachedKeyRing(newPubRing), + new UncachedKeyRing(secretKeyRing)); } else { status = storeKeyRingInCache(new UncachedKeyRing((PGPPublicKeyRing) keyring)); } @@ -278,15 +279,23 @@ public class PgpImportExport { return returnData; } + public int storeKeyRingInCache(UncachedKeyRing ring) { + return storeKeyRingInCache(ring, null); + } + @SuppressWarnings("unchecked") - public int storeKeyRingInCache(UncachedKeyRing keyring) { + public int storeKeyRingInCache(UncachedKeyRing ring, UncachedKeyRing secretRing) { int status; try { - PGPSecretKeyRing secretKeyRing = keyring.getSecretRing(); - PGPPublicKeyRing publicKeyRing = keyring.getPublicRing(); + // TODO make sure these are correctly typed! + PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) ring.getRing(); + PGPSecretKeyRing secretKeyRing = null; + if(secretRing != null) { + secretKeyRing = (PGPSecretKeyRing) secretRing.getRing(); + } // see what type we have. we can either have a secret + public keyring, or just public if (secretKeyRing != null) { - mProviderHelper.saveKeyRing(publicKeyRing, secretKeyRing); + mProviderHelper.saveKeyRing(ring, secretRing); status = RETURN_OK; } else { mProviderHelper.saveKeyRing(publicKeyRing); 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 b9634c34a..5e7134dc6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -331,15 +331,14 @@ public class PgpKeyOperation { } PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing(); - PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing(); - return new UncachedKeyRing(publicKeyRing, secretKeyRing); + return new UncachedKeyRing(secretKeyRing); } - public UncachedKeyRing buildSecretKey(WrappedSecretKeyRing wmKR, - WrappedPublicKeyRing wpKR, - SaveKeyringParcel saveParcel) + public Pair buildSecretKey(WrappedSecretKeyRing wmKR, + WrappedPublicKeyRing wpKR, + SaveKeyringParcel saveParcel) throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { PGPSecretKeyRing mKR = wmKR.getRing(); @@ -664,7 +663,8 @@ public class PgpKeyOperation { */ - return new UncachedKeyRing(pKR, mKR); + return new Pair(new UncachedKeyRing(pKR), + new UncachedKeyRing(mKR)); } 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 58601c49a..06f890fb4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -1,40 +1,51 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPUtil; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.Log; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.List; +import java.util.Vector; public class UncachedKeyRing { - final PGPPublicKeyRing mPublicRing; - final PGPSecretKeyRing mSecretRing; + final PGPKeyRing mRing; + final boolean mIsSecret; - UncachedKeyRing(PGPPublicKeyRing publicRing, PGPSecretKeyRing secretRing) { - mPublicRing = publicRing; - mSecretRing = secretRing; + UncachedKeyRing(PGPKeyRing ring) { + mRing = ring; + mIsSecret = ring instanceof PGPSecretKeyRing; } - UncachedKeyRing(PGPPublicKeyRing publicRing) { - this(publicRing, null); + /* TODO don't use this */ + @Deprecated + public PGPKeyRing getRing() { + return mRing; } - public PGPPublicKeyRing getPublicRing() { - return mPublicRing; + public UncachedPublicKey getPublicKey() { + return new UncachedPublicKey(mRing.getPublicKey()); } - public PGPSecretKeyRing getSecretRing() { - return mSecretRing; + public boolean isSecret() { + return mIsSecret; + } + + public byte[] getEncoded() throws IOException { + return mRing.getEncoded(); } public byte[] getFingerprint() { - return mPublicRing.getPublicKey().getFingerprint(); + return mRing.getPublicKey().getFingerprint(); } public static UncachedKeyRing decodePubkeyFromData(byte[] data) @@ -57,4 +68,25 @@ public class UncachedKeyRing { } } + public static List fromStream(InputStream stream) + throws PgpGeneralException, IOException { + + PGPObjectFactory objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(stream)); + + List result = new Vector(); + + // go through all objects in this block + Object obj; + while ((obj = objectFactory.nextObject()) != null) { + Log.d(Constants.TAG, "Found class: " + obj.getClass()); + + if (obj instanceof PGPKeyRing) { + result.add(new UncachedKeyRing((PGPKeyRing) obj)); + } else { + Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); + } + } + return result; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index bc37f6201..7f6fae4a6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -1,14 +1,19 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.List; public class UncachedPublicKey { protected final PGPPublicKey mPublicKey; @@ -22,7 +27,8 @@ public class UncachedPublicKey { return mPublicKey.getKeyID(); } - public boolean isRevoked() { + /** The revocation signature is NOT checked here, so this may be false! */ + public boolean maybeRevoked() { return mPublicKey.isRevoked(); } @@ -60,6 +66,34 @@ public class UncachedPublicKey { return mPublicKey.getAlgorithm(); } + public int getBitStrength() { + return mPublicKey.getBitStrength(); + } + + public String getPrimaryUserId() { + List userIds = new ArrayList(); + for (String userId : new IterableIterator(mPublicKey.getUserIDs())) { + userIds.add(userId); + for (PGPSignature sig : new IterableIterator(mPublicKey.getSignaturesForID(userId))) { + if (sig.getHashedSubPackets() != null + && sig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.PRIMARY_USER_ID)) { + try { + // make sure it's actually valid + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey); + if (sig.verifyCertification(userId, mPublicKey)) { + return userId; + } + } catch (Exception e) { + // nothing bad happens, the key is just not considered the primary key id + } + } + + } + } + return null; + } + public boolean isElGamalEncrypt() { return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java index 72352a451..32c6910be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java @@ -33,30 +33,4 @@ public class WrappedPublicKey extends UncachedPublicKey { 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/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 4df86ee9b..67d11f9f0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -449,24 +449,23 @@ public class ProviderHelper { } - public void saveKeyRing(UncachedKeyRing wrappedRing) throws IOException { - PGPPublicKeyRing pubRing = wrappedRing.getPublicRing(); - PGPSecretKeyRing secRing = wrappedRing.getSecretRing(); - saveKeyRing(pubRing, secRing); + public void saveKeyRing(UncachedKeyRing ring) throws IOException { + PGPPublicKeyRing pubRing = (PGPPublicKeyRing) ring.getRing(); + saveKeyRing(pubRing); } /** * Saves (or updates) a pair of public and secret KeyRings in the database */ - public void saveKeyRing(PGPPublicKeyRing pubRing, PGPSecretKeyRing privRing) throws IOException { - long masterKeyId = pubRing.getPublicKey().getKeyID(); + public void saveKeyRing(UncachedKeyRing pubRing, UncachedKeyRing secRing) throws IOException { + long masterKeyId = pubRing.getPublicKey().getKeyId(); // delete secret keyring (so it isn't unnecessarily saved by public-saveKeyRing below) mContentResolver.delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null); // save public keyring - saveKeyRing(pubRing); - saveKeyRing(privRing); + saveKeyRing((PGPPublicKeyRing) pubRing.getRing()); + saveKeyRing((PGPSecretKeyRing) secRing.getRing()); } /** 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 b866bdf7f..250e1cdda 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -524,19 +524,21 @@ public class KeychainIntentService extends IntentService setProgress(R.string.progress_done, 100, 100); } else { PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100)); - UncachedKeyRing pair; try { WrappedSecretKeyRing privkey = providerHelper.getWrappedSecretKeyRing(masterKeyId); WrappedPublicKeyRing pubkey = providerHelper.getWrappedPublicKeyRing(masterKeyId); - pair = keyOperations.buildSecretKey(privkey, pubkey, saveParcel); // edit existing + PgpKeyOperation.Pair pair = + keyOperations.buildSecretKey(privkey, pubkey, saveParcel); // edit existing + setProgress(R.string.progress_saving_key_ring, 90, 100); + providerHelper.saveKeyRing(pair.first, pair.second); } catch (ProviderHelper.NotFoundException e) { - pair = keyOperations.buildNewSecretKey(saveParcel); //new Keyring + UncachedKeyRing ring = keyOperations.buildNewSecretKey(saveParcel); //new Keyring + // save the pair + setProgress(R.string.progress_saving_key_ring, 90, 100); + providerHelper.saveKeyRing(ring); } - setProgress(R.string.progress_saving_key_ring, 90, 100); - // save the pair - providerHelper.saveKeyRing(pair); setProgress(R.string.progress_done, 100, 100); } PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase); -- cgit v1.2.3