From 4b3cfd4fa41ef8339a0691b38c4c6ec481b5c3df Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 3 May 2014 15:55:10 +0200 Subject: wrapped-key-ring: first steps, get rid of key imports in decryptverify and signencrypt --- .../keychain/pgp/CachedKeyRing.java | 61 +++++ .../keychain/pgp/CachedPublicKey.java | 53 ++++ .../keychain/pgp/CachedPublicKeyRing.java | 219 ++++++++++++++++ .../keychain/pgp/CachedSecretKey.java | 121 +++++++++ .../keychain/pgp/CachedSecretKeyRing.java | 74 ++++++ .../keychain/pgp/PgpDecryptVerify.java | 274 ++++----------------- .../keychain/pgp/PgpImportExport.java | 8 +- .../keychain/pgp/PgpKeyHelper.java | 48 ++-- .../keychain/pgp/PgpSignEncrypt.java | 82 ++---- .../keychain/provider/KeychainContract.java | 6 + .../keychain/provider/KeychainProvider.java | 22 ++ .../keychain/provider/ProviderHelper.java | 96 +++++++- 12 files changed, 744 insertions(+), 320 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java new file mode 100644 index 000000000..5cf89b6a6 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java @@ -0,0 +1,61 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPSignature; + +public abstract class CachedKeyRing { + + private final long mMasterKeyId; + private final int mKeySize; + private final boolean mIsRevoked; + private final boolean mCanCertify; + private final long mCreation; + private final long mExpiry; + private final int mAlgorithm; + private final byte[] mFingerprint; + private final String mUserId; + private final int mVerified; + private final boolean mHasSecret; + + protected CachedKeyRing(long masterKeyId, int keySize, boolean isRevoked, + boolean canCertify, long creation, long expiry, int algorithm, + byte[] fingerprint, String userId, int verified, boolean hasSecret) + { + mMasterKeyId = masterKeyId; + mKeySize = keySize; + mIsRevoked = isRevoked; + mCanCertify = canCertify; + mCreation = creation; + mExpiry = expiry; + mAlgorithm = algorithm; + mFingerprint = fingerprint; + mUserId = userId; + mVerified = verified; + mHasSecret = hasSecret; + } + + public boolean isRevoked() { + return mIsRevoked; + } + + public byte[] getFingerprint() { + + return mFingerprint; + } + + public String getPrimaryUserId() { + return mUserId; + } + + public long getMasterKeyId() { + return mMasterKeyId; + } + + public int getVerified() { + return mVerified; + } + + public void initSignature(PGPSignature sig) { + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java new file mode 100644 index 000000000..fb065c85f --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java @@ -0,0 +1,53 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.sufficientlysecure.keychain.Constants; + +public class CachedPublicKey { + + // this is the parent key ring + private final CachedPublicKeyRing mRing; + + private final PGPPublicKey mKey; + + CachedPublicKey(CachedPublicKeyRing ring, PGPPublicKey key) { + mRing = ring; + mKey = key; + } + + public CachedPublicKeyRing getKeyRing() { + return mRing; + } + + JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() { + return new JcePublicKeyKeyEncryptionMethodGenerator(mKey); + } + + public void initSignature(PGPSignature sig) throws PGPException { + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + sig.init(contentVerifierBuilderProvider, mKey); + } + + public void initSignature(PGPOnePassSignature sig) throws PGPException { + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + sig.init(contentVerifierBuilderProvider, mKey); + } + + public byte[] getFingerprint() { + return mKey.getFingerprint(); + } + + // Note that this method has package visibility - no access outside the pgp package! + PGPPublicKey getKey() { + return mKey; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java new file mode 100644 index 000000000..fb142adce --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java @@ -0,0 +1,219 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.bcpg.SignatureSubpacketTags; +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.io.IOException; +import java.security.SignatureException; +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; + +public class CachedPublicKeyRing extends CachedKeyRing { + + private PGPPublicKeyRing mRing; + private final byte[] mPubKey; + + public CachedPublicKeyRing(long masterKeyId, int keySize, boolean isRevoked, + boolean canCertify, long creation, long expiry, int algorithm, + byte[] fingerprint, String userId, int verified, boolean hasSecret, + byte[] pubkey) + { + super(masterKeyId, keySize, isRevoked, canCertify, creation, expiry, + algorithm, fingerprint, userId, verified, hasSecret); + + mPubKey = pubkey; + } + + private PGPPublicKeyRing getRing() { + if(mRing == null) { + mRing = (PGPPublicKeyRing) PgpConversionHelper.BytesToPGPKeyRing(mPubKey); + } + return mRing; + } + + public void encode(ArmoredOutputStream stream) throws IOException { + getRing().encode(stream); + } + + public CachedPublicKey getSubkey(long id) { + return new CachedPublicKey(this, getRing().getPublicKey(id)); + } + + public CachedPublicKey getFirstEncryptSubkey() throws PgpGeneralException { + // only return master key if no other encryption key is available + PGPPublicKey masterKey = null; + for (PGPPublicKey key : new IterableIterator(getRing().getPublicKeys())) { + if (key.isRevoked() || !isEncryptionKey(key) || isExpired(key)) { + continue; + } + if (key.isMasterKey()) { + masterKey = key; + } else { + return new CachedPublicKey(this, key); + } + } + if(masterKey == null) { + // TODO proper exception + throw new PgpGeneralException("key not found"); + } + return new CachedPublicKey(this, masterKey); + } + + public boolean verifySubkeyBinding(CachedPublicKey cachedSubkey) { + boolean validSubkeyBinding = false; + boolean validTempSubkeyBinding = false; + boolean validPrimaryKeyBinding = false; + + PGPPublicKey masterKey = getRing().getPublicKey(); + PGPPublicKey subKey = cachedSubkey.getKey(); + + // Is this the master key? Match automatically, then. + if(Arrays.equals(masterKey.getFingerprint(), subKey.getFingerprint())) { + return true; + } + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + + Iterator itr = subKey.getSignatures(); + + while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong? + //gpg has an invalid subkey binding error on key import I think, but doesn't shout + //about keys without subkey signing. Can't get it to import a slightly broken one + //either, so we will err on bad subkey binding here. + PGPSignature sig = itr.next(); + if (sig.getKeyID() == masterKey.getKeyID() && + sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) { + //check and if ok, check primary key binding. + try { + sig.init(contentVerifierBuilderProvider, masterKey); + validTempSubkeyBinding = sig.verifyCertification(masterKey, subKey); + } catch (PGPException e) { + continue; + } catch (SignatureException e) { + continue; + } + + if (validTempSubkeyBinding) { + validSubkeyBinding = true; + } + if (validTempSubkeyBinding) { + validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(), + masterKey, subKey); + if (validPrimaryKeyBinding) { + break; + } + validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(), + masterKey, subKey); + if (validPrimaryKeyBinding) { + break; + } + } + } + } + return validSubkeyBinding && validPrimaryKeyBinding; + + } + + + static boolean isEncryptionKey(PGPPublicKey key) { + if (!key.isEncryptionKey()) { + return false; + } + + if (key.getVersion() <= 3) { + // this must be true now + return key.isEncryptionKey(); + } + + // special cases + if (key.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) { + return true; + } + + if (key.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) { + return true; + } + + for (PGPSignature sig : new IterableIterator(key.getSignatures())) { + if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { + continue; + } + PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); + + if (hashed != null + && (hashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) { + return true; + } + + PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); + + if (unhashed != null + && (unhashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) { + return true; + } + } + return false; + } + + static boolean isExpired(PGPPublicKey key) { + Date creationDate = key.getCreationTime(); + Date expiryDate = key.getValidSeconds() > 0 + ? new Date(creationDate.getTime() + key.getValidSeconds() * 1000) : null; + + Date now = new Date(); + return creationDate.after(now) || (expiryDate != null && expiryDate.before(now)); + } + + static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts, + PGPPublicKey masterPublicKey, + PGPPublicKey signingPublicKey) { + boolean validPrimaryKeyBinding = false; + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureList eSigList; + + if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) { + try { + eSigList = pkts.getEmbeddedSignatures(); + } catch (IOException e) { + return false; + } catch (PGPException e) { + return false; + } + for (int j = 0; j < eSigList.size(); ++j) { + PGPSignature emSig = eSigList.get(j); + if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) { + try { + emSig.init(contentVerifierBuilderProvider, signingPublicKey); + validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey); + if (validPrimaryKeyBinding) { + break; + } + } catch (PGPException e) { + continue; + } catch (SignatureException e) { + continue; + } + } + } + } + + return validPrimaryKeyBinding; + } + +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java new file mode 100644 index 000000000..514fca6fb --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java @@ -0,0 +1,121 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPV3SignatureGenerator; +import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.spongycastle.openpgp.operator.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; + +public class CachedSecretKey { + + // this is the parent key ring + private final CachedSecretKeyRing mRing; + + private final PGPSecretKey mKey; + private PGPPrivateKey mPrivateKey = null; + + CachedSecretKey(CachedSecretKeyRing ring, PGPSecretKey key) { + mRing = ring; + mKey = key; + } + + public CachedSecretKeyRing getRing() { + return mRing; + } + + public void unlock(String passphrase) throws PgpGeneralException { + try { + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + mPrivateKey = mKey.extractPrivateKey(keyDecryptor); + } catch (PGPException e) { + throw new PgpGeneralException("error extracting key!", e); + } + if(mPrivateKey == null) { + throw new PgpGeneralException("error extracting key (bad passphrase?)"); + } + } + + 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( + mKey.getPublicKey().getAlgorithm(), hashAlgo) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + + int signatureType; + if (cleartext) { + // for sign-only ascii text + signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; + } else { + signatureType = PGPSignature.BINARY_DOCUMENT; + } + + try { + PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); + signatureGenerator.init(signatureType, mPrivateKey); + + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + spGen.setSignerUserID(false, mRing.getPrimaryUserId()); + signatureGenerator.setHashedSubpackets(spGen.generate()); + return signatureGenerator; + } catch(PGPException e) { + throw new PgpGeneralException("Error initializing signature!", e); + } + } + + public PGPV3SignatureGenerator getV3SignatureGenerator(int hashAlgo, boolean cleartext) + throws PgpGeneralException { + if(mPrivateKey == null) { + throw new PrivateKeyNotUnlockedException(); + } + + // content signer based on signing key algorithm and chosen hash algorithm + JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( + mKey.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); + } + + 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() + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java new file mode 100644 index 000000000..a2b2b2832 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java @@ -0,0 +1,74 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.sufficientlysecure.keychain.util.IterableIterator; + +public class CachedSecretKeyRing extends CachedKeyRing { + + private PGPSecretKeyRing mRing; + + public CachedSecretKeyRing(long masterKeyId, int keySize, boolean isRevoked, + boolean canCertify, long creation, long expiry, int algorithm, + byte[] fingerprint, String userId, int verified, boolean hasSecret, + byte[] blob) + { + super(masterKeyId, keySize, isRevoked, canCertify, creation, expiry, + algorithm, fingerprint, userId, verified, hasSecret); + + mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob); + } + + CachedSecretKey getSubKey(long id) { + return new CachedSecretKey(this, mRing.getSecretKey(id)); + } + + /** This returns the subkey that should be used for signing. + * At this point, this is simply the first suitable subkey. + */ + CachedSecretKey getSigningSubKey() { + for (PGPSecretKey key : new IterableIterator(mRing.getSecretKeys())) { + if (isSigningKey(key.getPublicKey())) { + return new CachedSecretKey(this, key); + } + } + // TODO exception + return null; + } + + @SuppressWarnings("unchecked") + public static boolean isSigningKey(PGPPublicKey key) { + if (key.getVersion() <= 3) { + return true; + } + + // special case + if (key.getAlgorithm() == PGPPublicKey.RSA_SIGN) { + return true; + } + + for (PGPSignature sig : new IterableIterator(key.getSignatures())) { + if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { + continue; + } + PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); + + if (hashed != null && (hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) { + return true; + } + + PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); + + if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) { + return true; + } + } + + return false; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 506c161ba..c84b9413f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -18,10 +18,7 @@ package org.sufficientlysecure.keychain.pgp; -import android.net.Uri; - import org.spongycastle.bcpg.ArmoredInputStream; -import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.openpgp.PGPCompressedData; import org.spongycastle.openpgp.PGPEncryptedData; import org.spongycastle.openpgp.PGPEncryptedDataList; @@ -31,29 +28,18 @@ import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPOnePassSignature; import org.spongycastle.openpgp.PGPOnePassSignatureList; import org.spongycastle.openpgp.PGPPBEEncryptedData; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.Progressable; -import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.InputData; @@ -67,7 +53,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.security.SignatureException; import java.util.Iterator; -import java.util.Map; import java.util.Set; /** @@ -248,7 +233,7 @@ public class PgpDecryptVerify { PGPPublicKeyEncryptedData encryptedDataAsymmetric = null; PGPPBEEncryptedData encryptedDataSymmetric = null; - PGPSecretKey secretEncryptionKey = null; + CachedSecretKey secretEncryptionKey = null; Iterator it = enc.getEncryptedDataObjects(); boolean asymmetricPacketFound = false; boolean symmetricPacketFound = false; @@ -260,15 +245,13 @@ public class PgpDecryptVerify { PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj; - long masterKeyId; - PGPSecretKeyRing secretKeyRing; + CachedSecretKeyRing secretKeyRing; try { - // get master key id for this encryption key id - masterKeyId = mProviderHelper.getMasterKeyId( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(encData.getKeyID())) - ); // get actual keyring object based on master key id - secretKeyRing = mProviderHelper.getPGPSecretKeyRing(masterKeyId); + secretKeyRing = mProviderHelper.getCachedSecretKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( + Long.toString(encData.getKeyID())) + ); } catch (ProviderHelper.NotFoundException e) { // continue with the next packet in the while loop continue; @@ -278,13 +261,14 @@ public class PgpDecryptVerify { continue; } // get subkey which has been used for this encryption packet - secretEncryptionKey = secretKeyRing.getSecretKey(encData.getKeyID()); + secretEncryptionKey = secretKeyRing.getSubKey(encData.getKeyID()); if (secretEncryptionKey == null) { // continue with the next packet in the while loop continue; } /* secret key exists in database! */ + long masterKeyId = secretEncryptionKey.getRing().getMasterKeyId(); // allow only specific keys for decryption? if (mAllowedKeyIds != null) { @@ -359,23 +343,15 @@ public class PgpDecryptVerify { } else if (asymmetricPacketFound) { currentProgress += 5; updateProgress(R.string.progress_extracting_key, currentProgress, 100); - PGPPrivateKey privateKey; try { - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - mPassphrase.toCharArray()); - privateKey = secretEncryptionKey.extractPrivateKey(keyDecryptor); - } catch (PGPException e) { + secretEncryptionKey.unlock(mPassphrase); + } catch (PgpGeneralException e) { throw new WrongPassphraseException(); } - if (privateKey == null) { - throw new KeyExtractionException(); - } currentProgress += 5; updateProgress(R.string.progress_preparing_streams, currentProgress, 100); - PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey); + PublicKeyDataDecryptorFactory decryptorFactory = secretEncryptionKey.getDecryptorFactory(); clear = encryptedDataAsymmetric.getDataStream(decryptorFactory); @@ -388,10 +364,9 @@ public class PgpDecryptVerify { PGPObjectFactory plainFact = new PGPObjectFactory(clear); Object dataChunk = plainFact.nextObject(); - PGPOnePassSignature signature = null; OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); - PGPPublicKey signatureKey = null; int signatureIndex = -1; + CachedPublicKey signingKey = null; if (dataChunk instanceof PGPCompressedData) { updateProgress(R.string.progress_decompressing_data, currentProgress, 100); @@ -403,6 +378,8 @@ public class PgpDecryptVerify { currentProgress += 10; } + PGPOnePassSignature signature = null; + if (dataChunk instanceof PGPOnePassSignatureList) { updateProgress(R.string.progress_processing_signature, currentProgress, 100); @@ -410,19 +387,15 @@ public class PgpDecryptVerify { // go through all signatures // and find out for which signature we have a key in our database - Long masterKeyId = null; - String primaryUserId = null; for (int i = 0; i < sigList.size(); ++i) { try { - Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( - Long.toString(sigList.get(i).getKeyID())); - Map data = mProviderHelper.getGenericData(uri, - new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID }, - new int[] { ProviderHelper.FIELD_TYPE_INTEGER, - ProviderHelper.FIELD_TYPE_STRING } + long sigKeyId = sigList.get(i).getKeyID(); + CachedPublicKeyRing signingRing = mProviderHelper.getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( + Long.toString(sigKeyId) + ) ); - masterKeyId = (Long) data.get(KeyRings.MASTER_KEY_ID); - primaryUserId = (String) data.get(KeyRings.USER_ID); + signingKey = signingRing.getSubkey(sigKeyId); signatureIndex = i; } catch (ProviderHelper.NotFoundException e) { Log.d(Constants.TAG, "key not found!"); @@ -430,43 +403,17 @@ public class PgpDecryptVerify { } } - if (masterKeyId != null) { + if (signingKey != null) { // key found in our database! signature = sigList.get(signatureIndex); - PGPPublicKeyRing publicKeyRing = null; - try { - publicKeyRing = mProviderHelper - .getPGPPublicKeyRing(masterKeyId); - } catch (ProviderHelper.NotFoundException e) { - // can't happen - } - - // get the subkey which has been used to generate this signature - signatureKey = publicKeyRing.getPublicKey(signature.getKeyID()); - signatureResultBuilder.signatureAvailable(true); signatureResultBuilder.knownKey(true); - signatureResultBuilder.userId(primaryUserId); - signatureResultBuilder.keyId(masterKeyId); + signatureResultBuilder.keyId(signingKey.getKeyRing().getMasterKeyId()); + signatureResultBuilder.userId(signingKey.getKeyRing().getPrimaryUserId()); + signatureResultBuilder.signatureKeyCertified(signingKey.getKeyRing().getVerified() > 0); - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - signature.init(contentVerifierBuilderProvider, signatureKey); - - // get certification status of this key - boolean isSignatureKeyCertified; - try { - Object data = mProviderHelper.getGenericData( - KeychainContract.KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), - KeyRings.VERIFIED, - ProviderHelper.FIELD_TYPE_INTEGER); - isSignatureKeyCertified = ((Long) data > 0); - } catch (ProviderHelper.NotFoundException e) { - isSignatureKeyCertified = false; - } - signatureResultBuilder.signatureKeyCertified(isSignatureKeyCertified); + signingKey.initSignature(signature); } else { // no key in our database -> return "unknown pub key" status including the first key id if (!sigList.isEmpty()) { @@ -541,7 +488,7 @@ public class PgpDecryptVerify { // Verify signature and check binding signatures boolean validSignature = signature.verify(messageSignature); - boolean validKeyBinding = verifyKeyBinding(messageSignature, signatureKey); + boolean validKeyBinding = signingKey.getKeyRing().verifySubkeyBinding(signingKey); signatureResultBuilder.validSignature(validSignature); signatureResultBuilder.validKeyBinding(validKeyBinding); @@ -617,22 +564,20 @@ public class PgpDecryptVerify { throw new InvalidDataException(); } + CachedPublicKey signingKey = null; + int signatureIndex = -1; + // go through all signatures // and find out for which signature we have a key in our database - Long masterKeyId = null; - String primaryUserId = null; - int signatureIndex = 0; for (int i = 0; i < sigList.size(); ++i) { try { - Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( - Long.toString(sigList.get(i).getKeyID())); - Map data = mProviderHelper.getGenericData(uri, - new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID }, - new int[] { ProviderHelper.FIELD_TYPE_INTEGER, - ProviderHelper.FIELD_TYPE_STRING } + long sigKeyId = sigList.get(i).getKeyID(); + CachedPublicKeyRing signingRing = mProviderHelper.getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( + Long.toString(sigKeyId) + ) ); - masterKeyId = (Long) data.get(KeyRings.MASTER_KEY_ID); - primaryUserId = (String) data.get(KeyRings.USER_ID); + signingKey = signingRing.getSubkey(sigKeyId); signatureIndex = i; } catch (ProviderHelper.NotFoundException e) { Log.d(Constants.TAG, "key not found!"); @@ -641,44 +586,18 @@ public class PgpDecryptVerify { } PGPSignature signature = null; - PGPPublicKey signatureKey = null; - if (masterKeyId != null) { + + if (signingKey != null) { // key found in our database! signature = sigList.get(signatureIndex); - PGPPublicKeyRing publicKeyRing = null; - try { - publicKeyRing = mProviderHelper - .getPGPPublicKeyRing(masterKeyId); - } catch (ProviderHelper.NotFoundException e) { - // can't happen - } - - // get the subkey which has been used to generate this signature - signatureKey = publicKeyRing.getPublicKey(signature.getKeyID()); - signatureResultBuilder.signatureAvailable(true); signatureResultBuilder.knownKey(true); - signatureResultBuilder.userId(primaryUserId); - signatureResultBuilder.keyId(masterKeyId); + signatureResultBuilder.keyId(signingKey.getKeyRing().getMasterKeyId()); + signatureResultBuilder.userId(signingKey.getKeyRing().getPrimaryUserId()); + signatureResultBuilder.signatureKeyCertified(signingKey.getKeyRing().getVerified() > 0); - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - signature.init(contentVerifierBuilderProvider, signatureKey); - - // get certification status of this key - boolean isSignatureKeyCertified; - try { - Object data = mProviderHelper.getGenericData( - KeychainContract.KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), - KeyRings.VERIFIED, - ProviderHelper.FIELD_TYPE_INTEGER); - isSignatureKeyCertified = ((Long) data > 0); - } catch (ProviderHelper.NotFoundException e) { - isSignatureKeyCertified = false; - } - signatureResultBuilder.signatureKeyCertified(isSignatureKeyCertified); + signingKey.initSignature(signature); } else { // no key in our database -> return "unknown pub key" status including the first key id if (!sigList.isEmpty()) { @@ -710,7 +629,7 @@ public class PgpDecryptVerify { // Verify signature and check binding signatures boolean validSignature = signature.verify(); - boolean validKeyBinding = verifyKeyBinding(signature, signatureKey); + boolean validKeyBinding = signingKey.getKeyRing().verifySubkeyBinding(signingKey); signatureResultBuilder.validSignature(validSignature); signatureResultBuilder.validKeyBinding(validKeyBinding); @@ -722,113 +641,6 @@ public class PgpDecryptVerify { return result; } - private boolean verifyKeyBinding(PGPSignature signature, PGPPublicKey signatureKey) { - long signatureKeyId = signature.getKeyID(); - boolean validKeyBinding = false; - - PGPPublicKey mKey = null; - try { - PGPPublicKeyRing signKeyRing = mProviderHelper.getPGPPublicKeyRingWithKeyId( - signatureKeyId); - mKey = signKeyRing.getPublicKey(); - } catch (ProviderHelper.NotFoundException e) { - Log.d(Constants.TAG, "key not found"); - } - - if (signature.getKeyID() != mKey.getKeyID()) { - validKeyBinding = verifyKeyBinding(mKey, signatureKey); - } else { //if the key used to make the signature was the master key, no need to check binding sigs - validKeyBinding = true; - } - return validKeyBinding; - } - - private boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { - boolean validSubkeyBinding = false; - boolean validTempSubkeyBinding = false; - boolean validPrimaryKeyBinding = false; - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - Iterator itr = signingPublicKey.getSignatures(); - - while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong? - //gpg has an invalid subkey binding error on key import I think, but doesn't shout - //about keys without subkey signing. Can't get it to import a slightly broken one - //either, so we will err on bad subkey binding here. - PGPSignature sig = itr.next(); - if (sig.getKeyID() == masterPublicKey.getKeyID() && - sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) { - //check and if ok, check primary key binding. - try { - sig.init(contentVerifierBuilderProvider, masterPublicKey); - validTempSubkeyBinding = sig.verifyCertification(masterPublicKey, signingPublicKey); - } catch (PGPException e) { - continue; - } catch (SignatureException e) { - continue; - } - - if (validTempSubkeyBinding) { - validSubkeyBinding = true; - } - if (validTempSubkeyBinding) { - validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(), - masterPublicKey, signingPublicKey); - if (validPrimaryKeyBinding) { - break; - } - validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(), - masterPublicKey, signingPublicKey); - if (validPrimaryKeyBinding) { - break; - } - } - } - } - return (validSubkeyBinding & validPrimaryKeyBinding); - } - - private boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts, - PGPPublicKey masterPublicKey, - PGPPublicKey signingPublicKey) { - boolean validPrimaryKeyBinding = false; - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - PGPSignatureList eSigList; - - if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) { - try { - eSigList = pkts.getEmbeddedSignatures(); - } catch (IOException e) { - return false; - } catch (PGPException e) { - return false; - } - for (int j = 0; j < eSigList.size(); ++j) { - PGPSignature emSig = eSigList.get(j); - if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) { - try { - emSig.init(contentVerifierBuilderProvider, signingPublicKey); - validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey); - if (validPrimaryKeyBinding) { - break; - } - } catch (PGPException e) { - continue; - } catch (SignatureException e) { - continue; - } - } - } - } - - return validPrimaryKeyBinding; - } - /** * Mostly taken from ClearSignedFileProcessor in Bouncy Castle * diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index bfbcd582e..6aeb19e65 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -32,8 +32,8 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; @@ -208,9 +208,11 @@ public class PgpImportExport { updateProgress(progress * 100 / masterKeyIdsSize, 100); try { - PGPPublicKeyRing publicKeyRing = mProviderHelper.getPGPPublicKeyRing(pubKeyMasterId); + CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing( + KeychainContract.KeyRings.buildGenericKeyRingUri(pubKeyMasterId) + ); - publicKeyRing.encode(arOutStream); + ring.encode(arOutStream); } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); // TODO: inform user? diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index f90250f57..ecaeac7e7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -52,14 +52,17 @@ public class PgpKeyHelper { private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$"); + @Deprecated public static Date getCreationDate(PGPPublicKey key) { return key.getCreationTime(); } + @Deprecated public static Date getCreationDate(PGPSecretKey key) { return key.getPublicKey().getCreationTime(); } + @Deprecated public static Date getExpiryDate(PGPPublicKey key) { Date creationDate = getCreationDate(key); if (key.getValidDays() == 0) { @@ -73,10 +76,12 @@ public class PgpKeyHelper { return calendar.getTime(); } + @Deprecated public static Date getExpiryDate(PGPSecretKey key) { return getExpiryDate(key.getPublicKey()); } + @Deprecated public static boolean isExpired(PGPPublicKey key) { Date creationDate = getCreationDate(key); Date expiryDate = getExpiryDate(key); @@ -89,6 +94,7 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") + @Deprecated public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) { long cnt = 0; if (keyRing == null) { @@ -105,6 +111,7 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") + @Deprecated private static Vector getEncryptKeys(PGPPublicKeyRing keyRing) { Vector encryptKeys = new Vector(); @@ -118,6 +125,7 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") + @Deprecated private static Vector getSigningKeys(PGPSecretKeyRing keyRing) { Vector signingKeys = new Vector(); @@ -131,6 +139,7 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") + @Deprecated private static Vector getCertificationKeys(PGPSecretKeyRing keyRing) { Vector signingKeys = new Vector(); @@ -143,26 +152,7 @@ public class PgpKeyHelper { return signingKeys; } - private static Vector getUsableEncryptKeys(PGPPublicKeyRing keyRing) { - Vector usableKeys = new Vector(); - Vector encryptKeys = getEncryptKeys(keyRing); - PGPPublicKey masterKey = null; - for (int i = 0; i < encryptKeys.size(); ++i) { - PGPPublicKey key = encryptKeys.get(i); - if (!isExpired(key) && !key.isRevoked()) { - if (key.isMasterKey()) { - masterKey = key; - } else { - usableKeys.add(key); - } - } - } - if (masterKey != null) { - usableKeys.add(masterKey); - } - return usableKeys; - } - + @Deprecated private static Vector getUsableCertificationKeys(PGPSecretKeyRing keyRing) { Vector usableKeys = new Vector(); Vector signingKeys = getCertificationKeys(keyRing); @@ -181,6 +171,7 @@ public class PgpKeyHelper { return usableKeys; } + @Deprecated private static Vector getUsableSigningKeys(PGPSecretKeyRing keyRing) { Vector usableKeys = new Vector(); Vector signingKeys = getSigningKeys(keyRing); @@ -199,16 +190,6 @@ public class PgpKeyHelper { return usableKeys; } - - public static PGPPublicKey getFirstEncryptSubkey(PGPPublicKeyRing keyRing) { - Vector encryptKeys = getUsableEncryptKeys(keyRing); - if (encryptKeys.size() == 0) { - Log.e(Constants.TAG, "encryptKeys is null!"); - return null; - } - return encryptKeys.get(0); - } - public static PGPSecretKey getFirstCertificationSubkey(PGPSecretKeyRing keyRing) { Vector signingKeys = getUsableCertificationKeys(keyRing); if (signingKeys.size() == 0) { @@ -253,6 +234,7 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") + @Deprecated public static boolean isEncryptionKey(PGPPublicKey key) { if (!key.isEncryptionKey()) { return false; @@ -298,6 +280,7 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") + @Deprecated public static boolean isSigningKey(PGPPublicKey key) { if (key.getVersion() <= 3) { return true; @@ -328,11 +311,13 @@ public class PgpKeyHelper { return false; } + @Deprecated public static boolean isSigningKey(PGPSecretKey key) { return isSigningKey(key.getPublicKey()); } @SuppressWarnings("unchecked") + @Deprecated public static boolean isCertificationKey(PGPPublicKey key) { if (key.getVersion() <= 3) { return true; @@ -358,11 +343,13 @@ public class PgpKeyHelper { return false; } + @Deprecated public static boolean isAuthenticationKey(PGPSecretKey key) { return isAuthenticationKey(key.getPublicKey()); } @SuppressWarnings("unchecked") + @Deprecated public static boolean isAuthenticationKey(PGPPublicKey key) { if (key.getVersion() <= 3) { return true; @@ -388,6 +375,7 @@ public class PgpKeyHelper { return false; } + @Deprecated public static boolean isCertificationKey(PGPSecretKey key) { return isCertificationKey(key.getPublicKey()); } 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 30cac9b77..48cc5d6da 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -25,25 +25,14 @@ import org.spongycastle.openpgp.PGPEncryptedDataGenerator; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPLiteralData; import org.spongycastle.openpgp.PGPLiteralDataGenerator; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureGenerator; -import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; import org.spongycastle.openpgp.PGPV3SignatureGenerator; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.Progressable; -import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; @@ -279,19 +268,15 @@ public class PgpSignEncrypt { } /* Get keys for signature generation for later usage */ - PGPSecretKey signingKey = null; - PGPSecretKeyRing signingKeyRing = null; - PGPPrivateKey signaturePrivateKey = null; - String signingUserId = null; + CachedSecretKey signingKey = null; if (enableSignature) { + CachedSecretKeyRing signingKeyRing = null; try { - signingKeyRing = mProviderHelper.getPGPSecretKeyRing(mSignatureMasterKeyId); - signingUserId = (String) mProviderHelper.getUnifiedData(mSignatureMasterKeyId, - KeychainContract.KeyRings.USER_ID, ProviderHelper.FIELD_TYPE_STRING); + signingKeyRing = mProviderHelper.getCachedSecretKeyRing(mSignatureMasterKeyId); } catch (ProviderHelper.NotFoundException e) { throw new NoSigningKeyException(); } - signingKey = PgpKeyHelper.getFirstSigningSubkey(signingKeyRing); + signingKey = signingKeyRing.getSigningSubKey(); if (signingKey == null) { throw new NoSigningKeyException(); } @@ -302,10 +287,9 @@ public class PgpSignEncrypt { updateProgress(R.string.progress_extracting_signature_key, 0, 100); - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray()); - signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor); - if (signaturePrivateKey == null) { + try { + signingKey.unlock(mSignaturePassphrase); + } catch (PgpGeneralException e) { throw new KeyExtractionException(); } } @@ -333,13 +317,12 @@ public class PgpSignEncrypt { // Asymmetric encryption for (long id : mEncryptionMasterKeyIds) { try { - PGPPublicKeyRing keyRing = mProviderHelper.getPGPPublicKeyRing(id); - PGPPublicKey key = PgpKeyHelper.getFirstEncryptSubkey(keyRing); - if (key != null) { - JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator = - new JcePublicKeyKeyEncryptionMethodGenerator(key); - cPk.addMethod(pubKeyEncryptionGenerator); - } + CachedPublicKeyRing keyRing = mProviderHelper.getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingUri(Long.toString(id))); + CachedPublicKey key = keyRing.getFirstEncryptSubkey(); + cPk.addMethod(key.getPubKeyEncryptionGenerator()); + } catch (PgpGeneralException e) { + Log.e(Constants.TAG, "key not found!", e); } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); } @@ -353,29 +336,18 @@ public class PgpSignEncrypt { if (enableSignature) { updateProgress(R.string.progress_preparing_signature, 10, 100); - // content signer based on signing key algorithm and chosen hash algorithm - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - signingKey.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - int signatureType; - if (mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption) { - // for sign-only ascii text - signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; - } else { - signatureType = PGPSignature.BINARY_DOCUMENT; - } - - if (mSignatureForceV3) { - signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder); - signatureV3Generator.init(signatureType, signaturePrivateKey); - } else { - signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(signatureType, signaturePrivateKey); - - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - spGen.setSignerUserID(false, signingUserId); - signatureGenerator.setHashedSubpackets(spGen.generate()); + try { + boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption; + if (mSignatureForceV3) { + signatureV3Generator = signingKey.getV3SignatureGenerator( + mSignatureHashAlgorithm,cleartext); + } else { + signatureGenerator = signingKey.getSignatureGenerator( + mSignatureHashAlgorithm, cleartext); + } + } catch (PgpGeneralException e) { + // TODO throw correct type of exception (which shouldn't be PGPException) + throw new KeyExtractionException(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index a4fa3dac9..a3c9fab1b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -110,6 +110,8 @@ public class KeychainContract { public static final String HAS_ANY_SECRET = "has_any_secret"; public static final String HAS_ENCRYPT = "has_encrypt"; public static final String HAS_SIGN = "has_sign"; + public static final String PUBKEY_DATA = "pubkey_data"; + public static final String PRIVKEY_DATA = "privkey_data"; public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() .appendPath(BASE_KEY_RINGS).build(); @@ -123,6 +125,10 @@ public class KeychainContract { return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build(); } + public static Uri buildGenericKeyRingUri(long masterKeyId) { + return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).build(); + } + public static Uri buildGenericKeyRingUri(String masterKeyId) { return CONTENT_URI.buildUpon().appendPath(masterKeyId).build(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 1dc822ac2..64dab3020 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -254,6 +254,12 @@ public class KeychainProvider extends ContentProvider { projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT); projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID); projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED); + projectionMap.put(KeyRings.PUBKEY_DATA, + Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.KEY_RING_DATA + + " AS " + KeyRings.PUBKEY_DATA); + projectionMap.put(KeyRings.PRIVKEY_DATA, + Tables.KEY_RINGS_SECRET + "." + KeyRingData.KEY_RING_DATA + + " AS " + KeyRings.PRIVKEY_DATA); projectionMap.put(KeyRings.HAS_SECRET, KeyRings.HAS_SECRET); projectionMap.put(KeyRings.HAS_ANY_SECRET, "(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET @@ -295,6 +301,22 @@ public class KeychainProvider extends ContentProvider { + " AND " + Tables.CERTS + "." + Certs.VERIFIED + " = " + Certs.VERIFIED_SECRET + ")" + // fairly expensive join (due to blob data), only do it when requested + + (Arrays.asList(projection).contains(KeyRings.PUBKEY_DATA) ? + " INNER JOIN " + Tables.KEY_RINGS_PUBLIC + " ON (" + + Tables.KEYS + "." + Keys.MASTER_KEY_ID + + " = " + + Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.MASTER_KEY_ID + + ")" + : "") + // fairly expensive join (due to blob data), only do it when requested + + (Arrays.asList(projection).contains(KeyRings.PRIVKEY_DATA) ? + " LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON (" + + Tables.KEYS + "." + Keys.MASTER_KEY_ID + + " = " + + Tables.KEY_RINGS_SECRET + "." + KeyRingData.MASTER_KEY_ID + + ")" + : "") ); qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0"); // in case there are multiple verifying certificates 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 214a9988c..80a3fe6e6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -36,9 +36,10 @@ import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; @@ -167,6 +168,7 @@ public class ProviderHelper { } } + @Deprecated public Map getPGPKeyRings(Uri queryUri) { Cursor cursor = mContentResolver.query(queryUri, new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA}, @@ -188,6 +190,94 @@ public class ProviderHelper { return result; } + public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws NotFoundException { + Cursor cursor = mContentResolver.query(queryUri, + new String[] { + KeyRings.MASTER_KEY_ID, KeyRings.KEY_SIZE, + KeyRings.IS_REVOKED, KeyRings.CAN_CERTIFY, + KeyRings.CREATION, KeyRings.EXPIRY, + KeyRings.ALGORITHM, KeyRings.FINGERPRINT, + KeyRings.USER_ID, KeyRings.VERIFIED, + KeyRings.HAS_SECRET, KeyRings.PUBKEY_DATA + }, null, null, null); + try { + if (cursor != null && cursor.moveToFirst()) { + long masterKeyId = cursor.getLong(0); + int keySize = cursor.getInt(1); + boolean isRevoked = cursor.getInt(2) > 0; + boolean canCertify = cursor.getInt(3) > 0; + long creation = cursor.getLong(4); + long expiry = cursor.getLong(5); + int algorithm = cursor.getInt(6); + byte[] fingerprint = cursor.getBlob(7); + String userId = cursor.getString(8); + int verified = cursor.getInt(9); + boolean hasSecret = cursor.getInt(10) > 0; + byte[] pubkey = cursor.getBlob(11); + return new CachedPublicKeyRing( + masterKeyId, keySize, isRevoked, canCertify, + creation, expiry, algorithm, fingerprint, + userId, verified, hasSecret, pubkey + ); + } else { + throw new NotFoundException("Key not found!"); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + public CachedSecretKeyRing getCachedSecretKeyRing(long id) throws NotFoundException { + return getCachedSecretKeyRing(KeyRings.buildUnifiedKeyRingUri(Long.toString(id))); + } + + public CachedSecretKeyRing getCachedSecretKeyRing(Uri queryUri) throws NotFoundException { + Cursor cursor = mContentResolver.query(queryUri, + new String[] { + KeyRings.MASTER_KEY_ID, KeyRings.KEY_SIZE, + KeyRings.IS_REVOKED, KeyRings.CAN_CERTIFY, + KeyRings.CREATION, KeyRings.EXPIRY, + KeyRings.ALGORITHM, KeyRings.FINGERPRINT, + KeyRings.USER_ID, KeyRings.VERIFIED, + KeyRings.HAS_SECRET, KeyRings.PRIVKEY_DATA + }, null, null, null); + try { + if (cursor != null && cursor.moveToFirst()) { + // check if a privkey is actually available + byte[] privkey = cursor.getBlob(11); + if(privkey == null) { + throw new NotFoundException("Key found, but no secret key available!"); + } + + long masterKeyId = cursor.getLong(0); + int keySize = cursor.getInt(1); + boolean isRevoked = cursor.getInt(2) > 0; + boolean canCertify = cursor.getInt(3) > 0; + long creation = cursor.getLong(4); + long expiry = cursor.getLong(5); + int algorithm = cursor.getInt(6); + byte[] fingerprint = cursor.getBlob(7); + String userId = cursor.getString(8); + int verified = cursor.getInt(9); + boolean hasSecret = cursor.getInt(10) > 0; + return new CachedSecretKeyRing( + masterKeyId, keySize, isRevoked, canCertify, + creation, expiry, algorithm, fingerprint, + userId, verified, hasSecret, privkey + ); + } else { + throw new NotFoundException("Key not found!"); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + @Deprecated public PGPKeyRing getPGPKeyRing(Uri queryUri) throws NotFoundException { Map result = getPGPKeyRings(queryUri); if (result.isEmpty()) { @@ -197,6 +287,7 @@ public class ProviderHelper { } } + @Deprecated public PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(long keyId) throws NotFoundException { Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)); @@ -204,6 +295,7 @@ public class ProviderHelper { return getPGPPublicKeyRing(masterKeyId); } + @Deprecated public PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(long keyId) throws NotFoundException { Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)); @@ -214,6 +306,7 @@ public class ProviderHelper { /** * Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId */ + @Deprecated public PGPPublicKeyRing getPGPPublicKeyRing(long masterKeyId) throws NotFoundException { Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)); return (PGPPublicKeyRing) getPGPKeyRing(queryUri); @@ -222,6 +315,7 @@ public class ProviderHelper { /** * Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId */ + @Deprecated public PGPSecretKeyRing getPGPSecretKeyRing(long masterKeyId) throws NotFoundException { Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)); return (PGPSecretKeyRing) getPGPKeyRing(queryUri); -- cgit v1.2.3 From c2c6a90991397929b024f726e4d515095e21d9a2 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 3 May 2014 15:59:25 +0200 Subject: certification is always done with the master key --- .../keychain/pgp/PgpKeyHelper.java | 55 ---------------------- .../keychain/service/KeychainIntentService.java | 2 +- 2 files changed, 1 insertion(+), 56 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index ecaeac7e7..e884c0e2f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -110,20 +110,6 @@ public class PgpKeyHelper { return null; } - @SuppressWarnings("unchecked") - @Deprecated - private static Vector getEncryptKeys(PGPPublicKeyRing keyRing) { - Vector encryptKeys = new Vector(); - - for (PGPPublicKey key : new IterableIterator(keyRing.getPublicKeys())) { - if (isEncryptionKey(key)) { - encryptKeys.add(key); - } - } - - return encryptKeys; - } - @SuppressWarnings("unchecked") @Deprecated private static Vector getSigningKeys(PGPSecretKeyRing keyRing) { @@ -138,39 +124,6 @@ public class PgpKeyHelper { return signingKeys; } - @SuppressWarnings("unchecked") - @Deprecated - private static Vector getCertificationKeys(PGPSecretKeyRing keyRing) { - Vector signingKeys = new Vector(); - - for (PGPSecretKey key : new IterableIterator(keyRing.getSecretKeys())) { - if (isCertificationKey(key)) { - signingKeys.add(key); - } - } - - return signingKeys; - } - - @Deprecated - private static Vector getUsableCertificationKeys(PGPSecretKeyRing keyRing) { - Vector usableKeys = new Vector(); - Vector signingKeys = getCertificationKeys(keyRing); - PGPSecretKey masterKey = null; - for (int i = 0; i < signingKeys.size(); ++i) { - PGPSecretKey key = signingKeys.get(i); - if (key.isMasterKey()) { - masterKey = key; - } else { - usableKeys.add(key); - } - } - if (masterKey != null) { - usableKeys.add(masterKey); - } - return usableKeys; - } - @Deprecated private static Vector getUsableSigningKeys(PGPSecretKeyRing keyRing) { Vector usableKeys = new Vector(); @@ -190,14 +143,6 @@ public class PgpKeyHelper { return usableKeys; } - public static PGPSecretKey getFirstCertificationSubkey(PGPSecretKeyRing keyRing) { - Vector signingKeys = getUsableCertificationKeys(keyRing); - if (signingKeys.size() == 0) { - return null; - } - return signingKeys.get(0); - } - public static PGPSecretKey getFirstSigningSubkey(PGPSecretKeyRing keyRing) { Vector signingKeys = getUsableSigningKeys(keyRing); if (signingKeys.size() == 0) { 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 5615b59c4..99d12ee8b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -836,7 +836,7 @@ public class KeychainIntentService extends IntentService Log.e(Constants.TAG, "key not found!", e); // TODO: throw exception here! } - PGPSecretKey certificationKey = PgpKeyHelper.getFirstCertificationSubkey(secretKeyRing); + PGPSecretKey certificationKey = secretKeyRing.getSecretKey(); publicKey = keyOperation.certifyKey(certificationKey, publicKey, userIds, signaturePassphrase); publicRing = PGPPublicKeyRing.insertPublicKey(publicRing, publicKey); -- cgit v1.2.3 From 1f8210f743687063a36da03ba327fa6a534280fa Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 3 May 2014 18:32:20 +0200 Subject: wrapped-key-ring: move certification logic into secretkey --- .../keychain/pgp/CachedPublicKeyRing.java | 7 ++- .../keychain/pgp/CachedSecretKey.java | 58 ++++++++++++++++++ .../keychain/pgp/CachedSecretKeyRing.java | 6 +- .../keychain/pgp/PgpImportExport.java | 69 +++++++++------------- .../keychain/pgp/PgpKeyOperation.java | 53 ----------------- .../keychain/provider/ProviderHelper.java | 4 ++ .../keychain/service/KeychainIntentService.java | 46 ++++++--------- 7 files changed, 118 insertions(+), 125 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java index fb142adce..3a45b4ff9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java @@ -36,7 +36,7 @@ public class CachedPublicKeyRing extends CachedKeyRing { mPubKey = pubkey; } - private PGPPublicKeyRing getRing() { + PGPPublicKeyRing getRing() { if(mRing == null) { mRing = (PGPPublicKeyRing) PgpConversionHelper.BytesToPGPKeyRing(mPubKey); } @@ -47,6 +47,10 @@ public class CachedPublicKeyRing extends CachedKeyRing { getRing().encode(stream); } + public CachedPublicKey getSubkey() { + return new CachedPublicKey(this, getRing().getPublicKey()); + } + public CachedPublicKey getSubkey(long id) { return new CachedPublicKey(this, getRing().getPublicKey(id)); } @@ -128,7 +132,6 @@ public class CachedPublicKeyRing extends CachedKeyRing { } - static boolean isEncryptionKey(PGPPublicKey key) { if (!key.isEncryptionKey()) { return false; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java index 514fca6fb..ea302ea0b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java @@ -2,10 +2,14 @@ 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; @@ -14,6 +18,13 @@ import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SignatureException; +import java.util.List; public class CachedSecretKey { @@ -113,6 +124,53 @@ public class CachedSecretKey { .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(CachedPublicKeyRing 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( + mKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + + signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); + signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey); + } + + { // supply signatureGenerator with a SubpacketVector + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + PGPSignatureSubpacketVector packetVector = spGen.generate(); + signatureGenerator.setHashedSubpackets(packetVector); + } + + // get the master subkey (which we certify for) + PGPPublicKey publicKey = publicKeyRing.getSubkey().getKey(); + + // 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() diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java index a2b2b2832..5403e1510 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java @@ -23,7 +23,11 @@ public class CachedSecretKeyRing extends CachedKeyRing { mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob); } - CachedSecretKey getSubKey(long id) { + public CachedSecretKey getSubKey() { + return new CachedSecretKey(this, mRing.getSecretKey()); + } + + public CachedSecretKey getSubKey(long id) { return new CachedSecretKey(this, mRing.getSecretKey(id)); } 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 6aeb19e65..6de958d8d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -97,12 +97,12 @@ public class PgpImportExport { } } - public boolean uploadKeyRingToServer(HkpKeyServer server, PGPPublicKeyRing keyring) { + public boolean uploadKeyRingToServer(HkpKeyServer server, CachedPublicKeyRing keyring) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ArmoredOutputStream aos = null; try { aos = new ArmoredOutputStream(bos); - aos.write(keyring.getEncoded()); + keyring.encode(aos); aos.close(); String armoredKey = bos.toString("UTF-8"); @@ -147,8 +147,25 @@ public class PgpImportExport { if (obj instanceof PGPKeyRing) { PGPKeyRing keyring = (PGPKeyRing) obj; - - int status = storeKeyRingInCache(keyring); + int status; + // TODO Better try to get this one from the db first! + if(keyring instanceof PGPSecretKeyRing) { + PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring; + // TODO: preserve certifications + // (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?) + PGPPublicKeyRing newPubRing = null; + for (PGPPublicKey key : new IterableIterator( + secretKeyRing.getPublicKeys())) { + if (newPubRing == null) { + newPubRing = new PGPPublicKeyRing(key.getEncoded(), + new JcaKeyFingerprintCalculator()); + } + newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key); + } + status = storeKeyRingInCache(new UncachedKeyRing(newPubRing ,secretKeyRing)); + } else { + status = storeKeyRingInCache(new UncachedKeyRing((PGPPublicKeyRing) keyring)); + } if (status == RETURN_ERROR) { throw new PgpGeneralException( @@ -259,44 +276,16 @@ public class PgpImportExport { } @SuppressWarnings("unchecked") - public int storeKeyRingInCache(PGPKeyRing keyring) { + public int storeKeyRingInCache(UncachedKeyRing keyring) { int status = RETURN_ERROR; try { - if (keyring instanceof PGPSecretKeyRing) { - PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring; - boolean save = true; - - for (PGPSecretKey testSecretKey : new IterableIterator( - secretKeyRing.getSecretKeys())) { - if (!testSecretKey.isMasterKey()) { - if (testSecretKey.isPrivateKeyEmpty()) { - // this is bad, something is very wrong... - save = false; - status = RETURN_BAD; - } - } - } - - if (save) { - // TODO: preserve certifications - // (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?) - PGPPublicKeyRing newPubRing = null; - for (PGPPublicKey key : new IterableIterator( - secretKeyRing.getPublicKeys())) { - if (newPubRing == null) { - newPubRing = new PGPPublicKeyRing(key.getEncoded(), - new JcaKeyFingerprintCalculator()); - } - newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key); - } - if (newPubRing != null) { - mProviderHelper.saveKeyRing(newPubRing); - } - mProviderHelper.saveKeyRing(secretKeyRing); - status = RETURN_OK; - } - } else if (keyring instanceof PGPPublicKeyRing) { - PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring; + PGPSecretKeyRing secretKeyRing = keyring.getSecretRing(); + PGPPublicKeyRing publicKeyRing = keyring.getPublicRing(); + // see what type we have. we can either have a secret + public keyring, or just public + if (secretKeyRing != null) { + mProviderHelper.saveKeyRing(publicKeyRing, secretKeyRing); + status = RETURN_OK; + } else { mProviderHelper.saveKeyRing(publicKeyRing); status = RETURN_OK; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 9dd9f660b..2033a91e7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -690,59 +690,6 @@ public class PgpKeyOperation { } - /** - * Certify the given pubkeyid with the given masterkeyid. - * - * @param certificationKey Certifying key - * @param publicKey public key to certify - * @param userIds User IDs to certify, must not be null or empty - * @param passphrase Passphrase of the secret key - * @return A keyring with added certifications - */ - public PGPPublicKey certifyKey(PGPSecretKey certificationKey, PGPPublicKey publicKey, - List userIds, String passphrase) - throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException, - PGPException, SignatureException { - - // create a signatureGenerator from the supplied masterKeyId and passphrase - PGPSignatureGenerator signatureGenerator; - { - - if (certificationKey == null) { - throw new PgpGeneralMsgIdException(R.string.error_no_signature_key); - } - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); - PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor); - if (signaturePrivateKey == null) { - throw new PgpGeneralMsgIdException(R.string.error_could_not_extract_private_key); - } - - // TODO: SHA256 fixed? - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - certificationKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, signaturePrivateKey); - } - - { // supply signatureGenerator with a SubpacketVector - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - PGPSignatureSubpacketVector packetVector = spGen.generate(); - signatureGenerator.setHashedSubpackets(packetVector); - } - - // fetch public key ring, add the certification and return it - for (String userId : new IterableIterator(userIds.iterator())) { - PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); - publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); - } - - return publicKey; - } - /** * Simple static subclass that stores two values. *

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 80a3fe6e6..0fe989e84 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -190,6 +190,10 @@ public class ProviderHelper { return result; } + public CachedPublicKeyRing getCachedPublicKeyRing(long id) throws NotFoundException { + return getCachedPublicKeyRing(KeyRings.buildUnifiedKeyRingUri(Long.toString(id))); + } + public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws NotFoundException { Cursor cursor = mContentResolver.query(queryUri, new String[] { 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 99d12ee8b..d02906c4f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -29,7 +29,6 @@ import android.os.RemoteException; import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; @@ -39,6 +38,9 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.CachedSecretKey; +import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; @@ -48,6 +50,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; 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.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -648,10 +651,8 @@ public class KeychainIntentService extends IntentService try { List entries = data.getParcelableArrayList(IMPORT_KEY_LIST); - Bundle resultData = new Bundle(); - PgpImportExport pgpImportExport = new PgpImportExport(this, this); - resultData = pgpImportExport.importKeyRings(entries); + Bundle resultData = pgpImportExport.importKeyRings(entries); sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); } catch (Exception e) { @@ -724,15 +725,12 @@ public class KeychainIntentService extends IntentService HkpKeyServer server = new HkpKeyServer(keyServer); ProviderHelper providerHelper = new ProviderHelper(this); - PGPPublicKeyRing keyring = (PGPPublicKeyRing) providerHelper.getPGPKeyRing(dataUri); - if (keyring != null) { - PgpImportExport pgpImportExport = new PgpImportExport(this, null); - - boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, - (PGPPublicKeyRing) keyring); - if (!uploaded) { - throw new PgpGeneralException("Unable to export key to selected server"); - } + CachedPublicKeyRing keyring = providerHelper.getCachedPublicKeyRing(dataUri); + PgpImportExport pgpImportExport = new PgpImportExport(this, null); + + boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, keyring); + if (!uploaded) { + throw new PgpGeneralException("Unable to export key to selected server"); } sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); @@ -795,7 +793,6 @@ public class KeychainIntentService extends IntentService entry.setBytes(downloadedKey.getEncoded()); } - Intent importIntent = new Intent(this, KeychainIntentService.class); importIntent.setAction(ACTION_IMPORT_KEYRING); Bundle importData = new Bundle(); @@ -826,24 +823,15 @@ public class KeychainIntentService extends IntentService } ProviderHelper providerHelper = new ProviderHelper(this); - PgpKeyOperation keyOperation = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); - PGPPublicKeyRing publicRing = providerHelper.getPGPPublicKeyRing(pubKeyId); - PGPPublicKey publicKey = publicRing.getPublicKey(pubKeyId); - PGPSecretKeyRing secretKeyRing = null; - try { - secretKeyRing = providerHelper.getPGPSecretKeyRing(masterKeyId); - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - // TODO: throw exception here! - } - PGPSecretKey certificationKey = secretKeyRing.getSecretKey(); - publicKey = keyOperation.certifyKey(certificationKey, publicKey, - userIds, signaturePassphrase); - publicRing = PGPPublicKeyRing.insertPublicKey(publicRing, publicKey); + CachedPublicKeyRing publicRing = providerHelper.getCachedPublicKeyRing(pubKeyId); + CachedSecretKeyRing secretKeyRing = providerHelper.getCachedSecretKeyRing(masterKeyId); + CachedSecretKey certificationKey = secretKeyRing.getSubKey(); + certificationKey.unlock(signaturePassphrase); + UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds); // store the signed key in our local cache PgpImportExport pgpImportExport = new PgpImportExport(this, null); - int retval = pgpImportExport.storeKeyRingInCache(publicRing); + int retval = pgpImportExport.storeKeyRingInCache(newRing); if (retval != PgpImportExport.RETURN_OK && retval != PgpImportExport.RETURN_UPDATED) { throw new PgpGeneralException("Failed to store signed key in local cache"); } -- cgit v1.2.3 From 2176e1ef1c29ca4549b256745c26c871503fe5ce Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 3 May 2014 19:04:23 +0200 Subject: wrapped-key-ring: move more helper methods into keys --- .../keychain/pgp/CachedPublicKey.java | 108 ++++++++++++++++++++- .../keychain/pgp/CachedSecretKey.java | 22 ++--- .../keychain/pgp/CachedSecretKeyRing.java | 35 +++++++ .../keychain/pgp/PgpKeyHelper.java | 1 + .../keychain/service/PassphraseCacheService.java | 2 + 5 files changed, 153 insertions(+), 15 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java index fb065c85f..08b9d5a0c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java @@ -1,26 +1,128 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPOnePassSignature; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; public class CachedPublicKey { // this is the parent key ring - private final CachedPublicKeyRing mRing; + final CachedKeyRing mRing; private final PGPPublicKey mKey; - CachedPublicKey(CachedPublicKeyRing ring, PGPPublicKey key) { + CachedPublicKey(CachedKeyRing ring, PGPPublicKey key) { mRing = ring; mKey = key; } - public CachedPublicKeyRing getKeyRing() { + public long getKeyId() { + return mKey.getKeyID(); + } + + public Date getCreationTime() { + return mKey.getCreationTime(); + } + + public Date getExpiryTime() { + Date creationDate = getCreationTime(); + if (mKey.getValidDays() == 0) { + // no expiry + return null; + } + Calendar calendar = GregorianCalendar.getInstance(); + calendar.setTime(creationDate); + calendar.add(Calendar.DATE, mKey.getValidDays()); + + return calendar.getTime(); + } + + public boolean isMasterKey() { + return mKey.isMasterKey(); + } + + public int getAlgorithm() { + return mKey.getAlgorithm(); + } + + public IterableIterator getUserIds() { + return new IterableIterator(mKey.getUserIDs()); + } + + private Integer mCacheUsage = null; + @SuppressWarnings("unchecked") + public int getKeyUsage() { + if(mCacheUsage == null) { + mCacheUsage = 0; + if (mKey.getVersion() >= 4) { + for (PGPSignature sig : new IterableIterator(mKey.getSignatures())) { + if (mKey.isMasterKey() && sig.getKeyID() != mKey.getKeyID()) { + continue; + } + + PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); + if (hashed != null) { + mCacheUsage |= hashed.getKeyFlags(); + } + + PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); + if (unhashed != null) { + mCacheUsage |= unhashed.getKeyFlags(); + } + } + } + } + return mCacheUsage; + } + + public boolean canAuthenticate() { + return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.AUTHENTICATION) != 0; + } + + public boolean canCertify() { + return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.CERTIFY_OTHER) != 0; + } + + public boolean canEncrypt() { + if (!mKey.isEncryptionKey()) { + return false; + } + + // special cases + if (mKey.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) { + return true; + } + + if (mKey.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) { + return true; + } + + return mKey.getVersion() <= 3 || + (getKeyUsage() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0; + + } + + public boolean canSign() { + // special case + if (mKey.getAlgorithm() == PGPPublicKey.RSA_SIGN) { + return true; + } + + return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.SIGN_DATA) != 0; + } + + public CachedKeyRing getKeyRing() { return mRing; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java index ea302ea0b..d0b18d757 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java @@ -1,5 +1,6 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPublicKey; @@ -26,28 +27,25 @@ import java.security.NoSuchProviderException; import java.security.SignatureException; import java.util.List; -public class CachedSecretKey { +public class CachedSecretKey extends CachedPublicKey { - // this is the parent key ring - private final CachedSecretKeyRing mRing; - - private final PGPSecretKey mKey; + private final PGPSecretKey mSecretKey; private PGPPrivateKey mPrivateKey = null; CachedSecretKey(CachedSecretKeyRing ring, PGPSecretKey key) { - mRing = ring; - mKey = key; + super(ring, key.getPublicKey()); + mSecretKey = key; } public CachedSecretKeyRing getRing() { - return mRing; + return (CachedSecretKeyRing) mRing; } public void unlock(String passphrase) throws PgpGeneralException { try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); - mPrivateKey = mKey.extractPrivateKey(keyDecryptor); + mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor); } catch (PGPException e) { throw new PgpGeneralException("error extracting key!", e); } @@ -64,7 +62,7 @@ public class CachedSecretKey { // content signer based on signing key algorithm and chosen hash algorithm JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - mKey.getPublicKey().getAlgorithm(), hashAlgo) + mSecretKey.getPublicKey().getAlgorithm(), hashAlgo) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); int signatureType; @@ -96,7 +94,7 @@ public class CachedSecretKey { // content signer based on signing key algorithm and chosen hash algorithm JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - mKey.getPublicKey().getAlgorithm(), hashAlgo) + mSecretKey.getPublicKey().getAlgorithm(), hashAlgo) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); int signatureType; @@ -144,7 +142,7 @@ public class CachedSecretKey { { // TODO: SHA256 fixed? JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - mKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) + mSecretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java index 5403e1510..097f530fd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java @@ -1,13 +1,19 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.sufficientlysecure.keychain.util.IterableIterator; +import java.util.Iterator; + public class CachedSecretKeyRing extends CachedKeyRing { private PGPSecretKeyRing mRing; @@ -31,6 +37,35 @@ public class CachedSecretKeyRing extends CachedKeyRing { return new CachedSecretKey(this, mRing.getSecretKey(id)); } + public IterableIterator iterator() { + return new IterableIterator(mRing.getSecretKeys()); + } + + 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; + } + } + /** This returns the subkey that should be used for signing. * At this point, this is simply the first suitable subkey. */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index e884c0e2f..5e78a5764 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -143,6 +143,7 @@ public class PgpKeyHelper { return usableKeys; } + @Deprecated public static PGPSecretKey getFirstSigningSubkey(PGPSecretKeyRing keyRing) { Vector signingKeys = getUsableSigningKeys(keyRing); if (signingKeys.size() == 0) { 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 db4fecef0..88e974288 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -197,6 +197,7 @@ public class PassphraseCacheService extends Service { return cachedPassphrase; } + @Deprecated public static boolean hasPassphrase(PGPSecretKeyRing secretKeyRing) { PGPSecretKey secretKey = null; boolean foundValidKey = false; @@ -228,6 +229,7 @@ public class PassphraseCacheService extends Service { * @param secretKeyId * @return true if it has a passphrase */ + @Deprecated public static boolean hasPassphrase(Context context, long secretKeyId) { // check if the key has no passphrase try { -- cgit v1.2.3 From ef6211e0bd380c4f6bca28cda327cfbe4c57a21e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 3 May 2014 19:05:03 +0200 Subject: wrapped-key-ring: forgot to add UncachedKeyRing class --- .../keychain/pgp/UncachedKeyRing.java | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java new file mode 100644 index 000000000..86a2ed48d --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -0,0 +1,29 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; + +public class UncachedKeyRing { + + final PGPPublicKeyRing mPublicRing; + final PGPSecretKeyRing mSecretRing; + + UncachedKeyRing(PGPPublicKeyRing publicRing, PGPSecretKeyRing secretRing) { + // this one must not be false! + assert(publicRing != null); + mPublicRing = publicRing; + mSecretRing = secretRing; + } + + UncachedKeyRing(PGPPublicKeyRing publicRing) { + this(publicRing, null); + } + + public PGPPublicKeyRing getPublicRing() { + return mPublicRing; + } + + public PGPSecretKeyRing getSecretRing() { + return mSecretRing; + } +} -- cgit v1.2.3 From 32baf425151b32bca7ce8db97b732bce44238c81 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 3 May 2014 19:14:30 +0200 Subject: wrapped-key-ring: small fix to make it work again --- .../keychain/pgp/CachedKeyRing.java | 4 ---- .../keychain/pgp/PgpDecryptVerify.java | 22 ++++++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java index 5cf89b6a6..9e5671a97 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java @@ -54,8 +54,4 @@ public abstract class CachedKeyRing { return mVerified; } - public void initSignature(PGPSignature sig) { - - } - } 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 c84b9413f..37dfee8b9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -366,6 +366,7 @@ public class PgpDecryptVerify { Object dataChunk = plainFact.nextObject(); OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); int signatureIndex = -1; + CachedPublicKeyRing signingRing = null; CachedPublicKey signingKey = null; if (dataChunk instanceof PGPCompressedData) { @@ -390,7 +391,7 @@ public class PgpDecryptVerify { for (int i = 0; i < sigList.size(); ++i) { try { long sigKeyId = sigList.get(i).getKeyID(); - CachedPublicKeyRing signingRing = mProviderHelper.getCachedPublicKeyRing( + signingRing = mProviderHelper.getCachedPublicKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( Long.toString(sigKeyId) ) @@ -409,9 +410,9 @@ public class PgpDecryptVerify { signatureResultBuilder.signatureAvailable(true); signatureResultBuilder.knownKey(true); - signatureResultBuilder.keyId(signingKey.getKeyRing().getMasterKeyId()); - signatureResultBuilder.userId(signingKey.getKeyRing().getPrimaryUserId()); - signatureResultBuilder.signatureKeyCertified(signingKey.getKeyRing().getVerified() > 0); + signatureResultBuilder.keyId(signingRing.getMasterKeyId()); + signatureResultBuilder.userId(signingRing.getPrimaryUserId()); + signatureResultBuilder.signatureKeyCertified(signingRing.getVerified() > 0); signingKey.initSignature(signature); } else { @@ -488,7 +489,7 @@ public class PgpDecryptVerify { // Verify signature and check binding signatures boolean validSignature = signature.verify(messageSignature); - boolean validKeyBinding = signingKey.getKeyRing().verifySubkeyBinding(signingKey); + boolean validKeyBinding = signingRing.verifySubkeyBinding(signingKey); signatureResultBuilder.validSignature(validSignature); signatureResultBuilder.validKeyBinding(validKeyBinding); @@ -564,6 +565,7 @@ public class PgpDecryptVerify { throw new InvalidDataException(); } + CachedPublicKeyRing signingRing = null; CachedPublicKey signingKey = null; int signatureIndex = -1; @@ -572,7 +574,7 @@ public class PgpDecryptVerify { for (int i = 0; i < sigList.size(); ++i) { try { long sigKeyId = sigList.get(i).getKeyID(); - CachedPublicKeyRing signingRing = mProviderHelper.getCachedPublicKeyRing( + signingRing = mProviderHelper.getCachedPublicKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( Long.toString(sigKeyId) ) @@ -593,9 +595,9 @@ public class PgpDecryptVerify { signatureResultBuilder.signatureAvailable(true); signatureResultBuilder.knownKey(true); - signatureResultBuilder.keyId(signingKey.getKeyRing().getMasterKeyId()); - signatureResultBuilder.userId(signingKey.getKeyRing().getPrimaryUserId()); - signatureResultBuilder.signatureKeyCertified(signingKey.getKeyRing().getVerified() > 0); + signatureResultBuilder.keyId(signingRing.getMasterKeyId()); + signatureResultBuilder.userId(signingRing.getPrimaryUserId()); + signatureResultBuilder.signatureKeyCertified(signingRing.getVerified() > 0); signingKey.initSignature(signature); } else { @@ -629,7 +631,7 @@ public class PgpDecryptVerify { // Verify signature and check binding signatures boolean validSignature = signature.verify(); - boolean validKeyBinding = signingKey.getKeyRing().verifySubkeyBinding(signingKey); + boolean validKeyBinding = signingRing.verifySubkeyBinding(signingKey); signatureResultBuilder.validSignature(validSignature); signatureResultBuilder.validKeyBinding(validKeyBinding); -- cgit v1.2.3 From f524fa692c8ab9bd737f7b03a5104ff2b2867669 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 3 May 2014 22:29:09 +0200 Subject: wrapped-key-ring: more refactoring - no more pgp imports in KeychainIntentService! --- .../keychain/pgp/CachedKeyRing.java | 28 +++---- .../keychain/pgp/CachedPublicKey.java | 13 ++++ .../keychain/pgp/CachedPublicKeyRing.java | 86 +++++++--------------- .../keychain/pgp/CachedSecretKeyRing.java | 35 ++++++++- .../keychain/pgp/PgpConversionHelper.java | 32 -------- .../keychain/pgp/PgpImportExport.java | 2 +- .../keychain/pgp/PgpKeyHelper.java | 54 -------------- .../keychain/pgp/PgpKeyOperation.java | 52 ++++--------- .../keychain/pgp/UncachedKeyRing.java | 35 ++++++++- .../keychain/pgp/UncachedSecretKeyRing.java | 19 +++++ .../keychain/provider/ProviderHelper.java | 20 ++++- .../keychain/service/KeychainIntentService.java | 79 +++++++------------- .../keychain/ui/EncryptAsymmetricFragment.java | 22 +++--- 13 files changed, 208 insertions(+), 269 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java index 9e5671a97..334f676c4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java @@ -1,44 +1,26 @@ package org.sufficientlysecure.keychain.pgp; -import org.spongycastle.openpgp.PGPSignature; - public abstract class CachedKeyRing { private final long mMasterKeyId; - private final int mKeySize; - private final boolean mIsRevoked; private final boolean mCanCertify; - private final long mCreation; - private final long mExpiry; - private final int mAlgorithm; private final byte[] mFingerprint; private final String mUserId; private final int mVerified; private final boolean mHasSecret; - protected CachedKeyRing(long masterKeyId, int keySize, boolean isRevoked, - boolean canCertify, long creation, long expiry, int algorithm, + protected CachedKeyRing(long masterKeyId, boolean canCertify, byte[] fingerprint, String userId, int verified, boolean hasSecret) { mMasterKeyId = masterKeyId; - mKeySize = keySize; - mIsRevoked = isRevoked; mCanCertify = canCertify; - mCreation = creation; - mExpiry = expiry; - mAlgorithm = algorithm; mFingerprint = fingerprint; mUserId = userId; mVerified = verified; mHasSecret = hasSecret; } - public boolean isRevoked() { - return mIsRevoked; - } - public byte[] getFingerprint() { - return mFingerprint; } @@ -54,4 +36,12 @@ public abstract class CachedKeyRing { return mVerified; } + public boolean canCertify() { + return mCanCertify; + } + + public boolean hasSecret() { + return mHasSecret; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java index 08b9d5a0c..2862b21c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java @@ -31,6 +31,10 @@ public class CachedPublicKey { return mKey.getKeyID(); } + public boolean isRevoked() { + return mKey.isRevoked(); + } + public Date getCreationTime() { return mKey.getCreationTime(); } @@ -48,6 +52,15 @@ public class CachedPublicKey { return calendar.getTime(); } + public boolean isExpired() { + Date creationDate = mKey.getCreationTime(); + Date expiryDate = mKey.getValidSeconds() > 0 + ? new Date(creationDate.getTime() + mKey.getValidSeconds() * 1000) : null; + + Date now = new Date(); + return creationDate.after(now) || (expiryDate != null && expiryDate.before(now)); + } + public boolean isMasterKey() { return mKey.isMasterKey(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java index 3a45b4ff9..8970d18ec 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java @@ -2,7 +2,6 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; @@ -17,7 +16,6 @@ import org.sufficientlysecure.keychain.util.IterableIterator; import java.io.IOException; import java.security.SignatureException; import java.util.Arrays; -import java.util.Date; import java.util.Iterator; public class CachedPublicKeyRing extends CachedKeyRing { @@ -30,8 +28,7 @@ public class CachedPublicKeyRing extends CachedKeyRing { byte[] fingerprint, String userId, int verified, boolean hasSecret, byte[] pubkey) { - super(masterKeyId, keySize, isRevoked, canCertify, creation, expiry, - algorithm, fingerprint, userId, verified, hasSecret); + super(masterKeyId, canCertify, fingerprint, userId, verified, hasSecret); mPubKey = pubkey; } @@ -55,24 +52,46 @@ public class CachedPublicKeyRing extends CachedKeyRing { return new CachedPublicKey(this, getRing().getPublicKey(id)); } + public CachedPublicKey getFirstSignSubkey() throws PgpGeneralException { + // only return master key if no other signing key is available + CachedPublicKey masterKey = null; + for (PGPPublicKey k : new IterableIterator(getRing().getPublicKeys())) { + CachedPublicKey key = new CachedPublicKey(this, k); + if (key.isRevoked() || key.canSign() || key.isExpired()) { + continue; + } + if (key.isMasterKey()) { + masterKey = key; + } else { + return key; + } + } + if(masterKey == null) { + // TODO proper exception + throw new PgpGeneralException("key not found"); + } + return masterKey; + } + public CachedPublicKey getFirstEncryptSubkey() throws PgpGeneralException { // only return master key if no other encryption key is available - PGPPublicKey masterKey = null; - for (PGPPublicKey key : new IterableIterator(getRing().getPublicKeys())) { - if (key.isRevoked() || !isEncryptionKey(key) || isExpired(key)) { + CachedPublicKey masterKey = null; + for (PGPPublicKey k : new IterableIterator(getRing().getPublicKeys())) { + CachedPublicKey key = new CachedPublicKey(this, k); + if (key.isRevoked() || key.canEncrypt() || key.isExpired()) { continue; } if (key.isMasterKey()) { masterKey = key; } else { - return new CachedPublicKey(this, key); + return key; } } if(masterKey == null) { // TODO proper exception throw new PgpGeneralException("key not found"); } - return new CachedPublicKey(this, masterKey); + return masterKey; } public boolean verifySubkeyBinding(CachedPublicKey cachedSubkey) { @@ -132,55 +151,6 @@ public class CachedPublicKeyRing extends CachedKeyRing { } - static boolean isEncryptionKey(PGPPublicKey key) { - if (!key.isEncryptionKey()) { - return false; - } - - if (key.getVersion() <= 3) { - // this must be true now - return key.isEncryptionKey(); - } - - // special cases - if (key.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) { - return true; - } - - if (key.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) { - return true; - } - - for (PGPSignature sig : new IterableIterator(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - - if (hashed != null - && (hashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) { - return true; - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - - if (unhashed != null - && (unhashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) { - return true; - } - } - return false; - } - - static boolean isExpired(PGPPublicKey key) { - Date creationDate = key.getCreationTime(); - Date expiryDate = key.getValidSeconds() > 0 - ? new Date(creationDate.getTime() + key.getValidSeconds() * 1000) : null; - - Date now = new Date(); - return creationDate.after(now) || (expiryDate != null && expiryDate.before(now)); - } - static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java index 097f530fd..590a02b95 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java @@ -9,9 +9,14 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; +import java.io.IOException; +import java.security.NoSuchProviderException; import java.util.Iterator; public class CachedSecretKeyRing extends CachedKeyRing { @@ -23,12 +28,15 @@ public class CachedSecretKeyRing extends CachedKeyRing { byte[] fingerprint, String userId, int verified, boolean hasSecret, byte[] blob) { - super(masterKeyId, keySize, isRevoked, canCertify, creation, expiry, - algorithm, fingerprint, userId, verified, hasSecret); + super(masterKeyId, canCertify, fingerprint, userId, verified, hasSecret); mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob); } + PGPSecretKeyRing getRing() { + return mRing; + } + public CachedSecretKey getSubKey() { return new CachedSecretKey(this, mRing.getSecretKey()); } @@ -110,4 +118,27 @@ public class CachedSecretKeyRing extends CachedKeyRing { return false; } + public UncachedSecretKeyRing changeSecretKeyPassphrase(String oldPassphrase, + String newPassphrase) + throws IOException, PGPException, NoSuchProviderException { + + if (oldPassphrase == null) { + oldPassphrase = ""; + } + if (newPassphrase == null) { + newPassphrase = ""; + } + + PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword( + mRing, + new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()), + new JcePBESecretKeyEncryptorBuilder(mRing.getSecretKey() + .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray())); + + return new UncachedSecretKeyRing(newKeyRing); + + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java index 86fba979c..2199047cd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java @@ -165,36 +165,4 @@ public class PgpConversionHelper { return os.toByteArray(); } - /** - * Convert from PGPSecretKey to byte[] - * - * @param key - * @return - */ - public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) { - try { - return key.getEncoded(); - } catch (IOException e) { - Log.e(Constants.TAG, "Encoding failed", e); - - return null; - } - } - - /** - * Convert from PGPSecretKeyRing to byte[] - * - * @param keyRing - * @return - */ - public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) { - try { - return keyRing.getEncoded(); - } catch (IOException e) { - Log.e(Constants.TAG, "Encoding failed", e); - - return null; - } - } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index 6de958d8d..a7e1bd603 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -277,7 +277,7 @@ public class PgpImportExport { @SuppressWarnings("unchecked") public int storeKeyRingInCache(UncachedKeyRing keyring) { - int status = RETURN_ERROR; + int status; try { PGPSecretKeyRing secretKeyRing = keyring.getSecretRing(); PGPPublicKeyRing publicKeyRing = keyring.getPublicRing(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index 5e78a5764..e888d594e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -81,18 +81,6 @@ public class PgpKeyHelper { return getExpiryDate(key.getPublicKey()); } - @Deprecated - public static boolean isExpired(PGPPublicKey key) { - Date creationDate = getCreationDate(key); - Date expiryDate = getExpiryDate(key); - Date now = new Date(); - if (now.compareTo(creationDate) >= 0 - && (expiryDate == null || now.compareTo(expiryDate) <= 0)) { - return false; - } - return true; - } - @SuppressWarnings("unchecked") @Deprecated public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) { @@ -110,48 +98,6 @@ public class PgpKeyHelper { return null; } - @SuppressWarnings("unchecked") - @Deprecated - private static Vector getSigningKeys(PGPSecretKeyRing keyRing) { - Vector signingKeys = new Vector(); - - for (PGPSecretKey key : new IterableIterator(keyRing.getSecretKeys())) { - if (isSigningKey(key)) { - signingKeys.add(key); - } - } - - return signingKeys; - } - - @Deprecated - private static Vector getUsableSigningKeys(PGPSecretKeyRing keyRing) { - Vector usableKeys = new Vector(); - Vector signingKeys = getSigningKeys(keyRing); - PGPSecretKey masterKey = null; - for (int i = 0; i < signingKeys.size(); ++i) { - PGPSecretKey key = signingKeys.get(i); - if (key.isMasterKey()) { - masterKey = key; - } else { - usableKeys.add(key); - } - } - if (masterKey != null) { - usableKeys.add(masterKey); - } - return usableKeys; - } - - @Deprecated - public static PGPSecretKey getFirstSigningSubkey(PGPSecretKeyRing keyRing) { - Vector signingKeys = getUsableSigningKeys(keyRing); - if (signingKeys.size() == 0) { - return null; - } - return signingKeys.get(0); - } - public static int getKeyUsage(PGPSecretKey key) { return getKeyUsage(key.getPublicKey()); } 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 2033a91e7..7251709e0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -35,7 +35,6 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureGenerator; import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; @@ -48,10 +47,8 @@ import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; -import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Primes; import java.io.IOException; @@ -66,7 +63,6 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Iterator; -import java.util.List; import java.util.TimeZone; /** @@ -124,7 +120,7 @@ public class PgpKeyOperation { */ // TODO: key flags? - public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase, + public byte[] createKey(int algorithmChoice, int keySize, String passphrase, boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, PgpGeneralMsgIdException, InvalidAlgorithmParameterException { @@ -188,35 +184,15 @@ public class PgpKeyOperation { PGPEncryptedData.CAST5, sha1Calc) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); - return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), - sha1Calc, isMasterKey, keyEncryptor); - } - - public PGPSecretKeyRing changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassphrase, - String newPassphrase) - throws IOException, PGPException, NoSuchProviderException { - - updateProgress(R.string.progress_building_key, 0, 100); - if (oldPassphrase == null) { - oldPassphrase = ""; - } - if (newPassphrase == null) { - newPassphrase = ""; + try { + return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), + sha1Calc, isMasterKey, keyEncryptor).getEncoded(); + } catch(IOException e) { + throw new PgpGeneralMsgIdException(R.string.error_encoding); } - - PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword( - keyRing, - new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()), - new JcePBESecretKeyEncryptorBuilder(keyRing.getSecretKey() - .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray())); - - return newKeyRing; - } - public Pair buildNewSecretKey( + public UncachedKeyRing buildNewSecretKey( SaveKeyringParcel saveParcel) throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { @@ -357,17 +333,19 @@ public class PgpKeyOperation { PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing(); PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing(); - return new Pair(secretKeyRing, publicKeyRing); + return new UncachedKeyRing(publicKeyRing, secretKeyRing); } - public Pair buildSecretKey(PGPSecretKeyRing mKR, - PGPPublicKeyRing pKR, + public UncachedKeyRing buildSecretKey(CachedSecretKeyRing wmKR, + CachedPublicKeyRing wpKR, SaveKeyringParcel saveParcel) throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { + PGPSecretKeyRing mKR = wmKR.getRing(); + PGPPublicKeyRing pKR = wpKR.getRing(); + updateProgress(R.string.progress_building_key, 0, 100); - PGPSecretKey masterKey = saveParcel.keys.get(0); if (saveParcel.oldPassphrase == null) { saveParcel.oldPassphrase = ""; @@ -404,7 +382,7 @@ public class PgpKeyOperation { } } - masterKey = mKR.getSecretKey(); + PGPSecretKey masterKey = mKR.getSecretKey(); PGPPublicKey masterPublicKey = masterKey.getPublicKey(); int usageId = saveParcel.keysUsages.get(0); @@ -686,7 +664,7 @@ public class PgpKeyOperation { */ - return new Pair(mKR, pKR); + return new UncachedKeyRing(pKR, 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 86a2ed48d..58601c49a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -1,7 +1,15 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPUtil; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; public class UncachedKeyRing { @@ -9,8 +17,6 @@ public class UncachedKeyRing { final PGPSecretKeyRing mSecretRing; UncachedKeyRing(PGPPublicKeyRing publicRing, PGPSecretKeyRing secretRing) { - // this one must not be false! - assert(publicRing != null); mPublicRing = publicRing; mSecretRing = secretRing; } @@ -26,4 +32,29 @@ public class UncachedKeyRing { public PGPSecretKeyRing getSecretRing() { return mSecretRing; } + + public byte[] getFingerprint() { + return mPublicRing.getPublicKey().getFingerprint(); + } + + public static UncachedKeyRing decodePubkeyFromData(byte[] data) + throws PgpGeneralException, IOException { + BufferedInputStream bufferedInput = + new BufferedInputStream(new ByteArrayInputStream(data)); + if (bufferedInput.available() > 0) { + InputStream in = PGPUtil.getDecoderStream(bufferedInput); + PGPObjectFactory objectFactory = new PGPObjectFactory(in); + + // get first object in block + Object obj; + if ((obj = objectFactory.nextObject()) != null && obj instanceof PGPPublicKeyRing) { + return new UncachedKeyRing((PGPPublicKeyRing) obj); + } else { + throw new PgpGeneralException("Object not recognized as PGPPublicKeyRing!"); + } + } else { + throw new PgpGeneralException("Object not recognized as PGPPublicKeyRing!"); + } + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java new file mode 100644 index 000000000..bda9ebbcf --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java @@ -0,0 +1,19 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPSecretKeyRing; + +public class UncachedSecretKeyRing { + + final PGPSecretKeyRing mSecretRing; + + UncachedSecretKeyRing(PGPSecretKeyRing secretRing) { + mSecretRing = secretRing; + } + + // Breaking the pattern here, for key import! + // TODO reduce this from public to default visibility! + public PGPSecretKeyRing getSecretKeyRing() { + return mSecretRing; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 0fe989e84..b135f8920 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -43,6 +43,8 @@ import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.UncachedSecretKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; @@ -484,12 +486,22 @@ public class ProviderHelper { } } + /** + * Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring + * is already in the database! + */ + public void saveKeyRing(UncachedSecretKeyRing wrappedRing) throws IOException { + // TODO split up getters + PGPSecretKeyRing keyRing = wrappedRing.getSecretKeyRing(); + saveKeyRing(keyRing); + } + /** * Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring * is already in the database! */ public void saveKeyRing(PGPSecretKeyRing keyRing) throws IOException { - long masterKeyId = keyRing.getPublicKey().getKeyID(); + long masterKeyId = keyRing.getSecretKey().getKeyID(); { Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId)); @@ -526,6 +538,12 @@ public class ProviderHelper { } + public void saveKeyRing(UncachedKeyRing wrappedRing) throws IOException { + PGPPublicKeyRing pubRing = wrappedRing.getPublicRing(); + PGPSecretKeyRing secRing = wrappedRing.getSecretRing(); + saveKeyRing(pubRing, secRing); + } + /** * Saves (or updates) a pair of public and secret KeyRings in the database */ 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 d02906c4f..972362f5f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -27,12 +27,6 @@ import android.os.Messenger; import android.os.RemoteException; import org.spongycastle.bcpg.sig.KeyFlags; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.FileHelper; @@ -41,7 +35,6 @@ import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CachedSecretKey; import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; @@ -51,6 +44,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.UncachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -63,7 +57,6 @@ import org.sufficientlysecure.keychain.util.KeychainServiceListener; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; -import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -516,19 +509,19 @@ public class KeychainIntentService extends IntentService /* Operation */ ProviderHelper providerHelper = new ProviderHelper(this); if (!canSign) { - PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 50, 100)); - PGPSecretKeyRing keyRing = providerHelper.getPGPSecretKeyRing(masterKeyId); - keyRing = keyOperations.changeSecretKeyPassphrase(keyRing, - oldPassphrase, newPassphrase); + setProgress(R.string.progress_building_key, 0, 100); + CachedSecretKeyRing keyRing = providerHelper.getCachedSecretKeyRing(masterKeyId); + UncachedSecretKeyRing newKeyRing = + keyRing.changeSecretKeyPassphrase(oldPassphrase, newPassphrase); setProgress(R.string.progress_saving_key_ring, 50, 100); - providerHelper.saveKeyRing(keyRing); + providerHelper.saveKeyRing(newKeyRing); setProgress(R.string.progress_done, 100, 100); } else { PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100)); - PgpKeyOperation.Pair pair; + UncachedKeyRing pair; try { - PGPSecretKeyRing privkey = providerHelper.getPGPSecretKeyRing(masterKeyId); - PGPPublicKeyRing pubkey = providerHelper.getPGPPublicKeyRing(masterKeyId); + CachedSecretKeyRing privkey = providerHelper.getCachedSecretKeyRing(masterKeyId); + CachedPublicKeyRing pubkey = providerHelper.getCachedPublicKeyRing(masterKeyId); pair = keyOperations.buildSecretKey(privkey, pubkey, saveParcel); // edit existing } catch (ProviderHelper.NotFoundException e) { @@ -537,7 +530,7 @@ public class KeychainIntentService extends IntentService setProgress(R.string.progress_saving_key_ring, 90, 100); // save the pair - providerHelper.saveKeyRing(pair.second, pair.first); + providerHelper.saveKeyRing(pair); setProgress(R.string.progress_done, 100, 100); } PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase); @@ -557,13 +550,11 @@ public class KeychainIntentService extends IntentService /* Operation */ PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); - PGPSecretKey newKey = keyOperations.createKey(algorithm, keysize, - passphrase, masterKey); + byte[] newKey = keyOperations.createKey(algorithm, keysize, passphrase, masterKey); /* Output */ Bundle resultData = new Bundle(); - resultData.putByteArray(RESULT_NEW_KEY, - PgpConversionHelper.PGPSecretKeyToBytes(newKey)); + resultData.putByteArray(RESULT_NEW_KEY, newKey); OtherHelper.logDebugBundle(resultData, "resultData"); @@ -576,7 +567,6 @@ public class KeychainIntentService extends IntentService try { /* Input */ String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE); - ArrayList newKeys = new ArrayList(); ArrayList keyUsageList = new ArrayList(); /* Operation */ @@ -589,23 +579,27 @@ public class KeychainIntentService extends IntentService keysTotal); PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); - PGPSecretKey masterKey = keyOperations.createKey(Constants.choice.algorithm.rsa, + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + byte[] buf; + + buf = keyOperations.createKey(Constants.choice.algorithm.rsa, 4096, passphrase, true); - newKeys.add(masterKey); + os.write(buf); keyUsageList.add(KeyFlags.CERTIFY_OTHER); keysCreated++; setProgress(keysCreated, keysTotal); - PGPSecretKey subKey = keyOperations.createKey(Constants.choice.algorithm.rsa, + buf = keyOperations.createKey(Constants.choice.algorithm.rsa, 4096, passphrase, false); - newKeys.add(subKey); + os.write(buf); keyUsageList.add(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE); keysCreated++; setProgress(keysCreated, keysTotal); - subKey = keyOperations.createKey(Constants.choice.algorithm.rsa, + buf = keyOperations.createKey(Constants.choice.algorithm.rsa, 4096, passphrase, false); - newKeys.add(subKey); + os.write(buf); keyUsageList.add(KeyFlags.SIGN_DATA); keysCreated++; setProgress(keysCreated, keysTotal); @@ -614,10 +608,8 @@ public class KeychainIntentService extends IntentService // for sign /* Output */ - Bundle resultData = new Bundle(); - resultData.putByteArray(RESULT_NEW_KEY, - PgpConversionHelper.PGPSecretKeyArrayListToBytes(newKeys)); + resultData.putByteArray(RESULT_NEW_KEY, os.toByteArray()); resultData.putIntegerArrayList(RESULT_KEY_USAGES, keyUsageList); OtherHelper.logDebugBundle(resultData, "resultData"); @@ -755,30 +747,13 @@ public class KeychainIntentService extends IntentService } // create PGPKeyRing object based on downloaded armored key - PGPKeyRing downloadedKey = null; - BufferedInputStream bufferedInput = - new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes)); - if (bufferedInput.available() > 0) { - InputStream in = PGPUtil.getDecoderStream(bufferedInput); - PGPObjectFactory objectFactory = new PGPObjectFactory(in); - - // get first object in block - Object obj; - if ((obj = objectFactory.nextObject()) != null) { - Log.d(Constants.TAG, "Found class: " + obj.getClass()); - - if (obj instanceof PGPKeyRing) { - downloadedKey = (PGPKeyRing) obj; - } else { - throw new PgpGeneralException("Object not recognized as PGPKeyRing!"); - } - } - } + UncachedKeyRing downloadedKey = + UncachedKeyRing.decodePubkeyFromData(downloadedKeyBytes); // verify downloaded key by comparing fingerprints if (entry.getFingerPrintHex() != null) { String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex( - downloadedKey.getPublicKey().getFingerprint()); + downloadedKey.getFingerprint()); if (downloadedKeyFp.equals(entry.getFingerPrintHex())) { Log.d(Constants.TAG, "fingerprint of downloaded key is the same as " + "the requested fingerprint!"); @@ -790,7 +765,7 @@ public class KeychainIntentService extends IntentService // save key bytes in entry object for doing the // actual import afterwards - entry.setBytes(downloadedKey.getEncoded()); + entry.setBytes(downloadedKeyBytes); } Intent importIntent = new Intent(this, KeychainIntentService.class); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index d1a5dca07..51a229677 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -34,7 +34,12 @@ import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.CachedPublicKey; +import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.CachedSecretKey; +import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; @@ -144,18 +149,14 @@ public class EncryptAsymmetricFragment extends Fragment { */ private void preselectKeys(long preselectedSignatureKeyId, long[] preselectedEncryptionKeyIds, ProviderHelper providerHelper) { + // TODO all of this works under the assumption that the first suitable subkey is always used! + // not sure if we need to distinguish between different subkeys here? if (preselectedSignatureKeyId != 0) { - // TODO: don't use bouncy castle objects! try { - PGPSecretKeyRing keyRing = providerHelper.getPGPSecretKeyRingWithKeyId( - preselectedSignatureKeyId); - - PGPSecretKey masterKey = keyRing.getSecretKey(); - if (masterKey != null) { - PGPSecretKey signKey = PgpKeyHelper.getFirstSigningSubkey(keyRing); - if (signKey != null) { - setSignatureKeyId(masterKey.getKeyID()); - } + CachedPublicKeyRing keyring = + providerHelper.getCachedPublicKeyRing(preselectedSignatureKeyId); + if(keyring.hasSecret()) { + setSignatureKeyId(keyring.getMasterKeyId()); } } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); @@ -165,7 +166,6 @@ public class EncryptAsymmetricFragment extends Fragment { if (preselectedEncryptionKeyIds != null) { Vector goodIds = new Vector(); for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) { - // TODO One query per selected key?! wtf try { long id = providerHelper.getMasterKeyId( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( -- cgit v1.2.3 From b5647b2062e3233451532f44ce03c8b1bcdb7a3e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 4 May 2014 03:38:58 +0200 Subject: wrapped-key-ring: no more pgp imports in PassphraseDialogFragment --- .../keychain/pgp/CachedSecretKey.java | 7 +- .../keychain/pgp/PgpDecryptVerify.java | 8 +- .../keychain/pgp/PgpKeyOperation.java | 4 +- .../keychain/provider/ProviderHelper.java | 8 -- .../keychain/service/KeychainIntentService.java | 4 +- .../ui/dialog/PassphraseDialogFragment.java | 117 +++++++++------------ 6 files changed, 61 insertions(+), 87 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java index d0b18d757..948227819 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java @@ -41,17 +41,18 @@ public class CachedSecretKey extends CachedPublicKey { return (CachedSecretKeyRing) mRing; } - public void unlock(String passphrase) throws PgpGeneralException { + 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) { - throw new PgpGeneralException("error extracting key!", e); + return false; } if(mPrivateKey == null) { - throw new PgpGeneralException("error extracting key (bad passphrase?)"); + throw new PgpGeneralException("error extracting key"); } + return true; } public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext) 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 37dfee8b9..27e9e8ebd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -344,9 +344,11 @@ public class PgpDecryptVerify { currentProgress += 5; updateProgress(R.string.progress_extracting_key, currentProgress, 100); try { - secretEncryptionKey.unlock(mPassphrase); - } catch (PgpGeneralException e) { - throw new WrongPassphraseException(); + if (!secretEncryptionKey.unlock(mPassphrase)) { + throw new WrongPassphraseException(); + } + } catch(PgpGeneralException e) { + throw new KeyExtractionException(); } currentProgress += 5; updateProgress(R.string.progress_preparing_streams, currentProgress, 100); 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 7251709e0..1dfbfaf3a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -338,8 +338,8 @@ public class PgpKeyOperation { } public UncachedKeyRing buildSecretKey(CachedSecretKeyRing wmKR, - CachedPublicKeyRing wpKR, - SaveKeyringParcel saveParcel) + CachedPublicKeyRing wpKR, + SaveKeyringParcel saveParcel) throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { PGPSecretKeyRing mKR = wmKR.getRing(); 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 b135f8920..f2abd915e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -293,14 +293,6 @@ public class ProviderHelper { } } - @Deprecated - public PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(long keyId) - throws NotFoundException { - Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)); - long masterKeyId = getMasterKeyId(uri); - return getPGPPublicKeyRing(masterKeyId); - } - @Deprecated public PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(long keyId) throws NotFoundException { 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 972362f5f..af6e66937 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -801,7 +801,9 @@ public class KeychainIntentService extends IntentService CachedPublicKeyRing publicRing = providerHelper.getCachedPublicKeyRing(pubKeyId); CachedSecretKeyRing secretKeyRing = providerHelper.getCachedSecretKeyRing(masterKeyId); CachedSecretKey certificationKey = secretKeyRing.getSubKey(); - certificationKey.unlock(signaturePassphrase); + if(!certificationKey.unlock(signaturePassphrase)) { + throw new PgpGeneralException("Error extracting key (bad passphrase?)"); + } UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds); // store the signed key in our local cache 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 3cb1ce7b4..256d9d4b7 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 @@ -41,17 +41,12 @@ import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.CachedSecretKey; +import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.util.Log; @@ -139,18 +134,17 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor alert.setTitle(R.string.title_authentication); - final PGPSecretKey secretKey; + final CachedSecretKeyRing secretRing; final String userId; if (secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none) { - secretKey = null; + secretRing = null; alert.setMessage(R.string.passphrase_for_symmetric_encryption); } else { try { ProviderHelper helper = new ProviderHelper(activity); - secretKey = helper.getPGPSecretKeyRing(secretKeyId).getSecretKey(); - userId = (String) helper.getUnifiedData(secretKeyId, - KeychainContract.KeyRings.USER_ID, ProviderHelper.FIELD_TYPE_STRING); + secretRing = helper.getCachedSecretKeyRing(secretKeyId); + userId = secretRing.getPrimaryUserId(); } catch (ProviderHelper.NotFoundException e) { alert.setTitle(R.string.title_key_not_found); alert.setMessage(getString(R.string.key_not_found, secretKeyId)); @@ -179,76 +173,59 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor @Override public void onClick(DialogInterface dialog, int id) { dismiss(); - long curKeyIndex = 1; - boolean keyOK = true; + String passphrase = mPassphraseEditText.getText().toString(); - long keyId; - PGPSecretKey clickSecretKey = secretKey; - - if (clickSecretKey != null) { - while (keyOK) { - if (clickSecretKey != null) { // check again for loop - try { - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - passphrase.toCharArray()); - PGPPrivateKey testKey = clickSecretKey - .extractPrivateKey(keyDecryptor); - if (testKey == null) { - if (!clickSecretKey.isMasterKey()) { - Toast.makeText(activity, - R.string.error_could_not_extract_private_key, - Toast.LENGTH_SHORT).show(); - - sendMessageToHandler(MESSAGE_CANCEL); - return; - } else { - try { - clickSecretKey = PgpKeyHelper.getKeyNum(new ProviderHelper(activity) - .getPGPSecretKeyRingWithKeyId(secretKeyId), - curKeyIndex - ); - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - curKeyIndex++; // does post-increment work like C? - continue; - } - } else { - keyOK = false; - } - } catch (PGPException e) { - Toast.makeText(activity, R.string.wrong_passphrase, - Toast.LENGTH_SHORT).show(); - - sendMessageToHandler(MESSAGE_CANCEL); - return; - } - } else { - Toast.makeText(activity, R.string.error_could_not_extract_private_key, - Toast.LENGTH_SHORT).show(); - - sendMessageToHandler(MESSAGE_CANCEL); - return; // ran out of keys to try + + // Early breakout if we are dealing with a symmetric key + if (secretRing == null) { + PassphraseCacheService.addCachedPassphrase(activity, Constants.key.symmetric, passphrase); + // also return passphrase back to activity + Bundle data = new Bundle(); + data.putString(MESSAGE_DATA_PASSPHRASE, passphrase); + sendMessageToHandler(MESSAGE_OKAY, data); + return; + } + + CachedSecretKey unlockedSecretKey = null; + + for(CachedSecretKey clickSecretKey : secretRing.iterator()) { + try { + boolean unlocked = clickSecretKey.unlock(passphrase); + if (unlocked) { + unlockedSecretKey = clickSecretKey; + break; } + } catch (PgpGeneralException e) { + Toast.makeText(activity, R.string.error_could_not_extract_private_key, + Toast.LENGTH_SHORT).show(); + + sendMessageToHandler(MESSAGE_CANCEL); + return; // ran out of keys to try } - keyId = secretKey.getKeyID(); - } else { - keyId = Constants.key.symmetric; } + // Means we got an exception every time + if (unlockedSecretKey == null) { + Toast.makeText(activity, R.string.wrong_passphrase, + Toast.LENGTH_SHORT).show(); + + sendMessageToHandler(MESSAGE_CANCEL); + return; + } + + long masterKeyId = secretRing.getMasterKeyId(); + // cache the new passphrase Log.d(Constants.TAG, "Everything okay! Caching entered passphrase"); - PassphraseCacheService.addCachedPassphrase(activity, keyId, passphrase); - if (!keyOK && clickSecretKey.getKeyID() != keyId) { - PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(), - passphrase); + PassphraseCacheService.addCachedPassphrase(activity, masterKeyId, passphrase); + if (unlockedSecretKey.getKeyId() != masterKeyId) { + PassphraseCacheService.addCachedPassphrase( + activity, unlockedSecretKey.getKeyId(), passphrase); } // also return passphrase back to activity Bundle data = new Bundle(); data.putString(MESSAGE_DATA_PASSPHRASE, passphrase); - sendMessageToHandler(MESSAGE_OKAY, data); } }); -- cgit v1.2.3 From d68fce687500fc308b5efaef8108e0ff9a26f556 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 4 May 2014 12:07:19 +0200 Subject: wrapped-key-ring: view certify --- .../keychain/pgp/CachedPublicKey.java | 13 +++++++++++++ .../keychain/ui/ViewCertActivity.java | 22 +++++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java index 2862b21c5..c1d866fba 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java @@ -11,6 +11,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodG import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; +import java.security.SignatureException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -157,6 +158,18 @@ public class CachedPublicKey { sig.init(contentVerifierBuilderProvider, mKey); } + /** 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, mKey); + } catch (SignatureException e) { + throw new PGPException("Error!", e); + } + } + public byte[] getFingerprint() { return mKey.getFingerprint(); } 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 f740cfc22..1d2b50faa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -37,20 +37,17 @@ import org.spongycastle.bcpg.SignatureSubpacket; import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.bcpg.sig.RevocationReason; import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; -import java.security.SignatureException; import java.util.Date; public class ViewCertActivity extends ActionBarActivity @@ -147,26 +144,17 @@ public class ViewCertActivity extends ActionBarActivity PGPSignature sig = PgpConversionHelper.BytesToPGPSignature(data.getBlob(INDEX_DATA)); try { ProviderHelper providerHelper = new ProviderHelper(this); - PGPKeyRing signeeRing = providerHelper.getPGPKeyRing( - KeychainContract.KeyRingData.buildPublicKeyRingUri( - Long.toString(data.getLong(INDEX_MASTER_KEY_ID)))); - PGPKeyRing signerRing = providerHelper.getPGPKeyRing( - KeychainContract.KeyRingData.buildPublicKeyRingUri( - Long.toString(sig.getKeyID()))); - + CachedPublicKeyRing signeeRing = providerHelper.getCachedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID)); + CachedPublicKeyRing signerRing = providerHelper.getCachedPublicKeyRing(sig.getKeyID()); try { - sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), signerRing.getPublicKey()); - if (sig.verifyCertification(signeeUid, signeeRing.getPublicKey())) { + signerRing.getSubkey().initSignature(sig); + if (signeeRing.getSubkey().verifySignature(sig, signeeUid)) { mStatus.setText(R.string.cert_verify_ok); mStatus.setTextColor(getResources().getColor(R.color.bbutton_success)); } else { mStatus.setText(R.string.cert_verify_failed); mStatus.setTextColor(getResources().getColor(R.color.alert)); } - } catch (SignatureException e) { - mStatus.setText(R.string.cert_verify_error); - mStatus.setTextColor(getResources().getColor(R.color.alert)); } catch (PGPException e) { mStatus.setText(R.string.cert_verify_error); mStatus.setTextColor(getResources().getColor(R.color.alert)); -- cgit v1.2.3 From d0e3af505cb0bd1405fac9f28ec32a404a8b0751 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 4 May 2014 12:08:53 +0200 Subject: wrapped-key-ring: cached data revamp --- .../keychain/provider/KeychainProvider.java | 70 ++++++++++++---------- 1 file changed, 37 insertions(+), 33 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 64dab3020..c67c2eca4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.util.Log; import java.util.Arrays; import java.util.Date; import java.util.HashMap; +import java.util.List; public class KeychainProvider extends ContentProvider { @@ -242,16 +243,16 @@ public class KeychainProvider extends ContentProvider { HashMap projectionMap = new HashMap(); projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); - projectionMap.put(KeyRings.KEY_ID, Keys.KEY_ID); - projectionMap.put(KeyRings.KEY_SIZE, Keys.KEY_SIZE); + projectionMap.put(KeyRings.KEY_ID, Tables.KEYS + "." + Keys.KEY_ID); + projectionMap.put(KeyRings.KEY_SIZE, Tables.KEYS + "." + Keys.KEY_SIZE); projectionMap.put(KeyRings.IS_REVOKED, Tables.KEYS + "." + Keys.IS_REVOKED); - projectionMap.put(KeyRings.CAN_CERTIFY, Keys.CAN_CERTIFY); - projectionMap.put(KeyRings.CAN_ENCRYPT, Keys.CAN_ENCRYPT); - projectionMap.put(KeyRings.CAN_SIGN, Keys.CAN_SIGN); + projectionMap.put(KeyRings.CAN_CERTIFY, Tables.KEYS + "." + Keys.CAN_CERTIFY); + projectionMap.put(KeyRings.CAN_ENCRYPT, Tables.KEYS + "." + Keys.CAN_ENCRYPT); + projectionMap.put(KeyRings.CAN_SIGN, Tables.KEYS + "." + Keys.CAN_SIGN); projectionMap.put(KeyRings.CREATION, Tables.KEYS + "." + Keys.CREATION); - projectionMap.put(KeyRings.EXPIRY, Keys.EXPIRY); - projectionMap.put(KeyRings.ALGORITHM, Keys.ALGORITHM); - projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT); + projectionMap.put(KeyRings.EXPIRY, Tables.KEYS + "." + Keys.EXPIRY); + projectionMap.put(KeyRings.ALGORITHM, Tables.KEYS + "." + Keys.ALGORITHM); + projectionMap.put(KeyRings.FINGERPRINT, Tables.KEYS + "." + Keys.FINGERPRINT); projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID); projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED); projectionMap.put(KeyRings.PUBKEY_DATA, @@ -267,26 +268,14 @@ public class KeychainProvider extends ContentProvider { + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + ")) AS " + KeyRings.HAS_ANY_SECRET); projectionMap.put(KeyRings.HAS_ENCRYPT, - "(EXISTS (SELECT * FROM " + Tables.KEYS + " AS k" - +" WHERE k." + Keys.MASTER_KEY_ID - + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND k." + Keys.IS_REVOKED + " = 0" - + " AND k." + Keys.CAN_ENCRYPT + " = 1" - + " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY - + " >= " + new Date().getTime() / 1000 + " )" - + ")) AS " + KeyRings.HAS_ENCRYPT); + "kE." + Keys.KEY_ID + " AS " + KeyRings.HAS_ENCRYPT); projectionMap.put(KeyRings.HAS_SIGN, - "(EXISTS (SELECT * FROM " + Tables.KEYS + " AS k" - +" WHERE k." + Keys.MASTER_KEY_ID - + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND k." + Keys.IS_REVOKED + " = 0" - + " AND k." + Keys.HAS_SECRET + " = 1" - + " AND k." + Keys.CAN_SIGN + " = 1" - + " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY - + " >= " + new Date().getTime() / 1000 + " )" - + ")) AS " + KeyRings.HAS_SIGN); + "kS." + Keys.KEY_ID + " AS " + KeyRings.HAS_SIGN); qb.setProjectionMap(projectionMap); + // Need this as list so we can search in it + List plist = Arrays.asList(projection); + qb.setTables( Tables.KEYS + " INNER JOIN " + Tables.USER_IDS + " ON (" @@ -301,22 +290,37 @@ public class KeychainProvider extends ContentProvider { + " AND " + Tables.CERTS + "." + Certs.VERIFIED + " = " + Certs.VERIFIED_SECRET + ")" - // fairly expensive join (due to blob data), only do it when requested - + (Arrays.asList(projection).contains(KeyRings.PUBKEY_DATA) ? + // fairly expensive joins following, only do when requested + + (plist.contains(KeyRings.PUBKEY_DATA) ? " INNER JOIN " + Tables.KEY_RINGS_PUBLIC + " ON (" + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = " + Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.MASTER_KEY_ID - + ")" - : "") - // fairly expensive join (due to blob data), only do it when requested - + (Arrays.asList(projection).contains(KeyRings.PRIVKEY_DATA) ? + + ")" : "") + + (plist.contains(KeyRings.PRIVKEY_DATA) ? " LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON (" + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = " + Tables.KEY_RINGS_SECRET + "." + KeyRingData.MASTER_KEY_ID - + ")" - : "") + + ")" : "") + + (plist.contains(KeyRings.HAS_ENCRYPT) ? + " LEFT JOIN " + Tables.KEYS + " AS kE ON (" + +"kE." + Keys.MASTER_KEY_ID + + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + + " AND kE." + Keys.IS_REVOKED + " = 0" + + " AND kE." + Keys.CAN_ENCRYPT + " = 1" + + " AND ( kE." + Keys.EXPIRY + " IS NULL OR kE." + Keys.EXPIRY + + " >= " + new Date().getTime() / 1000 + " )" + + ")" : "") + + (plist.contains(KeyRings.HAS_SIGN) ? + " LEFT JOIN " + Tables.KEYS + " AS kS ON (" + +"kS." + Keys.MASTER_KEY_ID + + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + + " AND kS." + Keys.IS_REVOKED + " = 0" + + " AND kS." + Keys.CAN_SIGN + " = 1" + + " AND ( kS." + Keys.EXPIRY + " IS NULL OR kS." + Keys.EXPIRY + + " >= " + new Date().getTime() / 1000 + " )" + + ")" : "") ); qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0"); // in case there are multiple verifying certificates -- cgit v1.2.3 From 411b4cfeb2caa1d7d1c33129711bc1cd617778cf Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 4 May 2014 12:55:22 +0200 Subject: wrapped-key-ring: redesign underlying CachedKeyRing --- .../keychain/pgp/CachedKeyRing.java | 53 +++++++---- .../keychain/pgp/CachedPublicKeyRing.java | 80 ++++++++--------- .../keychain/pgp/CachedSecretKeyRing.java | 94 ++++++++----------- .../keychain/pgp/PgpSignEncrypt.java | 9 +- .../keychain/provider/ProviderHelper.java | 100 ++++++++------------- .../keychain/ui/EncryptAsymmetricFragment.java | 8 +- 6 files changed, 153 insertions(+), 191 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java index 334f676c4..def673469 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java @@ -3,45 +3,66 @@ package org.sufficientlysecure.keychain.pgp; public abstract class CachedKeyRing { private final long mMasterKeyId; - private final boolean mCanCertify; - private final byte[] mFingerprint; private final String mUserId; + private final boolean mHasAnySecret; + private final boolean mIsRevoked; + private final boolean mCanCertify; + private final long mHasEncryptId; + private final long mHasSignId; private final int mVerified; - private final boolean mHasSecret; - protected CachedKeyRing(long masterKeyId, boolean canCertify, - byte[] fingerprint, String userId, int verified, boolean hasSecret) + protected CachedKeyRing(long masterKeyId, String userId, boolean hasAnySecret, + boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId, + int verified) { mMasterKeyId = masterKeyId; - mCanCertify = canCertify; - mFingerprint = fingerprint; mUserId = userId; + mHasAnySecret = hasAnySecret; + mIsRevoked = isRevoked; + mCanCertify = canCertify; + mHasEncryptId = hasEncryptId; + mHasSignId = hasSignId; mVerified = verified; - mHasSecret = hasSecret; } - public byte[] getFingerprint() { - return mFingerprint; + public long getMasterKeyId() { + return mMasterKeyId; } public String getPrimaryUserId() { return mUserId; } - public long getMasterKeyId() { - return mMasterKeyId; + public boolean hasAnySecret() { + return mHasAnySecret; } - public int getVerified() { - return mVerified; + public boolean isRevoked() { + return mIsRevoked; } public boolean canCertify() { return mCanCertify; } - public boolean hasSecret() { - return mHasSecret; + public long getEncryptId() { + return mHasEncryptId; + } + + public boolean hasEncrypt() { + return mHasEncryptId != 0; + } + + public long getSignId() { + return mHasSignId; + } + + public boolean hasSign() { + return mHasSignId != 0; + } + + public int getVerified() { + return mVerified; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java index 8970d18ec..bbce42f86 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java @@ -23,14 +23,14 @@ public class CachedPublicKeyRing extends CachedKeyRing { private PGPPublicKeyRing mRing; private final byte[] mPubKey; - public CachedPublicKeyRing(long masterKeyId, int keySize, boolean isRevoked, - boolean canCertify, long creation, long expiry, int algorithm, - byte[] fingerprint, String userId, int verified, boolean hasSecret, - byte[] pubkey) + public CachedPublicKeyRing(long masterKeyId, String userId, boolean hasAnySecret, + boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId, + int verified, byte[] blob) { - super(masterKeyId, canCertify, fingerprint, userId, verified, hasSecret); + super(masterKeyId, userId, hasAnySecret, isRevoked, canCertify, + hasEncryptId, hasSignId, verified); - mPubKey = pubkey; + mPubKey = blob; } PGPPublicKeyRing getRing() { @@ -52,46 +52,18 @@ public class CachedPublicKeyRing extends CachedKeyRing { return new CachedPublicKey(this, getRing().getPublicKey(id)); } - public CachedPublicKey getFirstSignSubkey() throws PgpGeneralException { - // only return master key if no other signing key is available - CachedPublicKey masterKey = null; - for (PGPPublicKey k : new IterableIterator(getRing().getPublicKeys())) { - CachedPublicKey key = new CachedPublicKey(this, k); - if (key.isRevoked() || key.canSign() || key.isExpired()) { - continue; + /** Getter that returns the subkey that should be used for signing. */ + CachedPublicKey getEncryptionSubKey() throws PgpGeneralException { + PGPPublicKey key = getRing().getPublicKey(getEncryptId()); + if(key != null) { + CachedPublicKey cKey = new CachedPublicKey(this, key); + if(!cKey.canEncrypt()) { + throw new PgpGeneralException("key error"); } - if (key.isMasterKey()) { - masterKey = key; - } else { - return key; - } - } - if(masterKey == null) { - // TODO proper exception - throw new PgpGeneralException("key not found"); - } - return masterKey; - } - - public CachedPublicKey getFirstEncryptSubkey() throws PgpGeneralException { - // only return master key if no other encryption key is available - CachedPublicKey masterKey = null; - for (PGPPublicKey k : new IterableIterator(getRing().getPublicKeys())) { - CachedPublicKey key = new CachedPublicKey(this, k); - if (key.isRevoked() || key.canEncrypt() || key.isExpired()) { - continue; - } - if (key.isMasterKey()) { - masterKey = key; - } else { - return key; - } - } - if(masterKey == null) { - // TODO proper exception - throw new PgpGeneralException("key not found"); + return cKey; } - return masterKey; + // TODO handle with proper exception + throw new PgpGeneralException("no encryption key available"); } public boolean verifySubkeyBinding(CachedPublicKey cachedSubkey) { @@ -189,4 +161,24 @@ public class CachedPublicKeyRing extends CachedKeyRing { return validPrimaryKeyBinding; } + public IterableIterator iterator() { + final Iterator it = getRing().getPublicKeys(); + return new IterableIterator(new Iterator() { + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public CachedPublicKey next() { + return new CachedPublicKey(CachedPublicKeyRing.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/CachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java index 590a02b95..398092aeb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java @@ -1,18 +1,15 @@ package org.sufficientlysecure.keychain.pgp; -import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.util.IterableIterator; import java.io.IOException; @@ -23,12 +20,13 @@ public class CachedSecretKeyRing extends CachedKeyRing { private PGPSecretKeyRing mRing; - public CachedSecretKeyRing(long masterKeyId, int keySize, boolean isRevoked, - boolean canCertify, long creation, long expiry, int algorithm, - byte[] fingerprint, String userId, int verified, boolean hasSecret, - byte[] blob) + public CachedSecretKeyRing(long masterKeyId, String userId, boolean hasAnySecret, + boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId, + int verified, byte[] blob) { - super(masterKeyId, canCertify, fingerprint, userId, verified, hasSecret); + super(masterKeyId, userId, hasAnySecret, + isRevoked, canCertify, hasEncryptId, hasSignId, + verified); mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob); } @@ -45,8 +43,18 @@ public class CachedSecretKeyRing extends CachedKeyRing { return new CachedSecretKey(this, mRing.getSecretKey(id)); } - public IterableIterator iterator() { - return new IterableIterator(mRing.getSecretKeys()); + /** Getter that returns the subkey that should be used for signing. */ + CachedSecretKey getSigningSubKey() throws PgpGeneralException { + PGPSecretKey key = mRing.getSecretKey(getSignId()); + if(key != null) { + CachedSecretKey cKey = new CachedSecretKey(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() { @@ -74,50 +82,6 @@ public class CachedSecretKeyRing extends CachedKeyRing { } } - /** This returns the subkey that should be used for signing. - * At this point, this is simply the first suitable subkey. - */ - CachedSecretKey getSigningSubKey() { - for (PGPSecretKey key : new IterableIterator(mRing.getSecretKeys())) { - if (isSigningKey(key.getPublicKey())) { - return new CachedSecretKey(this, key); - } - } - // TODO exception - return null; - } - - @SuppressWarnings("unchecked") - public static boolean isSigningKey(PGPPublicKey key) { - if (key.getVersion() <= 3) { - return true; - } - - // special case - if (key.getAlgorithm() == PGPPublicKey.RSA_SIGN) { - return true; - } - - for (PGPSignature sig : new IterableIterator(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - - if (hashed != null && (hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) { - return true; - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - - if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) { - return true; - } - } - - return false; - } - public UncachedSecretKeyRing changeSecretKeyPassphrase(String oldPassphrase, String newPassphrase) throws IOException, PGPException, NoSuchProviderException { @@ -141,4 +105,24 @@ public class CachedSecretKeyRing extends CachedKeyRing { } + public IterableIterator iterator() { + final Iterator it = mRing.getSecretKeys(); + return new IterableIterator(new Iterator() { + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public CachedSecretKey next() { + return new CachedSecretKey(CachedSecretKeyRing.this, it.next()); + } + + @Override + public void remove() { + it.remove(); + } + }); + } + } 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 48cc5d6da..ccbbb3719 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -270,14 +270,15 @@ public class PgpSignEncrypt { /* Get keys for signature generation for later usage */ CachedSecretKey signingKey = null; if (enableSignature) { - CachedSecretKeyRing signingKeyRing = null; + CachedSecretKeyRing signingKeyRing; try { signingKeyRing = mProviderHelper.getCachedSecretKeyRing(mSignatureMasterKeyId); } catch (ProviderHelper.NotFoundException e) { throw new NoSigningKeyException(); } - signingKey = signingKeyRing.getSigningSubKey(); - if (signingKey == null) { + try { + signingKey = signingKeyRing.getSigningSubKey(); + } catch(PgpGeneralException e) { throw new NoSigningKeyException(); } @@ -319,7 +320,7 @@ public class PgpSignEncrypt { try { CachedPublicKeyRing keyRing = mProviderHelper.getCachedPublicKeyRing( KeyRings.buildUnifiedKeyRingUri(Long.toString(id))); - CachedPublicKey key = keyRing.getFirstEncryptSubkey(); + CachedPublicKey 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/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index f2abd915e..d1a003ec1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -38,6 +38,7 @@ 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.CachedKeyRing; import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; @@ -193,86 +194,55 @@ public class ProviderHelper { } public CachedPublicKeyRing getCachedPublicKeyRing(long id) throws NotFoundException { - return getCachedPublicKeyRing(KeyRings.buildUnifiedKeyRingUri(Long.toString(id))); + return (CachedPublicKeyRing) getCachedKeyRing( + KeyRings.buildUnifiedKeyRingUri(Long.toString(id)), false); } public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws NotFoundException { - Cursor cursor = mContentResolver.query(queryUri, - new String[] { - KeyRings.MASTER_KEY_ID, KeyRings.KEY_SIZE, - KeyRings.IS_REVOKED, KeyRings.CAN_CERTIFY, - KeyRings.CREATION, KeyRings.EXPIRY, - KeyRings.ALGORITHM, KeyRings.FINGERPRINT, - KeyRings.USER_ID, KeyRings.VERIFIED, - KeyRings.HAS_SECRET, KeyRings.PUBKEY_DATA - }, null, null, null); - try { - if (cursor != null && cursor.moveToFirst()) { - long masterKeyId = cursor.getLong(0); - int keySize = cursor.getInt(1); - boolean isRevoked = cursor.getInt(2) > 0; - boolean canCertify = cursor.getInt(3) > 0; - long creation = cursor.getLong(4); - long expiry = cursor.getLong(5); - int algorithm = cursor.getInt(6); - byte[] fingerprint = cursor.getBlob(7); - String userId = cursor.getString(8); - int verified = cursor.getInt(9); - boolean hasSecret = cursor.getInt(10) > 0; - byte[] pubkey = cursor.getBlob(11); - return new CachedPublicKeyRing( - masterKeyId, keySize, isRevoked, canCertify, - creation, expiry, algorithm, fingerprint, - userId, verified, hasSecret, pubkey - ); - } else { - throw new NotFoundException("Key not found!"); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } + return (CachedPublicKeyRing) getCachedKeyRing(queryUri, false); } public CachedSecretKeyRing getCachedSecretKeyRing(long id) throws NotFoundException { - return getCachedSecretKeyRing(KeyRings.buildUnifiedKeyRingUri(Long.toString(id))); + return (CachedSecretKeyRing) getCachedKeyRing( + KeyRings.buildUnifiedKeyRingUri(Long.toString(id)), true); } public CachedSecretKeyRing getCachedSecretKeyRing(Uri queryUri) throws NotFoundException { + return (CachedSecretKeyRing) getCachedKeyRing(queryUri, true); + } + + + private CachedKeyRing getCachedKeyRing(Uri queryUri, boolean secret) throws NotFoundException { Cursor cursor = mContentResolver.query(queryUri, new String[] { - KeyRings.MASTER_KEY_ID, KeyRings.KEY_SIZE, - KeyRings.IS_REVOKED, KeyRings.CAN_CERTIFY, - KeyRings.CREATION, KeyRings.EXPIRY, - KeyRings.ALGORITHM, KeyRings.FINGERPRINT, - KeyRings.USER_ID, KeyRings.VERIFIED, - KeyRings.HAS_SECRET, KeyRings.PRIVKEY_DATA + // we pick from cache: + // basic data, primary uid in particular because it's expensive + KeyRings.MASTER_KEY_ID, KeyRings.USER_ID, KeyRings.HAS_ANY_SECRET, + // complex knowledge about subkeys + KeyRings.IS_REVOKED, KeyRings.CAN_CERTIFY, KeyRings.HAS_ENCRYPT, KeyRings.HAS_SIGN, + // stuff only the db knows and of course, ring data + KeyRings.VERIFIED, secret ? KeyRings.PRIVKEY_DATA : KeyRings.PUBKEY_DATA }, null, null, null); try { if (cursor != null && cursor.moveToFirst()) { - // check if a privkey is actually available - byte[] privkey = cursor.getBlob(11); - if(privkey == null) { - throw new NotFoundException("Key found, but no secret key available!"); - } - long masterKeyId = cursor.getLong(0); - int keySize = cursor.getInt(1); - boolean isRevoked = cursor.getInt(2) > 0; - boolean canCertify = cursor.getInt(3) > 0; - long creation = cursor.getLong(4); - long expiry = cursor.getLong(5); - int algorithm = cursor.getInt(6); - byte[] fingerprint = cursor.getBlob(7); - String userId = cursor.getString(8); - int verified = cursor.getInt(9); - boolean hasSecret = cursor.getInt(10) > 0; - return new CachedSecretKeyRing( - masterKeyId, keySize, isRevoked, canCertify, - creation, expiry, algorithm, fingerprint, - userId, verified, hasSecret, privkey - ); + String userId = cursor.getString(1); + boolean hasAnySecret = cursor.getInt(2) > 0; + boolean isRevoked = cursor.getInt(3) > 0; + boolean canCertify = cursor.getInt(4) > 0; + long hasEncryptId = cursor.getLong(5); + long hasSignId = cursor.getLong(6); + int verified = cursor.getInt(7); + byte[] blob = cursor.getBlob(8); + return secret + ? new CachedSecretKeyRing( + masterKeyId, userId, hasAnySecret, + isRevoked, canCertify, hasEncryptId, hasSignId, + verified, blob) + : new CachedPublicKeyRing( + masterKeyId, userId, hasAnySecret, + isRevoked, canCertify, hasEncryptId, hasSignId, + verified, blob); } else { throw new NotFoundException("Key not found!"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index 51a229677..0b6449cda 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -30,16 +30,10 @@ import android.widget.TextView; import com.beardedhen.androidbootstrap.BootstrapButton; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.CachedPublicKey; import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.CachedSecretKey; -import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; @@ -155,7 +149,7 @@ public class EncryptAsymmetricFragment extends Fragment { try { CachedPublicKeyRing keyring = providerHelper.getCachedPublicKeyRing(preselectedSignatureKeyId); - if(keyring.hasSecret()) { + if(keyring.hasAnySecret()) { setSignatureKeyId(keyring.getMasterKeyId()); } } catch (ProviderHelper.NotFoundException e) { -- cgit v1.2.3 From 8cf0638f54fc4679c33a0243e17c514271931c48 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 4 May 2014 16:56:44 +0200 Subject: wrapped-key-ring: introduce Uncached*Key objects --- .../keychain/pgp/CachedPublicKey.java | 133 ++------------------ .../keychain/pgp/CachedPublicKeyRing.java | 2 +- .../keychain/pgp/CachedSecretKey.java | 7 +- .../keychain/pgp/UncachedPublicKey.java | 140 +++++++++++++++++++++ .../keychain/pgp/UncachedSecretKey.java | 26 ++++ 5 files changed, 179 insertions(+), 129 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java index c1d866fba..dee03db6f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java @@ -1,139 +1,28 @@ package org.sufficientlysecure.keychain.pgp; -import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPOnePassSignature; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; import java.security.SignatureException; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -public class CachedPublicKey { +public class CachedPublicKey extends UncachedPublicKey { // this is the parent key ring final CachedKeyRing mRing; - private final PGPPublicKey mKey; - CachedPublicKey(CachedKeyRing ring, PGPPublicKey key) { + super(key); mRing = ring; - mKey = key; - } - - public long getKeyId() { - return mKey.getKeyID(); - } - - public boolean isRevoked() { - return mKey.isRevoked(); - } - - public Date getCreationTime() { - return mKey.getCreationTime(); - } - - public Date getExpiryTime() { - Date creationDate = getCreationTime(); - if (mKey.getValidDays() == 0) { - // no expiry - return null; - } - Calendar calendar = GregorianCalendar.getInstance(); - calendar.setTime(creationDate); - calendar.add(Calendar.DATE, mKey.getValidDays()); - - return calendar.getTime(); - } - - public boolean isExpired() { - Date creationDate = mKey.getCreationTime(); - Date expiryDate = mKey.getValidSeconds() > 0 - ? new Date(creationDate.getTime() + mKey.getValidSeconds() * 1000) : null; - - Date now = new Date(); - return creationDate.after(now) || (expiryDate != null && expiryDate.before(now)); - } - - public boolean isMasterKey() { - return mKey.isMasterKey(); - } - - public int getAlgorithm() { - return mKey.getAlgorithm(); } public IterableIterator getUserIds() { - return new IterableIterator(mKey.getUserIDs()); - } - - private Integer mCacheUsage = null; - @SuppressWarnings("unchecked") - public int getKeyUsage() { - if(mCacheUsage == null) { - mCacheUsage = 0; - if (mKey.getVersion() >= 4) { - for (PGPSignature sig : new IterableIterator(mKey.getSignatures())) { - if (mKey.isMasterKey() && sig.getKeyID() != mKey.getKeyID()) { - continue; - } - - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - if (hashed != null) { - mCacheUsage |= hashed.getKeyFlags(); - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - if (unhashed != null) { - mCacheUsage |= unhashed.getKeyFlags(); - } - } - } - } - return mCacheUsage; - } - - public boolean canAuthenticate() { - return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.AUTHENTICATION) != 0; - } - - public boolean canCertify() { - return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.CERTIFY_OTHER) != 0; - } - - public boolean canEncrypt() { - if (!mKey.isEncryptionKey()) { - return false; - } - - // special cases - if (mKey.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) { - return true; - } - - if (mKey.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) { - return true; - } - - return mKey.getVersion() <= 3 || - (getKeyUsage() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0; - - } - - public boolean canSign() { - // special case - if (mKey.getAlgorithm() == PGPPublicKey.RSA_SIGN) { - return true; - } - - return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.SIGN_DATA) != 0; + return new IterableIterator(mPublicKey.getUserIDs()); } public CachedKeyRing getKeyRing() { @@ -141,21 +30,21 @@ public class CachedPublicKey { } JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() { - return new JcePublicKeyKeyEncryptionMethodGenerator(mKey); + return new JcePublicKeyKeyEncryptionMethodGenerator(mPublicKey); } public void initSignature(PGPSignature sig) throws PGPException { JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - sig.init(contentVerifierBuilderProvider, mKey); + sig.init(contentVerifierBuilderProvider, mPublicKey); } public void initSignature(PGPOnePassSignature sig) throws PGPException { JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - sig.init(contentVerifierBuilderProvider, mKey); + sig.init(contentVerifierBuilderProvider, mPublicKey); } /** Verify a signature for this pubkey, after it has been initialized by the signer using @@ -164,18 +53,10 @@ public class CachedPublicKey { */ public boolean verifySignature(PGPSignature sig, String uid) throws PGPException { try { - return sig.verifyCertification(uid, mKey); + return sig.verifyCertification(uid, mPublicKey); } catch (SignatureException e) { throw new PGPException("Error!", e); } } - public byte[] getFingerprint() { - return mKey.getFingerprint(); - } - - // Note that this method has package visibility - no access outside the pgp package! - PGPPublicKey getKey() { - return mKey; - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java index bbce42f86..108ed1a4a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java @@ -72,7 +72,7 @@ public class CachedPublicKeyRing extends CachedKeyRing { boolean validPrimaryKeyBinding = false; PGPPublicKey masterKey = getRing().getPublicKey(); - PGPPublicKey subKey = cachedSubkey.getKey(); + PGPPublicKey subKey = cachedSubkey.getPublicKey(); // Is this the master key? Match automatically, then. if(Arrays.equals(masterKey.getFingerprint(), subKey.getFingerprint())) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java index 948227819..d1634859a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java @@ -1,6 +1,5 @@ package org.sufficientlysecure.keychain.pgp; -import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPublicKey; @@ -157,7 +156,7 @@ public class CachedSecretKey extends CachedPublicKey { } // get the master subkey (which we certify for) - PGPPublicKey publicKey = publicKeyRing.getSubkey().getKey(); + PGPPublicKey publicKey = publicKeyRing.getSubkey().getPublicKey(); // fetch public key ring, add the certification and return it for (String userId : new IterableIterator(userIds.iterator())) { @@ -175,4 +174,8 @@ public class CachedSecretKey extends CachedPublicKey { // 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/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java new file mode 100644 index 000000000..bc37f6201 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -0,0 +1,140 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +public class UncachedPublicKey { + protected final PGPPublicKey mPublicKey; + private Integer mCacheUsage = null; + + public UncachedPublicKey(PGPPublicKey key) { + mPublicKey = key; + } + + public long getKeyId() { + return mPublicKey.getKeyID(); + } + + public boolean isRevoked() { + return mPublicKey.isRevoked(); + } + + public Date getCreationTime() { + return mPublicKey.getCreationTime(); + } + + public Date getExpiryTime() { + Date creationDate = getCreationTime(); + if (mPublicKey.getValidDays() == 0) { + // no expiry + return null; + } + Calendar calendar = GregorianCalendar.getInstance(); + calendar.setTime(creationDate); + calendar.add(Calendar.DATE, mPublicKey.getValidDays()); + + return calendar.getTime(); + } + + public boolean isExpired() { + Date creationDate = mPublicKey.getCreationTime(); + Date expiryDate = mPublicKey.getValidSeconds() > 0 + ? new Date(creationDate.getTime() + mPublicKey.getValidSeconds() * 1000) : null; + + Date now = new Date(); + return creationDate.after(now) || (expiryDate != null && expiryDate.before(now)); + } + + public boolean isMasterKey() { + return mPublicKey.isMasterKey(); + } + + public int getAlgorithm() { + return mPublicKey.getAlgorithm(); + } + + public boolean isElGamalEncrypt() { + return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT; + } + + public boolean isDSA() { + return getAlgorithm() == PGPPublicKey.DSA; + } + + @SuppressWarnings("unchecked") + public int getKeyUsage() { + if(mCacheUsage == null) { + mCacheUsage = 0; + if (mPublicKey.getVersion() >= 4) { + for (PGPSignature sig : new IterableIterator(mPublicKey.getSignatures())) { + if (mPublicKey.isMasterKey() && sig.getKeyID() != mPublicKey.getKeyID()) { + continue; + } + + PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); + if (hashed != null) { + mCacheUsage |= hashed.getKeyFlags(); + } + + PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); + if (unhashed != null) { + mCacheUsage |= unhashed.getKeyFlags(); + } + } + } + } + return mCacheUsage; + } + + public boolean canAuthenticate() { + return mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.AUTHENTICATION) != 0; + } + + public boolean canCertify() { + return mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.CERTIFY_OTHER) != 0; + } + + public boolean canEncrypt() { + if (!mPublicKey.isEncryptionKey()) { + return false; + } + + // special cases + if (mPublicKey.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) { + return true; + } + + if (mPublicKey.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) { + return true; + } + + return mPublicKey.getVersion() <= 3 || + (getKeyUsage() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0; + + } + + public boolean canSign() { + // special case + if (mPublicKey.getAlgorithm() == PGPPublicKey.RSA_SIGN) { + return true; + } + + return mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.SIGN_DATA) != 0; + } + + public byte[] getFingerprint() { + return mPublicKey.getFingerprint(); + } + + // Note that this method has package visibility - no access outside the pgp package! + PGPPublicKey getPublicKey() { + return mPublicKey; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java new file mode 100644 index 000000000..82224c6cf --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java @@ -0,0 +1,26 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPSecretKey; + +import java.io.IOException; +import java.io.OutputStream; + +public class UncachedSecretKey extends UncachedPublicKey { + + final PGPSecretKey mSecretKey; + + public UncachedSecretKey(PGPSecretKey secretKey) { + super(secretKey.getPublicKey()); + mSecretKey = secretKey; + } + + @Deprecated + public PGPSecretKey getSecretKeyExternal() { + return mSecretKey; + } + + public void encodeSecretKey(OutputStream os) throws IOException { + mSecretKey.encode(os); + } + +} -- cgit v1.2.3 From cd8af25ba71d95ebb2ab2a3ab4b19dc28cad63fc Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 4 May 2014 16:59:20 +0200 Subject: wrapped-key-ring: more work on passphrase caching and certification --- .../keychain/pgp/PgpKeyHelper.java | 17 ------ .../keychain/service/PassphraseCacheService.java | 66 +++++++++++----------- .../keychain/ui/CertifyKeyActivity.java | 63 ++++++--------------- .../ui/dialog/PassphraseDialogFragment.java | 8 ++- 4 files changed, 56 insertions(+), 98 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index e888d594e..77697b026 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -81,23 +81,6 @@ public class PgpKeyHelper { return getExpiryDate(key.getPublicKey()); } - @SuppressWarnings("unchecked") - @Deprecated - public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) { - long cnt = 0; - if (keyRing == null) { - return null; - } - for (PGPSecretKey key : new IterableIterator(keyRing.getSecretKeys())) { - if (cnt == num) { - return key; - } - cnt++; - } - - return null; - } - public static int getKeyUsage(PGPSecretKey key) { return getKeyUsage(key.getPublicKey()); } 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 88e974288..2889b89c6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -42,6 +42,7 @@ import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; @@ -163,38 +164,46 @@ public class PassphraseCacheService extends Service { * @return */ private String getCachedPassphraseImpl(long keyId) { - Log.d(TAG, "getCachedPassphraseImpl() get masterKeyId for " + keyId); - - // try to get master key id which is used as an identifier for cached passphrases - long masterKeyId = keyId; - if (masterKeyId != Constants.key.symmetric) { - try { - masterKeyId = new ProviderHelper(this).getMasterKeyId( - KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId))); - } catch (ProviderHelper.NotFoundException e) { + // passphrase for symmetric encryption? + if (keyId == Constants.key.symmetric) { + Log.d(TAG, "getCachedPassphraseImpl() for symmetric encryption"); + String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric); + if (cachedPassphrase == null) { return null; } + addCachedPassphrase(this, Constants.key.symmetric, cachedPassphrase); + return cachedPassphrase; } - Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + masterKeyId); - // get cached passphrase - String cachedPassphrase = mPassphraseCache.get(masterKeyId); - if (cachedPassphrase == null) { - // if key has no passphrase -> cache and return empty passphrase - if (!hasPassphrase(this, masterKeyId)) { + // try to get master key id which is used as an identifier for cached passphrases + try { + Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + keyId); + CachedSecretKeyRing key = new ProviderHelper(this).getCachedSecretKeyRing( + KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId))); + // no passphrase needed? just add empty string and return it, then + if (!key.hasPassphrase()) { Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!"); - addCachedPassphrase(this, masterKeyId, ""); + addCachedPassphrase(this, keyId, ""); return ""; - } else { + } + + // get cached passphrase + String cachedPassphrase = mPassphraseCache.get(keyId); + if (cachedPassphrase == null) { + // this is an error return null; } - } - // set it again to reset the cache life cycle - Log.d(TAG, "Cache passphrase again when getting it!"); - addCachedPassphrase(this, masterKeyId, cachedPassphrase); - return cachedPassphrase; + // set it again to reset the cache life cycle + Log.d(TAG, "Cache passphrase again when getting it!"); + addCachedPassphrase(this, keyId, cachedPassphrase); + return cachedPassphrase; + + } catch (ProviderHelper.NotFoundException e) { + Log.e(TAG, "Passphrase for unknown key was requested!"); + return null; + } } @Deprecated @@ -230,16 +239,9 @@ public class PassphraseCacheService extends Service { * @return true if it has a passphrase */ @Deprecated - public static boolean hasPassphrase(Context context, long secretKeyId) { - // check if the key has no passphrase - try { - PGPSecretKeyRing secRing = new ProviderHelper(context).getPGPSecretKeyRing(secretKeyId); - return hasPassphrase(secRing); - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - - return true; + public static boolean hasPassphrase(Context context, long secretKeyId) + throws ProviderHelper.NotFoundException { + return new ProviderHelper(context).getCachedSecretKeyRing(secretKeyId).hasPassphrase(); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index fbcbbb0c3..30e8d9537 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -226,53 +226,22 @@ public class CertifyKeyActivity extends ActionBarActivity implements * handles the UI bits of the signing process on the UI thread */ private void initiateSigning() { - try { - PGPPublicKeyRing pubring = new ProviderHelper(this).getPGPPublicKeyRing(mPubKeyId); - - // if we have already signed this key, dont bother doing it again - boolean alreadySigned = false; - - /* todo: reconsider this at a later point when certs are in the db - @SuppressWarnings("unchecked") - Iterator itr = pubring.getPublicKey(mPubKeyId).getSignatures(); - while (itr.hasNext()) { - PGPSignature sig = itr.next(); - if (sig.getKeyID() == mMasterKeyId) { - alreadySigned = true; - break; - } - } - */ - - if (!alreadySigned) { - /* - * get the user's passphrase for this key (if required) - */ - String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId); - if (passphrase == null) { - PassphraseDialogFragment.show(this, mMasterKeyId, - new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - startSigning(); - } - } - }); - // bail out; need to wait until the user has entered the passphrase before trying again - return; - } else { - startSigning(); - } - } else { - AppMsg.makeText(this, R.string.key_has_already_been_certified, AppMsg.STYLE_ALERT) - .show(); - - setResult(RESULT_CANCELED); - finish(); - } - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); + // get the user's passphrase for this key (if required) + String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId); + if (passphrase == null) { + PassphraseDialogFragment.show(this, mMasterKeyId, + new Handler() { + @Override + public void handleMessage(Message message) { + if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { + startSigning(); + } + } + }); + // bail out; need to wait until the user has entered the passphrase before trying again + return; + } else { + startSigning(); } } 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 256d9d4b7..9b5581cc7 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 @@ -101,8 +101,12 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor long secretKeyId) throws PgpGeneralException { // check if secret key has a passphrase if (!(secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none)) { - if (!PassphraseCacheService.hasPassphrase(context, secretKeyId)) { - throw new PgpGeneralException("No passphrase! No passphrase dialog needed!"); + try { + if (new ProviderHelper(context).getCachedSecretKeyRing(secretKeyId).hasPassphrase()) { + throw new PgpGeneralException("No passphrase! No passphrase dialog needed!"); + } + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException("Error: Key not found!", e); } } -- cgit v1.2.3 From 9baddb7d719b09fb88f6fc4e7ed8ec495b68c3e1 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 4 May 2014 16:59:55 +0200 Subject: wrapped-key-ring: get rid of bc objects in key editor --- .../keychain/pgp/CachedSecretKey.java | 8 ++++ .../keychain/pgp/PgpConversionHelper.java | 33 +++------------- .../keychain/pgp/PgpKeyOperation.java | 10 ++--- .../keychain/remote/OpenPgpService.java | 2 +- .../keychain/service/KeychainIntentService.java | 2 +- .../keychain/service/SaveKeyringParcel.java | 35 ++++++++++++----- .../keychain/ui/CertifyKeyActivity.java | 2 - .../keychain/ui/EditKeyActivity.java | 45 ++++++++++------------ .../keychain/ui/widget/KeyEditor.java | 45 +++++++++++----------- .../keychain/ui/widget/SectionView.java | 16 ++++---- 10 files changed, 98 insertions(+), 100 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java index d1634859a..8e45ceb4f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java @@ -40,6 +40,14 @@ public class CachedSecretKey extends CachedPublicKey { return (CachedSecretKeyRing) mRing; } + /** Returns the wrapped PGPSecretKeyRing. + * This function is for compatibility only, should not be used anymore and will be removed + */ + @Deprecated + public PGPSecretKey getKeyExternal() { + return mSecretKey; + } + public boolean unlock(String passphrase) throws PgpGeneralException { try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java index 2199047cd..63e2ff2f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java @@ -26,12 +26,10 @@ import org.spongycastle.openpgp.PGPSignatureList; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.Log; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; - public class PgpConversionHelper { /** @@ -60,10 +58,10 @@ public class PgpConversionHelper { * @param keysBytes * @return */ - public static ArrayList BytesToPGPSecretKeyList(byte[] keysBytes) { + public static ArrayList BytesToPGPSecretKeyList(byte[] keysBytes) { PGPObjectFactory factory = new PGPObjectFactory(keysBytes); Object obj = null; - ArrayList keys = new ArrayList(); + ArrayList keys = new ArrayList(); try { while ((obj = factory.nextObject()) != null) { PGPSecretKey secKey = null; @@ -72,7 +70,7 @@ public class PgpConversionHelper { if (secKey == null) { Log.e(Constants.TAG, "No keys given!"); } - keys.add(secKey); + keys.add(new UncachedSecretKey(secKey)); } else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings PGPSecretKeyRing keyRing = null; keyRing = (PGPSecretKeyRing) obj; @@ -82,7 +80,7 @@ public class PgpConversionHelper { @SuppressWarnings("unchecked") Iterator itr = keyRing.getSecretKeys(); while (itr.hasNext()) { - keys.add(itr.next()); + keys.add(new UncachedSecretKey(itr.next())); } } } @@ -100,7 +98,7 @@ public class PgpConversionHelper { * @param keyBytes * @return */ - public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) { + public static UncachedSecretKey BytesToPGPSecretKey(byte[] keyBytes) { PGPObjectFactory factory = new PGPObjectFactory(keyBytes); Object obj = null; try { @@ -121,7 +119,7 @@ public class PgpConversionHelper { secKey = keyRing.getSecretKey(); } - return secKey; + return new UncachedSecretKey(secKey); } /** @@ -146,23 +144,4 @@ public class PgpConversionHelper { return signatures.get(0); } - /** - * Convert from ArrayList to byte[] - * - * @param keys - * @return - */ - public static byte[] PGPSecretKeyArrayListToBytes(ArrayList keys) { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - for (PGPSecretKey key : keys) { - try { - key.encode(os); - } catch (IOException e) { - Log.e(Constants.TAG, "Error while converting ArrayList to byte[]!", e); - } - } - - return os.toByteArray(); - } - } 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 1dfbfaf3a..d0ca77da7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -200,7 +200,7 @@ public class PgpKeyOperation { boolean canSign; String mainUserId = saveParcel.userIds.get(0); - PGPSecretKey masterKey = saveParcel.keys.get(0); + PGPSecretKey masterKey = saveParcel.keys.get(0).getSecretKeyExternal(); // this removes all userIds and certifications previously attached to the masterPublicKey PGPPublicKey masterPublicKey = masterKey.getPublicKey(); @@ -275,7 +275,7 @@ public class PgpKeyOperation { for (int i = 1; i < saveParcel.keys.size(); ++i) { updateProgress(40 + 40 * (i - 1) / (saveParcel.keys.size() - 1), 100); - PGPSecretKey subKey = saveParcel.keys.get(i); + PGPSecretKey subKey = saveParcel.keys.get(i).getSecretKeyExternal(); PGPPublicKey subPublicKey = subKey.getPublicKey(); PBESecretKeyDecryptor keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder() @@ -377,8 +377,8 @@ public class PgpKeyOperation { */ if (saveParcel.deletedKeys != null) { - for (PGPSecretKey dKey : saveParcel.deletedKeys) { - mKR = PGPSecretKeyRing.removeSecretKey(mKR, dKey); + for (UncachedSecretKey dKey : saveParcel.deletedKeys) { + mKR = PGPSecretKeyRing.removeSecretKey(mKR, dKey.getSecretKeyExternal()); } } @@ -542,7 +542,7 @@ public class PgpKeyOperation { for (int i = 1; i < saveParcel.keys.size(); ++i) { updateProgress(40 + 50 * i / saveParcel.keys.size(), 100); if (saveParcel.moddedKeys[i]) { - PGPSecretKey subKey = saveParcel.keys.get(i); + PGPSecretKey subKey = saveParcel.keys.get(i).getSecretKeyExternal(); PGPPublicKey subPublicKey = subKey.getPublicKey(); PBESecretKeyDecryptor keyDecryptor2; 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 1e0cfaa8e..8a247a11b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -412,7 +412,7 @@ public class OpenPgpService extends RemoteService { try { // try to find key, throws NotFoundException if not in db! - mProviderHelper.getPGPPublicKeyRing(masterKeyId); + mProviderHelper.getCachedPublicKeyRing(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 af6e66937..5365ed62c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -504,7 +504,7 @@ public class KeychainIntentService extends IntentService newPassphrase = oldPassphrase; } - long masterKeyId = saveParcel.keys.get(0).getKeyID(); + long masterKeyId = saveParcel.keys.get(0).getKeyId(); /* Operation */ ProviderHelper providerHelper = new ProviderHelper(this); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index 3f0b37b75..60fdf895d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -20,9 +20,14 @@ package org.sufficientlysecure.keychain.service; import android.os.Parcel; import android.os.Parcelable; -import org.spongycastle.openpgp.PGPSecretKey; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; +import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; +import org.sufficientlysecure.keychain.util.IterableIterator; +import org.sufficientlysecure.keychain.util.Log; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; @@ -34,13 +39,13 @@ public class SaveKeyringParcel implements Parcelable { public boolean[] newIDs; public boolean primaryIDChanged; public boolean[] moddedKeys; - public ArrayList deletedKeys; + public ArrayList deletedKeys; public ArrayList keysExpiryDates; public ArrayList keysUsages; public String newPassphrase; public String oldPassphrase; public boolean[] newKeys; - public ArrayList keys; + public ArrayList keys; public String originalPrimaryID; public SaveKeyringParcel() {} @@ -75,17 +80,13 @@ public class SaveKeyringParcel implements Parcelable { destination.writeBooleanArray(newIDs); destination.writeByte((byte) (primaryIDChanged ? 1 : 0)); destination.writeBooleanArray(moddedKeys); - byte[] tmp = null; - if (deletedKeys.size() != 0) { - tmp = PgpConversionHelper.PGPSecretKeyArrayListToBytes(deletedKeys); - } - destination.writeByteArray(tmp); + destination.writeByteArray(encodeArrayList(deletedKeys)); destination.writeSerializable(keysExpiryDates); destination.writeList(keysUsages); destination.writeString(newPassphrase); destination.writeString(oldPassphrase); destination.writeBooleanArray(newKeys); - destination.writeByteArray(PgpConversionHelper.PGPSecretKeyArrayListToBytes(keys)); + destination.writeByteArray(encodeArrayList(keys)); destination.writeString(originalPrimaryID); } @@ -99,6 +100,22 @@ public class SaveKeyringParcel implements Parcelable { } }; + private static byte[] encodeArrayList(ArrayList list) { + if(list.isEmpty()) { + return null; + } + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for(UncachedSecretKey key : new IterableIterator(list.iterator())) { + try { + key.encodeSecretKey(os); + } catch (IOException e) { + Log.e(Constants.TAG, "Error while converting ArrayList to byte[]!", e); + } + } + return os.toByteArray(); + } + @Override public int describeContents() { return 0; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index 30e8d9537..eb8ef003c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -43,7 +43,6 @@ import android.widget.TextView; import com.beardedhen.androidbootstrap.BootstrapButton; import com.devspark.appmsg.AppMsg; -import org.spongycastle.openpgp.PGPPublicKeyRing; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; @@ -51,7 +50,6 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 4c747d0d9..529ea62a3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -44,16 +44,17 @@ import android.widget.Toast; import com.beardedhen.androidbootstrap.BootstrapButton; import com.devspark.appmsg.AppMsg; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.ExportHelper; +import org.sufficientlysecure.keychain.pgp.CachedSecretKey; +import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; @@ -66,7 +67,6 @@ import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; import org.sufficientlysecure.keychain.ui.widget.KeyEditor; import org.sufficientlysecure.keychain.ui.widget.SectionView; import org.sufficientlysecure.keychain.ui.widget.UserIdEditor; -import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; @@ -88,8 +88,6 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener // EDIT private Uri mDataUri; - private PGPSecretKeyRing mKeyRing = null; - private SectionView mUserIdsView; private SectionView mKeysView; @@ -105,7 +103,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener private CheckBox mNoPassphrase; Vector mUserIds; - Vector mKeys; + Vector mKeys; Vector mKeysUsages; boolean mMasterCanSign = true; @@ -158,7 +156,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener ); mUserIds = new Vector(); - mKeys = new Vector(); + mKeys = new Vector(); mKeysUsages = new Vector(); // Catch Intents opened from other apps @@ -239,7 +237,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener // get new key from data bundle returned from service Bundle data = message.getData(); - ArrayList newKeys = + ArrayList newKeys = PgpConversionHelper.BytesToPGPSecretKeyList(data .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); @@ -287,18 +285,18 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener Log.d(Constants.TAG, "uri: " + mDataUri); try { - Uri secretUri = KeychainContract.KeyRingData.buildSecretKeyRingUri(mDataUri); - mKeyRing = (PGPSecretKeyRing) new ProviderHelper(this).getPGPKeyRing(secretUri); - - PGPSecretKey masterKey = mKeyRing.getSecretKey(); - mMasterCanSign = PgpKeyHelper.isCertificationKey(mKeyRing.getSecretKey()); - for (PGPSecretKey key : new IterableIterator(mKeyRing.getSecretKeys())) { - mKeys.add(key); - mKeysUsages.add(-1); // get usage when view is created + Uri secretUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + CachedSecretKeyRing keyRing = new ProviderHelper(this).getCachedSecretKeyRing(secretUri); + + mMasterCanSign = keyRing.getSubKey().canCertify(); + for (CachedSecretKey key : keyRing.iterator()) { + // Turn into uncached instance + mKeys.add(key.getUncached()); + mKeysUsages.add(key.getKeyUsage()); // get usage when view is created } boolean isSet = false; - for (String userId : new IterableIterator(masterKey.getUserIDs())) { + for (String userId : keyRing.getSubKey().getUserIds()) { Log.d(Constants.TAG, "Added userId " + userId); if (!isSet) { isSet = true; @@ -313,7 +311,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener buildLayout(false); mCurrentPassphrase = ""; - mIsPassphraseSet = PassphraseCacheService.hasPassphrase(mKeyRing); + mIsPassphraseSet = keyRing.hasPassphrase(); if (!mIsPassphraseSet) { // check "no passphrase" checkbox and remove button mNoPassphrase.setChecked(true); @@ -431,7 +429,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener if (mKeysView.getEditors().getChildCount() == 0) { return 0; } - return ((KeyEditor) mKeysView.getEditors().getChildAt(0)).getValue().getKeyID(); + return ((KeyEditor) mKeysView.getEditors().getChildAt(0)).getValue().getKeyId(); } public boolean isPassphraseSet() { @@ -571,7 +569,6 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener saveParams.keys = getKeys(mKeysView); saveParams.originalPrimaryID = mUserIdsView.getOriginalPrimaryID(); - // fill values for this action Bundle data = new Bundle(); data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, mMasterCanSign); @@ -590,7 +587,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener Intent data = new Intent(); // return uri pointing to new created key - Uri uri = KeychainContract.KeyRings.buildGenericKeyRingUri( + Uri uri = KeyRings.buildGenericKeyRingUri( String.valueOf(getMasterKeyId())); data.setData(uri); @@ -689,8 +686,8 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener * @param keysView * @return */ - private ArrayList getKeys(SectionView keysView) throws PgpGeneralException { - ArrayList keys = new ArrayList(); + private ArrayList getKeys(SectionView keysView) throws PgpGeneralException { + ArrayList keys = new ArrayList(); ViewGroup keyEditors = keysView.getEditors(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index 1628c9e95..e1a603787 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -39,21 +39,18 @@ import android.widget.TextView; import com.beardedhen.androidbootstrap.BootstrapButton; import org.spongycastle.bcpg.sig.KeyFlags; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSecretKey; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.util.Choice; +import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; -import java.util.Vector; public class KeyEditor extends LinearLayout implements Editor, OnClickListener { - private PGPSecretKey mKey; + private UncachedSecretKey mKey; private EditorListener mEditorListener = null; @@ -208,7 +205,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } } - public void setValue(PGPSecretKey key, boolean isMasterKey, int usage, boolean isNewKey) { + public void setValue(UncachedSecretKey key, boolean isMasterKey, int usage, boolean isNewKey) { mKey = key; mIsMasterKey = isMasterKey; @@ -216,13 +213,12 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { mDeleteButton.setVisibility(View.INVISIBLE); } - mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(getContext(), key)); - String keyIdStr = PgpKeyHelper.convertKeyIdToHex(key.getKeyID()); + mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(getContext(), key.getAlgorithm())); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(key.getKeyId()); mKeyId.setText(keyIdStr); - Vector choices = new Vector(); - boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT); - boolean isDSAKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.DSA); + boolean isElGamalKey = (key.isElGamalEncrypt()); + boolean isDSAKey = (key.isDSA()); if (isElGamalKey) { mChkSign.setVisibility(View.INVISIBLE); TableLayout table = (TableLayout) findViewById(R.id.table_keylayout); @@ -254,32 +250,35 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { ((usage & KeyFlags.ENCRYPT_STORAGE) == KeyFlags.ENCRYPT_STORAGE)); mChkAuthenticate.setChecked((usage & KeyFlags.AUTHENTICATION) == KeyFlags.AUTHENTICATION); } else { - mUsage = PgpKeyHelper.getKeyUsage(key); + mUsage = key.getKeyUsage(); mOriginalUsage = mUsage; if (key.isMasterKey()) { - mChkCertify.setChecked(PgpKeyHelper.isCertificationKey(key)); + mChkCertify.setChecked(key.canCertify()); } - mChkSign.setChecked(PgpKeyHelper.isSigningKey(key)); - mChkEncrypt.setChecked(PgpKeyHelper.isEncryptionKey(key)); - mChkAuthenticate.setChecked(PgpKeyHelper.isAuthenticationKey(key)); + mChkSign.setChecked(key.canSign()); + mChkEncrypt.setChecked(key.canEncrypt()); + mChkAuthenticate.setChecked(key.canAuthenticate()); } - Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - cal.setTime(PgpKeyHelper.getCreationDate(key)); - setCreatedDate(cal); - cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - Date expiryDate = PgpKeyHelper.getExpiryDate(key); + { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.setTime(key.getCreationTime()); + setCreatedDate(cal); + } + + Date expiryDate = key.getExpiryTime(); if (expiryDate == null) { setExpiryDate(null); } else { - cal.setTime(PgpKeyHelper.getExpiryDate(key)); + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.setTime(expiryDate); setExpiryDate(cal); mOriginalExpiryDate = cal; } } - public PGPSecretKey getValue() { + public UncachedSecretKey getValue() { return mKey; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index a7719012a..35ebfcd58 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -36,9 +36,9 @@ import android.widget.TextView; import com.beardedhen.androidbootstrap.BootstrapButton; import org.spongycastle.openpgp.PGPKeyFlags; -import org.spongycastle.openpgp.PGPSecretKey; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; +import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; @@ -63,7 +63,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor private int mNewKeySize; private boolean mOldItemDeleted = false; private ArrayList mDeletedIDs = new ArrayList(); - private ArrayList mDeletedKeys = new ArrayList(); + private ArrayList mDeletedKeys = new ArrayList(); private boolean mCanBeEdited = true; private ActionBarActivity mActivity; @@ -227,7 +227,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor return mDeletedIDs; } - public ArrayList getDeletedKeys() { + public ArrayList getDeletedKeys() { return mDeletedKeys; } @@ -325,7 +325,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor this.updateEditorsVisible(); } - public void setKeys(Vector list, Vector usages, boolean newKeys) { + public void setKeys(Vector list, Vector usages, boolean newKeys) { if (mType != TYPE_KEY) { return; } @@ -358,9 +358,9 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor String passphrase; if (mEditors.getChildCount() > 0) { - PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue(); + UncachedSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue(); passphrase = PassphraseCacheService - .getCachedPassphrase(mActivity, masterKey.getKeyID()); + .getCachedPassphrase(mActivity, masterKey.getKeyId()); isMasterKey = false; } else { passphrase = ""; @@ -395,7 +395,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { // get new key from data bundle returned from service Bundle data = message.getData(); - PGPSecretKey newKey = (PGPSecretKey) PgpConversionHelper + UncachedSecretKey newKey = PgpConversionHelper .BytesToPGPSecretKey(data .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); addGeneratedKeyToView(newKey); @@ -413,7 +413,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor mActivity.startService(intent); } - private void addGeneratedKeyToView(PGPSecretKey newKey) { + private void addGeneratedKeyToView(UncachedSecretKey newKey) { // add view with new key KeyEditor view = (KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, false); -- cgit v1.2.3 From 90ac60b6db0637fbefbce5cb2cd80a64f5bb708d Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 4 May 2014 17:44:10 +0200 Subject: wrapped-key-ring: remove more unneeded methods --- .../keychain/pgp/PgpKeyHelper.java | 91 ---------------------- .../keychain/provider/ProviderHelper.java | 17 ---- .../keychain/ui/ViewKeyActivity.java | 8 +- 3 files changed, 4 insertions(+), 112 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index 77697b026..59a48e7eb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -57,11 +57,6 @@ public class PgpKeyHelper { return key.getCreationTime(); } - @Deprecated - public static Date getCreationDate(PGPSecretKey key) { - return key.getPublicKey().getCreationTime(); - } - @Deprecated public static Date getExpiryDate(PGPPublicKey key) { Date creationDate = getCreationDate(key); @@ -76,38 +71,6 @@ public class PgpKeyHelper { return calendar.getTime(); } - @Deprecated - public static Date getExpiryDate(PGPSecretKey key) { - return getExpiryDate(key.getPublicKey()); - } - - public static int getKeyUsage(PGPSecretKey key) { - return getKeyUsage(key.getPublicKey()); - } - - @SuppressWarnings("unchecked") - private static int getKeyUsage(PGPPublicKey key) { - int usage = 0; - if (key.getVersion() >= 4) { - for (PGPSignature sig : new IterableIterator(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - if (hashed != null) { - usage |= hashed.getKeyFlags(); - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - if (unhashed != null) { - usage |= unhashed.getKeyFlags(); - } - } - } - return usage; - } - @SuppressWarnings("unchecked") @Deprecated public static boolean isEncryptionKey(PGPPublicKey key) { @@ -150,10 +113,6 @@ public class PgpKeyHelper { return false; } - public static boolean isEncryptionKey(PGPSecretKey key) { - return isEncryptionKey(key.getPublicKey()); - } - @SuppressWarnings("unchecked") @Deprecated public static boolean isSigningKey(PGPPublicKey key) { @@ -186,11 +145,6 @@ public class PgpKeyHelper { return false; } - @Deprecated - public static boolean isSigningKey(PGPSecretKey key) { - return isSigningKey(key.getPublicKey()); - } - @SuppressWarnings("unchecked") @Deprecated public static boolean isCertificationKey(PGPPublicKey key) { @@ -218,51 +172,6 @@ public class PgpKeyHelper { return false; } - @Deprecated - public static boolean isAuthenticationKey(PGPSecretKey key) { - return isAuthenticationKey(key.getPublicKey()); - } - - @SuppressWarnings("unchecked") - @Deprecated - public static boolean isAuthenticationKey(PGPPublicKey key) { - if (key.getVersion() <= 3) { - return true; - } - - for (PGPSignature sig : new IterableIterator(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - - if (hashed != null && (hashed.getKeyFlags() & KeyFlags.AUTHENTICATION) != 0) { - return true; - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - - if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.AUTHENTICATION) != 0) { - return true; - } - } - - return false; - } - - @Deprecated - public static boolean isCertificationKey(PGPSecretKey key) { - return isCertificationKey(key.getPublicKey()); - } - - public static String getAlgorithmInfo(Context context, PGPPublicKey key) { - return getAlgorithmInfo(context, key.getAlgorithm(), key.getBitStrength()); - } - - public static String getAlgorithmInfo(Context context, PGPSecretKey key) { - return getAlgorithmInfo(context, key.getPublicKey()); - } - /** * TODO: Only used in HkpKeyServer. Get rid of this one! */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index d1a003ec1..0784a0f33 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -263,23 +263,6 @@ public class ProviderHelper { } } - @Deprecated - public PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(long keyId) - throws NotFoundException { - Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)); - long masterKeyId = getMasterKeyId(uri); - return getPGPSecretKeyRing(masterKeyId); - } - - /** - * Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId - */ - @Deprecated - public PGPPublicKeyRing getPGPPublicKeyRing(long masterKeyId) throws NotFoundException { - Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)); - return (PGPPublicKeyRing) getPGPKeyRing(queryUri); - } - /** * Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index e595c1889..79f409663 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -367,10 +367,10 @@ public class ViewKeyActivity extends ActionBarActivity { try { Uri blobUri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); - mNfcKeyringBytes = mProviderHelper.getPGPKeyRing( - blobUri).getEncoded(); - } catch (IOException e) { - Log.e(Constants.TAG, "Error parsing keyring", e); + mNfcKeyringBytes = (byte[]) mProviderHelper.getGenericData( + blobUri, + KeychainContract.KeyRingData.KEY_RING_DATA, + ProviderHelper.FIELD_TYPE_BLOB); } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); } -- cgit v1.2.3 From 761d87b661ef14023870ad7be107d33d69ab03e7 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 21 May 2014 21:07:32 +0200 Subject: wrapped-key-ring: split up CachedKeyRing and WrappedKeyRing --- .../keychain/pgp/CachedKeyRing.java | 68 -------- .../keychain/pgp/CachedPublicKey.java | 62 ------- .../keychain/pgp/CachedPublicKeyRing.java | 184 -------------------- .../keychain/pgp/CachedSecretKey.java | 189 --------------------- .../keychain/pgp/CachedSecretKeyRing.java | 128 -------------- .../sufficientlysecure/keychain/pgp/KeyRing.java | 25 +++ .../keychain/pgp/PgpDecryptVerify.java | 30 ++-- .../keychain/pgp/PgpImportExport.java | 5 +- .../keychain/pgp/PgpKeyHelper.java | 3 - .../keychain/pgp/PgpKeyOperation.java | 4 +- .../keychain/pgp/PgpSignEncrypt.java | 10 +- .../keychain/pgp/WrappedKeyRing.java | 81 +++++++++ .../keychain/pgp/WrappedPublicKey.java | 62 +++++++ .../keychain/pgp/WrappedPublicKeyRing.java | 179 +++++++++++++++++++ .../keychain/pgp/WrappedSecretKey.java | 189 +++++++++++++++++++++ .../keychain/pgp/WrappedSecretKeyRing.java | 123 ++++++++++++++ .../pgp/exception/PgpGeneralException.java | 3 + .../keychain/provider/CachedPublicKeyRing.java | 125 ++++++++++++++ .../keychain/provider/KeychainProvider.java | 2 +- .../keychain/provider/ProviderHelper.java | 63 +++---- .../keychain/remote/OpenPgpService.java | 2 +- .../keychain/service/KeychainIntentService.java | 24 +-- .../keychain/service/PassphraseCacheService.java | 6 +- .../keychain/ui/EditKeyActivity.java | 9 +- .../keychain/ui/EncryptAsymmetricFragment.java | 6 +- .../keychain/ui/ViewCertActivity.java | 6 +- .../ui/dialog/PassphraseDialogFragment.java | 27 +-- 27 files changed, 887 insertions(+), 728 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java deleted file mode 100644 index def673469..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedKeyRing.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -public abstract class CachedKeyRing { - - private final long mMasterKeyId; - private final String mUserId; - private final boolean mHasAnySecret; - private final boolean mIsRevoked; - private final boolean mCanCertify; - private final long mHasEncryptId; - private final long mHasSignId; - private final int mVerified; - - protected CachedKeyRing(long masterKeyId, String userId, boolean hasAnySecret, - boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId, - int verified) - { - mMasterKeyId = masterKeyId; - mUserId = userId; - mHasAnySecret = hasAnySecret; - mIsRevoked = isRevoked; - mCanCertify = canCertify; - mHasEncryptId = hasEncryptId; - mHasSignId = hasSignId; - mVerified = verified; - } - - public long getMasterKeyId() { - return mMasterKeyId; - } - - public String getPrimaryUserId() { - return mUserId; - } - - public boolean hasAnySecret() { - return mHasAnySecret; - } - - public boolean isRevoked() { - return mIsRevoked; - } - - public boolean canCertify() { - return mCanCertify; - } - - public long getEncryptId() { - return mHasEncryptId; - } - - public boolean hasEncrypt() { - return mHasEncryptId != 0; - } - - public long getSignId() { - return mHasSignId; - } - - public boolean hasSign() { - return mHasSignId != 0; - } - - public int getVerified() { - return mVerified; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java deleted file mode 100644 index dee03db6f..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKey.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPOnePassSignature; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; -import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.IterableIterator; - -import java.security.SignatureException; - -public class CachedPublicKey extends UncachedPublicKey { - - // this is the parent key ring - final CachedKeyRing mRing; - - CachedPublicKey(CachedKeyRing ring, PGPPublicKey key) { - super(key); - mRing = ring; - } - - public IterableIterator getUserIds() { - return new IterableIterator(mPublicKey.getUserIDs()); - } - - public CachedKeyRing getKeyRing() { - return mRing; - } - - JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() { - return new JcePublicKeyKeyEncryptionMethodGenerator(mPublicKey); - } - - public void initSignature(PGPSignature sig) throws PGPException { - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - sig.init(contentVerifierBuilderProvider, mPublicKey); - } - - public void initSignature(PGPOnePassSignature sig) throws PGPException { - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - sig.init(contentVerifierBuilderProvider, mPublicKey); - } - - /** Verify a signature for this pubkey, after it has been initialized by the signer using - * initSignature(). This method should probably move into a wrapped PGPSignature class - * at some point. - */ - public boolean verifySignature(PGPSignature sig, String uid) throws PGPException { - try { - return sig.verifyCertification(uid, mPublicKey); - } catch (SignatureException e) { - throw new PGPException("Error!", e); - } - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java deleted file mode 100644 index 108ed1a4a..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedPublicKeyRing.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.bcpg.ArmoredOutputStream; -import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureList; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.util.IterableIterator; - -import java.io.IOException; -import java.security.SignatureException; -import java.util.Arrays; -import java.util.Iterator; - -public class CachedPublicKeyRing extends CachedKeyRing { - - private PGPPublicKeyRing mRing; - private final byte[] mPubKey; - - public CachedPublicKeyRing(long masterKeyId, String userId, boolean hasAnySecret, - boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId, - int verified, byte[] blob) - { - super(masterKeyId, userId, hasAnySecret, isRevoked, canCertify, - hasEncryptId, hasSignId, verified); - - mPubKey = blob; - } - - PGPPublicKeyRing getRing() { - if(mRing == null) { - mRing = (PGPPublicKeyRing) PgpConversionHelper.BytesToPGPKeyRing(mPubKey); - } - return mRing; - } - - public void encode(ArmoredOutputStream stream) throws IOException { - getRing().encode(stream); - } - - public CachedPublicKey getSubkey() { - return new CachedPublicKey(this, getRing().getPublicKey()); - } - - public CachedPublicKey getSubkey(long id) { - return new CachedPublicKey(this, getRing().getPublicKey(id)); - } - - /** Getter that returns the subkey that should be used for signing. */ - CachedPublicKey getEncryptionSubKey() throws PgpGeneralException { - PGPPublicKey key = getRing().getPublicKey(getEncryptId()); - if(key != null) { - CachedPublicKey cKey = new CachedPublicKey(this, key); - if(!cKey.canEncrypt()) { - throw new PgpGeneralException("key error"); - } - return cKey; - } - // TODO handle with proper exception - throw new PgpGeneralException("no encryption key available"); - } - - public boolean verifySubkeyBinding(CachedPublicKey cachedSubkey) { - boolean validSubkeyBinding = false; - boolean validTempSubkeyBinding = false; - boolean validPrimaryKeyBinding = false; - - PGPPublicKey masterKey = getRing().getPublicKey(); - PGPPublicKey subKey = cachedSubkey.getPublicKey(); - - // Is this the master key? Match automatically, then. - if(Arrays.equals(masterKey.getFingerprint(), subKey.getFingerprint())) { - return true; - } - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - Iterator itr = subKey.getSignatures(); - - while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong? - //gpg has an invalid subkey binding error on key import I think, but doesn't shout - //about keys without subkey signing. Can't get it to import a slightly broken one - //either, so we will err on bad subkey binding here. - PGPSignature sig = itr.next(); - if (sig.getKeyID() == masterKey.getKeyID() && - sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) { - //check and if ok, check primary key binding. - try { - sig.init(contentVerifierBuilderProvider, masterKey); - validTempSubkeyBinding = sig.verifyCertification(masterKey, subKey); - } catch (PGPException e) { - continue; - } catch (SignatureException e) { - continue; - } - - if (validTempSubkeyBinding) { - validSubkeyBinding = true; - } - if (validTempSubkeyBinding) { - validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(), - masterKey, subKey); - if (validPrimaryKeyBinding) { - break; - } - validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(), - masterKey, subKey); - if (validPrimaryKeyBinding) { - break; - } - } - } - } - return validSubkeyBinding && validPrimaryKeyBinding; - - } - - static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts, - PGPPublicKey masterPublicKey, - PGPPublicKey signingPublicKey) { - boolean validPrimaryKeyBinding = false; - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - PGPSignatureList eSigList; - - if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) { - try { - eSigList = pkts.getEmbeddedSignatures(); - } catch (IOException e) { - return false; - } catch (PGPException e) { - return false; - } - for (int j = 0; j < eSigList.size(); ++j) { - PGPSignature emSig = eSigList.get(j); - if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) { - try { - emSig.init(contentVerifierBuilderProvider, signingPublicKey); - validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey); - if (validPrimaryKeyBinding) { - break; - } - } catch (PGPException e) { - continue; - } catch (SignatureException e) { - continue; - } - } - } - } - - return validPrimaryKeyBinding; - } - - public IterableIterator iterator() { - final Iterator it = getRing().getPublicKeys(); - return new IterableIterator(new Iterator() { - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public CachedPublicKey next() { - return new CachedPublicKey(CachedPublicKeyRing.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/CachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java deleted file mode 100644 index 8e45ceb4f..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKey.java +++ /dev/null @@ -1,189 +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; - -public class CachedSecretKey extends CachedPublicKey { - - private final PGPSecretKey mSecretKey; - private PGPPrivateKey mPrivateKey = null; - - CachedSecretKey(CachedSecretKeyRing ring, PGPSecretKey key) { - super(ring, key.getPublicKey()); - mSecretKey = key; - } - - public CachedSecretKeyRing getRing() { - return (CachedSecretKeyRing) mRing; - } - - /** Returns the wrapped PGPSecretKeyRing. - * This function is for compatibility only, should not be used anymore and will be removed - */ - @Deprecated - public PGPSecretKey getKeyExternal() { - return mSecretKey; - } - - public boolean unlock(String passphrase) throws PgpGeneralException { - try { - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); - mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor); - } catch (PGPException e) { - return false; - } - if(mPrivateKey == null) { - throw new PgpGeneralException("error extracting key"); - } - return true; - } - - public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext) - throws PgpGeneralException { - if(mPrivateKey == null) { - throw new PrivateKeyNotUnlockedException(); - } - - // content signer based on signing key algorithm and chosen hash algorithm - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - mSecretKey.getPublicKey().getAlgorithm(), hashAlgo) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - int signatureType; - if (cleartext) { - // for sign-only ascii text - signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; - } else { - signatureType = PGPSignature.BINARY_DOCUMENT; - } - - try { - PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(signatureType, mPrivateKey); - - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - spGen.setSignerUserID(false, mRing.getPrimaryUserId()); - signatureGenerator.setHashedSubpackets(spGen.generate()); - return signatureGenerator; - } catch(PGPException e) { - throw new PgpGeneralException("Error initializing signature!", e); - } - } - - public PGPV3SignatureGenerator getV3SignatureGenerator(int hashAlgo, boolean cleartext) - throws PgpGeneralException { - if(mPrivateKey == null) { - throw new PrivateKeyNotUnlockedException(); - } - - // content signer based on signing key algorithm and chosen hash algorithm - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - mSecretKey.getPublicKey().getAlgorithm(), hashAlgo) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - int signatureType; - if (cleartext) { - // for sign-only ascii text - signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; - } else { - signatureType = PGPSignature.BINARY_DOCUMENT; - } - - try { - PGPV3SignatureGenerator signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder); - signatureV3Generator.init(signatureType, mPrivateKey); - return signatureV3Generator; - } catch(PGPException e) { - throw new PgpGeneralException("Error initializing signature!", e); - } - } - - public PublicKeyDataDecryptorFactory getDecryptorFactory() { - if(mPrivateKey == null) { - throw new PrivateKeyNotUnlockedException(); - } - return new JcePublicKeyDataDecryptorFactoryBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey); - } - - /** - * Certify the given pubkeyid with the given masterkeyid. - * - * @param publicKeyRing Keyring to add certification to. - * @param userIds User IDs to certify, must not be null or empty - * @return A keyring with added certifications - */ - public UncachedKeyRing certifyUserIds(CachedPublicKeyRing 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.getSubkey().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/CachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java deleted file mode 100644 index 398092aeb..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CachedSecretKeyRing.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.util.IterableIterator; - -import java.io.IOException; -import java.security.NoSuchProviderException; -import java.util.Iterator; - -public class CachedSecretKeyRing extends CachedKeyRing { - - private PGPSecretKeyRing mRing; - - public CachedSecretKeyRing(long masterKeyId, String userId, boolean hasAnySecret, - boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId, - int verified, byte[] blob) - { - super(masterKeyId, userId, hasAnySecret, - isRevoked, canCertify, hasEncryptId, hasSignId, - verified); - - mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob); - } - - PGPSecretKeyRing getRing() { - return mRing; - } - - public CachedSecretKey getSubKey() { - return new CachedSecretKey(this, mRing.getSecretKey()); - } - - public CachedSecretKey getSubKey(long id) { - return new CachedSecretKey(this, mRing.getSecretKey(id)); - } - - /** Getter that returns the subkey that should be used for signing. */ - CachedSecretKey getSigningSubKey() throws PgpGeneralException { - PGPSecretKey key = mRing.getSecretKey(getSignId()); - if(key != null) { - CachedSecretKey cKey = new CachedSecretKey(this, key); - if(!cKey.canSign()) { - throw new PgpGeneralException("key error"); - } - return cKey; - } - // TODO handle with proper exception - throw new PgpGeneralException("no signing key available"); - } - - public boolean hasPassphrase() { - PGPSecretKey secretKey = null; - boolean foundValidKey = false; - for (Iterator keys = mRing.getSecretKeys(); keys.hasNext(); ) { - secretKey = (PGPSecretKey) keys.next(); - if (!secretKey.isPrivateKeyEmpty()) { - foundValidKey = true; - break; - } - } - if(!foundValidKey) { - return false; - } - - try { - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() - .setProvider("SC").build("".toCharArray()); - PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor); - return testKey == null; - } catch(PGPException e) { - // this means the crc check failed -> passphrase required - return true; - } - } - - public UncachedSecretKeyRing changeSecretKeyPassphrase(String oldPassphrase, - String newPassphrase) - throws IOException, PGPException, NoSuchProviderException { - - if (oldPassphrase == null) { - oldPassphrase = ""; - } - if (newPassphrase == null) { - newPassphrase = ""; - } - - PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword( - mRing, - new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()), - new JcePBESecretKeyEncryptorBuilder(mRing.getSecretKey() - .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray())); - - return new UncachedSecretKeyRing(newKeyRing); - - } - - public IterableIterator iterator() { - final Iterator it = mRing.getSecretKeys(); - return new IterableIterator(new Iterator() { - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public CachedSecretKey next() { - return new CachedSecretKey(CachedSecretKeyRing.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 new file mode 100644 index 000000000..cfbad89b7 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java @@ -0,0 +1,25 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; + +public abstract class KeyRing { + + abstract public long getMasterKeyId() throws PgpGeneralException; + + abstract public String getPrimaryUserId() throws PgpGeneralException; + + abstract public boolean isRevoked() throws PgpGeneralException; + + abstract public boolean canCertify() throws PgpGeneralException; + + abstract public long getEncryptId() throws PgpGeneralException; + + abstract public boolean hasEncrypt() throws PgpGeneralException; + + abstract public long getSignId() throws PgpGeneralException; + + abstract public boolean hasSign() throws PgpGeneralException; + + abstract public int getVerified() throws PgpGeneralException; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 27e9e8ebd..21a7c20e3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -233,7 +233,7 @@ public class PgpDecryptVerify { PGPPublicKeyEncryptedData encryptedDataAsymmetric = null; PGPPBEEncryptedData encryptedDataSymmetric = null; - CachedSecretKey secretEncryptionKey = null; + WrappedSecretKey secretEncryptionKey = null; Iterator it = enc.getEncryptedDataObjects(); boolean asymmetricPacketFound = false; boolean symmetricPacketFound = false; @@ -245,10 +245,10 @@ public class PgpDecryptVerify { PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj; - CachedSecretKeyRing secretKeyRing; + WrappedSecretKeyRing secretKeyRing; try { // get actual keyring object based on master key id - secretKeyRing = mProviderHelper.getCachedSecretKeyRing( + secretKeyRing = mProviderHelper.getWrappedSecretKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( Long.toString(encData.getKeyID())) ); @@ -368,8 +368,8 @@ public class PgpDecryptVerify { Object dataChunk = plainFact.nextObject(); OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); int signatureIndex = -1; - CachedPublicKeyRing signingRing = null; - CachedPublicKey signingKey = null; + WrappedPublicKeyRing signingRing = null; + WrappedPublicKey signingKey = null; if (dataChunk instanceof PGPCompressedData) { updateProgress(R.string.progress_decompressing_data, currentProgress, 100); @@ -393,7 +393,7 @@ public class PgpDecryptVerify { for (int i = 0; i < sigList.size(); ++i) { try { long sigKeyId = sigList.get(i).getKeyID(); - signingRing = mProviderHelper.getCachedPublicKeyRing( + signingRing = mProviderHelper.getWrappedPublicKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( Long.toString(sigKeyId) ) @@ -413,7 +413,11 @@ public class PgpDecryptVerify { signatureResultBuilder.signatureAvailable(true); signatureResultBuilder.knownKey(true); signatureResultBuilder.keyId(signingRing.getMasterKeyId()); - signatureResultBuilder.userId(signingRing.getPrimaryUserId()); + try { + signatureResultBuilder.userId(signingRing.getPrimaryUserId()); + } catch(PgpGeneralException e) { + Log.d(Constants.TAG, "No primary user id in key " + signingRing.getMasterKeyId()); + } signatureResultBuilder.signatureKeyCertified(signingRing.getVerified() > 0); signingKey.initSignature(signature); @@ -567,8 +571,8 @@ public class PgpDecryptVerify { throw new InvalidDataException(); } - CachedPublicKeyRing signingRing = null; - CachedPublicKey signingKey = null; + WrappedPublicKeyRing signingRing = null; + WrappedPublicKey signingKey = null; int signatureIndex = -1; // go through all signatures @@ -576,7 +580,7 @@ public class PgpDecryptVerify { for (int i = 0; i < sigList.size(); ++i) { try { long sigKeyId = sigList.get(i).getKeyID(); - signingRing = mProviderHelper.getCachedPublicKeyRing( + signingRing = mProviderHelper.getWrappedPublicKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( Long.toString(sigKeyId) ) @@ -598,7 +602,11 @@ public class PgpDecryptVerify { signatureResultBuilder.signatureAvailable(true); signatureResultBuilder.knownKey(true); signatureResultBuilder.keyId(signingRing.getMasterKeyId()); - signatureResultBuilder.userId(signingRing.getPrimaryUserId()); + try { + signatureResultBuilder.userId(signingRing.getPrimaryUserId()); + } catch(PgpGeneralException e) { + Log.d(Constants.TAG, "No primary user id in key " + signingRing.getMasterKeyId()); + } signatureResultBuilder.signatureKeyCertified(signingRing.getVerified() > 0); signingKey.initSignature(signature); 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 a0d2d5cea..5c4604647 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -27,7 +27,6 @@ import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.sufficientlysecure.keychain.Constants; @@ -101,7 +100,7 @@ public class PgpImportExport { } } - public boolean uploadKeyRingToServer(HkpKeyServer server, CachedPublicKeyRing keyring) { + public boolean uploadKeyRingToServer(HkpKeyServer server, WrappedPublicKeyRing keyring) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ArmoredOutputStream aos = null; try { @@ -229,7 +228,7 @@ public class PgpImportExport { updateProgress(progress * 100 / masterKeyIdsSize, 100); try { - CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing( + WrappedPublicKeyRing ring = mProviderHelper.getWrappedPublicKeyRing( KeychainContract.KeyRings.buildGenericKeyRingUri(pubKeyMasterId) ); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index 59a48e7eb..b25c38f1a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -72,7 +72,6 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") - @Deprecated public static boolean isEncryptionKey(PGPPublicKey key) { if (!key.isEncryptionKey()) { return false; @@ -114,7 +113,6 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") - @Deprecated public static boolean isSigningKey(PGPPublicKey key) { if (key.getVersion() <= 3) { return true; @@ -146,7 +144,6 @@ public class PgpKeyHelper { } @SuppressWarnings("unchecked") - @Deprecated public static boolean isCertificationKey(PGPPublicKey key) { if (key.getVersion() <= 3) { return true; 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 d0ca77da7..b9634c34a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -337,8 +337,8 @@ public class PgpKeyOperation { } - public UncachedKeyRing buildSecretKey(CachedSecretKeyRing wmKR, - CachedPublicKeyRing wpKR, + public UncachedKeyRing buildSecretKey(WrappedSecretKeyRing wmKR, + WrappedPublicKeyRing wpKR, SaveKeyringParcel saveParcel) throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { 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 96ee3f10a..24d090d04 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 */ - CachedSecretKey signingKey = null; + WrappedSecretKey signingKey = null; if (enableSignature) { - CachedSecretKeyRing signingKeyRing; + WrappedSecretKeyRing signingKeyRing; try { - signingKeyRing = mProviderHelper.getCachedSecretKeyRing(mSignatureMasterKeyId); + signingKeyRing = mProviderHelper.getWrappedSecretKeyRing(mSignatureMasterKeyId); } catch (ProviderHelper.NotFoundException e) { throw new NoSigningKeyException(); } @@ -316,9 +316,9 @@ public class PgpSignEncrypt { // Asymmetric encryption for (long id : mEncryptionMasterKeyIds) { try { - CachedPublicKeyRing keyRing = mProviderHelper.getCachedPublicKeyRing( + WrappedPublicKeyRing keyRing = mProviderHelper.getWrappedPublicKeyRing( KeyRings.buildUnifiedKeyRingUri(Long.toString(id))); - CachedPublicKey key = keyRing.getEncryptionSubKey(); + WrappedPublicKey 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/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java new file mode 100644 index 000000000..94eb91420 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java @@ -0,0 +1,81 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPKeyRing; +import org.spongycastle.openpgp.PGPPublicKey; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.IterableIterator; + +public abstract class WrappedKeyRing extends KeyRing { + + private final boolean mHasAnySecret; + private final int mVerified; + + WrappedKeyRing(boolean hasAnySecret, int verified) { + mHasAnySecret = hasAnySecret; + mVerified = verified; + } + + public long getMasterKeyId() { + return getRing().getPublicKey().getKeyID(); + } + + public boolean hasAnySecret() { + return mHasAnySecret; + } + + public int getVerified() { + return mVerified; + } + + public String getPrimaryUserId() throws PgpGeneralException { + return (String) getRing().getPublicKey().getUserIDs().next(); + }; + + public boolean isRevoked() throws PgpGeneralException { + // Is the master key revoked? + return getRing().getPublicKey().isRevoked(); + } + + public boolean canCertify() throws PgpGeneralException { + return getRing().getPublicKey().isEncryptionKey(); + } + + public long getEncryptId() throws PgpGeneralException { + for(PGPPublicKey key : new IterableIterator(getRing().getPublicKeys())) { + if(PgpKeyHelper.isEncryptionKey(key)) { + return key.getKeyID(); + } + } + throw new PgpGeneralException("No valid encryption key found!"); + } + + public boolean hasEncrypt() throws PgpGeneralException { + try { + getEncryptId(); + return true; + } catch(PgpGeneralException e) { + return false; + } + } + + public long getSignId() throws PgpGeneralException { + for(PGPPublicKey key : new IterableIterator(getRing().getPublicKeys())) { + if(PgpKeyHelper.isSigningKey(key)) { + return key.getKeyID(); + } + } + throw new PgpGeneralException("No valid signing key found!"); + } + + public boolean hasSign() throws PgpGeneralException { + try { + getSignId(); + return true; + } catch (PgpGeneralException e) { + return false; + } + } + + abstract PGPKeyRing getRing(); + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java new file mode 100644 index 000000000..72352a451 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java @@ -0,0 +1,62 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.security.SignatureException; + +public class WrappedPublicKey extends UncachedPublicKey { + + // this is the parent key ring + final KeyRing mRing; + + WrappedPublicKey(KeyRing ring, PGPPublicKey key) { + super(key); + mRing = ring; + } + + public IterableIterator getUserIds() { + return new IterableIterator(mPublicKey.getUserIDs()); + } + + public KeyRing getKeyRing() { + return mRing; + } + + JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() { + return new JcePublicKeyKeyEncryptionMethodGenerator(mPublicKey); + } + + public void initSignature(PGPSignature sig) throws PGPException { + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + sig.init(contentVerifierBuilderProvider, mPublicKey); + } + + public void initSignature(PGPOnePassSignature sig) throws PGPException { + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + sig.init(contentVerifierBuilderProvider, mPublicKey); + } + + /** Verify a signature for this pubkey, after it has been initialized by the signer using + * initSignature(). This method should probably move into a wrapped PGPSignature class + * at some point. + */ + public boolean verifySignature(PGPSignature sig, String uid) throws PGPException { + try { + return sig.verifyCertification(uid, mPublicKey); + } catch (SignatureException e) { + throw new PGPException("Error!", e); + } + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java new file mode 100644 index 000000000..624382165 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java @@ -0,0 +1,179 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.bcpg.SignatureSubpacketTags; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.io.IOException; +import java.security.SignatureException; +import java.util.Arrays; +import java.util.Iterator; + +public class WrappedPublicKeyRing extends WrappedKeyRing { + + private PGPPublicKeyRing mRing; + private final byte[] mPubKey; + + public WrappedPublicKeyRing(byte[] blob, boolean hasAnySecret, int verified) { + super(hasAnySecret, verified); + mPubKey = blob; + } + + PGPPublicKeyRing getRing() { + if(mRing == null) { + mRing = (PGPPublicKeyRing) PgpConversionHelper.BytesToPGPKeyRing(mPubKey); + } + return mRing; + } + + public void encode(ArmoredOutputStream stream) throws IOException { + getRing().encode(stream); + } + + public WrappedPublicKey getSubkey() { + return new WrappedPublicKey(this, getRing().getPublicKey()); + } + + public WrappedPublicKey getSubkey(long id) { + return new WrappedPublicKey(this, getRing().getPublicKey(id)); + } + + /** Getter that returns the subkey that should be used for signing. */ + WrappedPublicKey getEncryptionSubKey() throws PgpGeneralException { + PGPPublicKey key = getRing().getPublicKey(getEncryptId()); + if(key != null) { + WrappedPublicKey cKey = new WrappedPublicKey(this, key); + if(!cKey.canEncrypt()) { + throw new PgpGeneralException("key error"); + } + return cKey; + } + // TODO handle with proper exception + throw new PgpGeneralException("no encryption key available"); + } + + public boolean verifySubkeyBinding(WrappedPublicKey cachedSubkey) { + boolean validSubkeyBinding = false; + boolean validTempSubkeyBinding = false; + boolean validPrimaryKeyBinding = false; + + PGPPublicKey masterKey = getRing().getPublicKey(); + PGPPublicKey subKey = cachedSubkey.getPublicKey(); + + // Is this the master key? Match automatically, then. + if(Arrays.equals(masterKey.getFingerprint(), subKey.getFingerprint())) { + return true; + } + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + + Iterator itr = subKey.getSignatures(); + + while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong? + //gpg has an invalid subkey binding error on key import I think, but doesn't shout + //about keys without subkey signing. Can't get it to import a slightly broken one + //either, so we will err on bad subkey binding here. + PGPSignature sig = itr.next(); + if (sig.getKeyID() == masterKey.getKeyID() && + sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) { + //check and if ok, check primary key binding. + try { + sig.init(contentVerifierBuilderProvider, masterKey); + validTempSubkeyBinding = sig.verifyCertification(masterKey, subKey); + } catch (PGPException e) { + continue; + } catch (SignatureException e) { + continue; + } + + if (validTempSubkeyBinding) { + validSubkeyBinding = true; + } + if (validTempSubkeyBinding) { + validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(), + masterKey, subKey); + if (validPrimaryKeyBinding) { + break; + } + validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(), + masterKey, subKey); + if (validPrimaryKeyBinding) { + break; + } + } + } + } + return validSubkeyBinding && validPrimaryKeyBinding; + + } + + static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts, + PGPPublicKey masterPublicKey, + PGPPublicKey signingPublicKey) { + boolean validPrimaryKeyBinding = false; + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureList eSigList; + + if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) { + try { + eSigList = pkts.getEmbeddedSignatures(); + } catch (IOException e) { + return false; + } catch (PGPException e) { + return false; + } + for (int j = 0; j < eSigList.size(); ++j) { + PGPSignature emSig = eSigList.get(j); + if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) { + try { + emSig.init(contentVerifierBuilderProvider, signingPublicKey); + validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey); + if (validPrimaryKeyBinding) { + break; + } + } catch (PGPException e) { + continue; + } catch (SignatureException e) { + continue; + } + } + } + } + + return validPrimaryKeyBinding; + } + + public IterableIterator iterator() { + 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 new file mode 100644 index 000000000..a03e10098 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java @@ -0,0 +1,189 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.PGPV3SignatureGenerator; +import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SignatureException; +import java.util.List; + +public class WrappedSecretKey extends WrappedPublicKey { + + private final PGPSecretKey mSecretKey; + private PGPPrivateKey mPrivateKey = null; + + WrappedSecretKey(WrappedSecretKeyRing ring, PGPSecretKey key) { + super(ring, key.getPublicKey()); + mSecretKey = key; + } + + public WrappedSecretKeyRing getRing() { + return (WrappedSecretKeyRing) mRing; + } + + /** Returns the wrapped PGPSecretKeyRing. + * This function is for compatibility only, should not be used anymore and will be removed + */ + @Deprecated + public PGPSecretKey getKeyExternal() { + return mSecretKey; + } + + public boolean unlock(String passphrase) throws PgpGeneralException { + try { + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor); + } catch (PGPException e) { + return false; + } + if(mPrivateKey == null) { + throw new PgpGeneralException("error extracting key"); + } + return true; + } + + public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext) + throws PgpGeneralException { + if(mPrivateKey == null) { + throw new PrivateKeyNotUnlockedException(); + } + + // content signer based on signing key algorithm and chosen hash algorithm + JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( + mSecretKey.getPublicKey().getAlgorithm(), hashAlgo) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + + int signatureType; + if (cleartext) { + // for sign-only ascii text + signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; + } else { + signatureType = PGPSignature.BINARY_DOCUMENT; + } + + try { + PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); + signatureGenerator.init(signatureType, mPrivateKey); + + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + spGen.setSignerUserID(false, mRing.getPrimaryUserId()); + signatureGenerator.setHashedSubpackets(spGen.generate()); + return signatureGenerator; + } catch(PGPException e) { + throw new PgpGeneralException("Error initializing signature!", e); + } + } + + public PGPV3SignatureGenerator getV3SignatureGenerator(int hashAlgo, boolean cleartext) + throws PgpGeneralException { + if(mPrivateKey == null) { + throw new PrivateKeyNotUnlockedException(); + } + + // content signer based on signing key algorithm and chosen hash algorithm + JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( + mSecretKey.getPublicKey().getAlgorithm(), hashAlgo) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + + int signatureType; + if (cleartext) { + // for sign-only ascii text + signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; + } else { + signatureType = PGPSignature.BINARY_DOCUMENT; + } + + try { + PGPV3SignatureGenerator signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder); + signatureV3Generator.init(signatureType, mPrivateKey); + return signatureV3Generator; + } catch(PGPException e) { + throw new PgpGeneralException("Error initializing signature!", e); + } + } + + public PublicKeyDataDecryptorFactory getDecryptorFactory() { + if(mPrivateKey == null) { + throw new PrivateKeyNotUnlockedException(); + } + return new JcePublicKeyDataDecryptorFactoryBuilder() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey); + } + + /** + * Certify the given pubkeyid with the given masterkeyid. + * + * @param publicKeyRing Keyring to add certification to. + * @param userIds User IDs to certify, must not be null or empty + * @return A keyring with added certifications + */ + public UncachedKeyRing certifyUserIds(WrappedPublicKeyRing publicKeyRing, List userIds) + throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException, + PGPException, SignatureException { + + if(mPrivateKey == null) { + throw new PrivateKeyNotUnlockedException(); + } + + // create a signatureGenerator from the supplied masterKeyId and passphrase + PGPSignatureGenerator signatureGenerator; + { + // TODO: SHA256 fixed? + JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( + mSecretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + + signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); + signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey); + } + + { // supply signatureGenerator with a SubpacketVector + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + PGPSignatureSubpacketVector packetVector = spGen.generate(); + signatureGenerator.setHashedSubpackets(packetVector); + } + + // get the master subkey (which we certify for) + PGPPublicKey publicKey = publicKeyRing.getSubkey().getPublicKey(); + + // fetch public key ring, add the certification and return it + for (String userId : new IterableIterator(userIds.iterator())) { + PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); + publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); + } + + PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey); + + return new UncachedKeyRing(ring); + } + + static class PrivateKeyNotUnlockedException extends RuntimeException { + // this exception is a programming error which happens when an operation which requires + // the private key is called without a previous call to unlock() + } + + public UncachedSecretKey getUncached() { + return new UncachedSecretKey(mSecretKey); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java new file mode 100644 index 000000000..c94b7dfba --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java @@ -0,0 +1,123 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.IterableIterator; + +import java.io.IOException; +import java.security.NoSuchProviderException; +import java.util.Iterator; + +public class WrappedSecretKeyRing extends WrappedKeyRing { + + private PGPSecretKeyRing mRing; + + public WrappedSecretKeyRing(byte[] blob, boolean isRevoked, int verified) + { + super(isRevoked, verified); + mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob); + } + + PGPSecretKeyRing getRing() { + return mRing; + } + + public WrappedSecretKey getSubKey() { + return new WrappedSecretKey(this, mRing.getSecretKey()); + } + + public WrappedSecretKey getSubKey(long id) { + return new WrappedSecretKey(this, mRing.getSecretKey(id)); + } + + /** Getter that returns the subkey that should be used for signing. */ + WrappedSecretKey getSigningSubKey() throws PgpGeneralException { + PGPSecretKey key = mRing.getSecretKey(getSignId()); + if(key != null) { + WrappedSecretKey cKey = new WrappedSecretKey(this, key); + if(!cKey.canSign()) { + throw new PgpGeneralException("key error"); + } + return cKey; + } + // TODO handle with proper exception + throw new PgpGeneralException("no signing key available"); + } + + public boolean hasPassphrase() { + PGPSecretKey secretKey = null; + boolean foundValidKey = false; + for (Iterator keys = mRing.getSecretKeys(); keys.hasNext(); ) { + secretKey = (PGPSecretKey) keys.next(); + if (!secretKey.isPrivateKeyEmpty()) { + foundValidKey = true; + break; + } + } + if(!foundValidKey) { + return false; + } + + try { + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() + .setProvider("SC").build("".toCharArray()); + PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor); + return testKey == null; + } catch(PGPException e) { + // this means the crc check failed -> passphrase required + return true; + } + } + + public UncachedSecretKeyRing changeSecretKeyPassphrase(String oldPassphrase, + String newPassphrase) + throws IOException, PGPException, NoSuchProviderException { + + if (oldPassphrase == null) { + oldPassphrase = ""; + } + if (newPassphrase == null) { + newPassphrase = ""; + } + + PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword( + mRing, + new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()), + new JcePBESecretKeyEncryptorBuilder(mRing.getSecretKey() + .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray())); + + return new UncachedSecretKeyRing(newKeyRing); + + } + + public IterableIterator iterator() { + 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(); + } + }); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java index 37d21eea4..f37a61852 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java @@ -27,4 +27,7 @@ public class PgpGeneralException extends Exception { public PgpGeneralException(String message, Throwable cause) { super(message, cause); } + public PgpGeneralException(Throwable cause) { + super(cause); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java new file mode 100644 index 000000000..6f7623d65 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java @@ -0,0 +1,125 @@ +package org.sufficientlysecure.keychain.provider; + +import android.net.Uri; + +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; + +public class CachedPublicKeyRing extends KeyRing { + + final ProviderHelper mProviderHelper; + final Uri mUri; + + public CachedPublicKeyRing(ProviderHelper providerHelper, Uri uri) { + mProviderHelper = providerHelper; + mUri = uri; + } + + public long getMasterKeyId() throws PgpGeneralException { + try { + return mProviderHelper.getMasterKeyId(mUri); + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public String getPrimaryUserId() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_STRING); + return (String) data; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public boolean isRevoked() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_INTEGER); + return (Long) data > 0; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public boolean canCertify() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_INTEGER); + return (Long) data > 0; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public long getEncryptId() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_INTEGER); + return (Long) data; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public boolean hasEncrypt() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_INTEGER); + return (Long) data > 0; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public long getSignId() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_INTEGER); + return (Long) data; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public boolean hasSign() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_INTEGER); + return (Long) data > 0; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public int getVerified() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_INTEGER); + return (Integer) data; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + } + + public boolean hasAnySecret() throws PgpGeneralException { + try { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, + ProviderHelper.FIELD_TYPE_INTEGER); + return (Long) data > 0; + } catch(ProviderHelper.NotFoundException e) { + throw new PgpGeneralException(e); + } + + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 9f6314329..be7bd1556 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -261,7 +261,7 @@ public class KeychainProvider extends ContentProvider { projectionMap.put(KeyRings.PRIVKEY_DATA, Tables.KEY_RINGS_SECRET + "." + KeyRingData.KEY_RING_DATA + " AS " + KeyRings.PRIVKEY_DATA); - projectionMap.put(KeyRings.HAS_SECRET, KeyRings.HAS_SECRET); + projectionMap.put(KeyRings.HAS_SECRET, Tables.KEYS + "." + KeyRings.HAS_SECRET); projectionMap.put(KeyRings.HAS_ANY_SECRET, "(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET + " WHERE " + Tables.KEY_RINGS_SECRET + "." + KeyRingData.MASTER_KEY_ID 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 18035eefe..be769dfbe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -39,9 +39,9 @@ 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.CachedKeyRing; -import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; -import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; @@ -67,7 +67,6 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; public class ProviderHelper { @@ -198,56 +197,46 @@ public class ProviderHelper { return result; } - public CachedPublicKeyRing getCachedPublicKeyRing(long id) throws NotFoundException { - return (CachedPublicKeyRing) getCachedKeyRing( + public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) { + return new CachedPublicKeyRing(this, queryUri); + } + + public WrappedPublicKeyRing getWrappedPublicKeyRing(long id) throws NotFoundException { + return (WrappedPublicKeyRing) getWrappedKeyRing( KeyRings.buildUnifiedKeyRingUri(Long.toString(id)), false); } - public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws NotFoundException { - return (CachedPublicKeyRing) getCachedKeyRing(queryUri, false); + public WrappedPublicKeyRing getWrappedPublicKeyRing(Uri queryUri) throws NotFoundException { + return (WrappedPublicKeyRing) getWrappedKeyRing(queryUri, false); } - public CachedSecretKeyRing getCachedSecretKeyRing(long id) throws NotFoundException { - return (CachedSecretKeyRing) getCachedKeyRing( + public WrappedSecretKeyRing getWrappedSecretKeyRing(long id) throws NotFoundException { + return (WrappedSecretKeyRing) getWrappedKeyRing( KeyRings.buildUnifiedKeyRingUri(Long.toString(id)), true); } - public CachedSecretKeyRing getCachedSecretKeyRing(Uri queryUri) throws NotFoundException { - return (CachedSecretKeyRing) getCachedKeyRing(queryUri, true); + public WrappedSecretKeyRing getWrappedSecretKeyRing(Uri queryUri) throws NotFoundException { + return (WrappedSecretKeyRing) getWrappedKeyRing(queryUri, true); } - private CachedKeyRing getCachedKeyRing(Uri queryUri, boolean secret) throws NotFoundException { + private KeyRing getWrappedKeyRing(Uri queryUri, boolean secret) throws NotFoundException { Cursor cursor = mContentResolver.query(queryUri, new String[] { - // we pick from cache: - // basic data, primary uid in particular because it's expensive - KeyRings.MASTER_KEY_ID, KeyRings.USER_ID, KeyRings.HAS_ANY_SECRET, - // complex knowledge about subkeys - KeyRings.IS_REVOKED, KeyRings.CAN_CERTIFY, KeyRings.HAS_ENCRYPT, KeyRings.HAS_SIGN, - // stuff only the db knows and of course, ring data - KeyRings.VERIFIED, secret ? KeyRings.PRIVKEY_DATA : KeyRings.PUBKEY_DATA + // we pick from cache only information that is not easily available from keyrings + KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED, + // and of course, ring data + secret ? KeyRings.PRIVKEY_DATA : KeyRings.PUBKEY_DATA }, null, null, null); try { if (cursor != null && cursor.moveToFirst()) { - long masterKeyId = cursor.getLong(0); - String userId = cursor.getString(1); - boolean hasAnySecret = cursor.getInt(2) > 0; - boolean isRevoked = cursor.getInt(3) > 0; - boolean canCertify = cursor.getInt(4) > 0; - long hasEncryptId = cursor.getLong(5); - long hasSignId = cursor.getLong(6); - int verified = cursor.getInt(7); - byte[] blob = cursor.getBlob(8); + + boolean hasAnySecret = cursor.getInt(0) > 0; + int verified = cursor.getInt(1); + byte[] blob = cursor.getBlob(2); return secret - ? new CachedSecretKeyRing( - masterKeyId, userId, hasAnySecret, - isRevoked, canCertify, hasEncryptId, hasSignId, - verified, blob) - : new CachedPublicKeyRing( - masterKeyId, userId, hasAnySecret, - isRevoked, canCertify, hasEncryptId, hasSignId, - verified, blob); + ? new WrappedSecretKeyRing(blob, hasAnySecret, verified) + : new WrappedPublicKeyRing(blob, hasAnySecret, verified); } else { throw new NotFoundException("Key not found!"); } 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 58aa2ece8..d8a52ee83 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -419,7 +419,7 @@ public class OpenPgpService extends RemoteService { try { // try to find key, throws NotFoundException if not in db! - mProviderHelper.getCachedPublicKeyRing(masterKeyId); + mProviderHelper.getWrappedPublicKeyRing(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 ff599aaa1..f0d01e2ce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -27,14 +27,17 @@ import android.os.Messenger; import android.os.RemoteException; import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.openpgp.PGPKeyRing; +import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.CachedSecretKey; -import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedSecretKey; +import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; @@ -57,6 +60,7 @@ import org.sufficientlysecure.keychain.keyimport.KeybaseKeyServer; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -512,7 +516,7 @@ public class KeychainIntentService extends IntentService ProviderHelper providerHelper = new ProviderHelper(this); if (!canSign) { setProgress(R.string.progress_building_key, 0, 100); - CachedSecretKeyRing keyRing = providerHelper.getCachedSecretKeyRing(masterKeyId); + WrappedSecretKeyRing keyRing = providerHelper.getWrappedSecretKeyRing(masterKeyId); UncachedSecretKeyRing newKeyRing = keyRing.changeSecretKeyPassphrase(oldPassphrase, newPassphrase); setProgress(R.string.progress_saving_key_ring, 50, 100); @@ -522,8 +526,8 @@ public class KeychainIntentService extends IntentService PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100)); UncachedKeyRing pair; try { - CachedSecretKeyRing privkey = providerHelper.getCachedSecretKeyRing(masterKeyId); - CachedPublicKeyRing pubkey = providerHelper.getCachedPublicKeyRing(masterKeyId); + WrappedSecretKeyRing privkey = providerHelper.getWrappedSecretKeyRing(masterKeyId); + WrappedPublicKeyRing pubkey = providerHelper.getWrappedPublicKeyRing(masterKeyId); pair = keyOperations.buildSecretKey(privkey, pubkey, saveParcel); // edit existing } catch (ProviderHelper.NotFoundException e) { @@ -720,7 +724,7 @@ public class KeychainIntentService extends IntentService HkpKeyServer server = new HkpKeyServer(keyServer); ProviderHelper providerHelper = new ProviderHelper(this); - CachedPublicKeyRing keyring = providerHelper.getCachedPublicKeyRing(dataUri); + WrappedPublicKeyRing keyring = providerHelper.getWrappedPublicKeyRing(dataUri); PgpImportExport pgpImportExport = new PgpImportExport(this, null); boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, keyring); @@ -850,9 +854,9 @@ public class KeychainIntentService extends IntentService } ProviderHelper providerHelper = new ProviderHelper(this); - CachedPublicKeyRing publicRing = providerHelper.getCachedPublicKeyRing(pubKeyId); - CachedSecretKeyRing secretKeyRing = providerHelper.getCachedSecretKeyRing(masterKeyId); - CachedSecretKey certificationKey = secretKeyRing.getSubKey(); + WrappedPublicKeyRing publicRing = providerHelper.getWrappedPublicKeyRing(pubKeyId); + WrappedSecretKeyRing secretKeyRing = providerHelper.getWrappedSecretKeyRing(masterKeyId); + WrappedSecretKey certificationKey = secretKeyRing.getSubKey(); if(!certificationKey.unlock(signaturePassphrase)) { throw new PgpGeneralException("Error extracting key (bad passphrase?)"); } 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 2889b89c6..ef9adaf08 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -42,7 +42,7 @@ import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; @@ -178,7 +178,7 @@ public class PassphraseCacheService extends Service { // try to get master key id which is used as an identifier for cached passphrases try { Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + keyId); - CachedSecretKeyRing key = new ProviderHelper(this).getCachedSecretKeyRing( + WrappedSecretKeyRing key = new ProviderHelper(this).getWrappedSecretKeyRing( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId))); // no passphrase needed? just add empty string and return it, then if (!key.hasPassphrase()) { @@ -241,7 +241,7 @@ public class PassphraseCacheService extends Service { @Deprecated public static boolean hasPassphrase(Context context, long secretKeyId) throws ProviderHelper.NotFoundException { - return new ProviderHelper(context).getCachedSecretKeyRing(secretKeyId).hasPassphrase(); + return new ProviderHelper(context).getWrappedSecretKeyRing(secretKeyId).hasPassphrase(); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index fdcb98976..630b23645 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.app.Activity; -import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; @@ -48,8 +47,8 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.ExportHelper; -import org.sufficientlysecure.keychain.pgp.CachedSecretKey; -import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedSecretKey; +import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; @@ -287,10 +286,10 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener try { Uri secretUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - CachedSecretKeyRing keyRing = new ProviderHelper(this).getCachedSecretKeyRing(secretUri); + WrappedSecretKeyRing keyRing = new ProviderHelper(this).getWrappedSecretKeyRing(secretUri); mMasterCanSign = keyRing.getSubKey().canCertify(); - for (CachedSecretKey key : keyRing.iterator()) { + for (WrappedSecretKey key : keyRing.iterator()) { // Turn into uncached instance mKeys.add(key.getUncached()); mKeysUsages.add(key.getKeyUsage()); // get usage when view is created diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index 2b0c94f22..86067086c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -32,7 +32,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -147,8 +147,8 @@ public class EncryptAsymmetricFragment extends Fragment { // not sure if we need to distinguish between different subkeys here? if (preselectedSignatureKeyId != 0) { try { - CachedPublicKeyRing keyring = - providerHelper.getCachedPublicKeyRing(preselectedSignatureKeyId); + WrappedPublicKeyRing keyring = + providerHelper.getWrappedPublicKeyRing(preselectedSignatureKeyId); if(keyring.hasAnySecret()) { setSignatureKeyId(keyring.getMasterKeyId()); } 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 cf7fdcd89..48beb9cf5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -39,7 +39,7 @@ import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPSignature; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; @@ -147,8 +147,8 @@ public class ViewCertActivity extends ActionBarActivity try { ProviderHelper providerHelper = new ProviderHelper(this); - CachedPublicKeyRing signeeRing = providerHelper.getCachedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID)); - CachedPublicKeyRing signerRing = providerHelper.getCachedPublicKeyRing(sig.getKeyID()); + WrappedPublicKeyRing signeeRing = providerHelper.getWrappedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID)); + WrappedPublicKeyRing signerRing = providerHelper.getWrappedPublicKeyRing(sig.getKeyID()); try { signerRing.getSubkey().initSignature(sig); 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 cc653e58c..e7bcd2bc0 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 @@ -44,8 +44,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.CachedSecretKey; -import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedSecretKey; +import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.PassphraseCacheService; @@ -102,7 +102,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).getCachedSecretKeyRing(secretKeyId).hasPassphrase()) { + if (new ProviderHelper(context).getWrappedSecretKeyRing(secretKeyId).hasPassphrase()) { throw new PgpGeneralException("No passphrase! No passphrase dialog needed!"); } } catch(ProviderHelper.NotFoundException e) { @@ -138,17 +138,24 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor alert.setTitle(R.string.title_authentication); - final CachedSecretKeyRing secretRing; - final String userId; + final WrappedSecretKeyRing secretRing; + String userId; if (secretKeyId == Constants.key.symmetric || secretKeyId == Constants.key.none) { - secretRing = null; alert.setMessage(R.string.passphrase_for_symmetric_encryption); + secretRing = null; } else { try { ProviderHelper helper = new ProviderHelper(activity); - secretRing = helper.getCachedSecretKeyRing(secretKeyId); - userId = secretRing.getPrimaryUserId(); + secretRing = helper.getWrappedSecretKeyRing(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. + try { + userId = secretRing.getPrimaryUserId(); + } catch (PgpGeneralException e) { + userId = null; + } } catch (ProviderHelper.NotFoundException e) { alert.setTitle(R.string.title_key_not_found); alert.setMessage(getString(R.string.key_not_found, secretKeyId)); @@ -190,9 +197,9 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor return; } - CachedSecretKey unlockedSecretKey = null; + WrappedSecretKey unlockedSecretKey = null; - for(CachedSecretKey clickSecretKey : secretRing.iterator()) { + for(WrappedSecretKey clickSecretKey : secretRing.iterator()) { try { boolean unlocked = clickSecretKey.unlock(passphrase); if (unlocked) { -- cgit v1.2.3 From ab6c47a9b3642b9f7fe2e3bb45ebbd971517d7e1 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 21 May 2014 21:21:28 +0200 Subject: use long rather than String to build uris by key --- .../keychain/pgp/PgpDecryptVerify.java | 11 +++-------- .../sufficientlysecure/keychain/pgp/PgpSignEncrypt.java | 2 +- .../keychain/provider/KeychainContract.java | 16 ++++++++++------ .../keychain/provider/KeychainProvider.java | 2 +- .../keychain/provider/ProviderHelper.java | 8 +++----- .../keychain/remote/OpenPgpService.java | 2 +- .../keychain/service/PassphraseCacheService.java | 2 +- .../sufficientlysecure/keychain/ui/EditKeyActivity.java | 3 +-- .../keychain/ui/EncryptAsymmetricFragment.java | 12 +++++++----- .../sufficientlysecure/keychain/ui/KeyListFragment.java | 2 +- .../keychain/ui/SelectSecretKeyFragment.java | 2 +- .../keychain/ui/SelectSecretKeyLayoutFragment.java | 2 +- .../sufficientlysecure/keychain/ui/ViewCertActivity.java | 6 ++---- 13 files changed, 33 insertions(+), 37 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 21a7c20e3..abe7d0fb1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -249,8 +249,7 @@ public class PgpDecryptVerify { try { // get actual keyring object based on master key id secretKeyRing = mProviderHelper.getWrappedSecretKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( - Long.toString(encData.getKeyID())) + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(encData.getKeyID()) ); } catch (ProviderHelper.NotFoundException e) { // continue with the next packet in the while loop @@ -394,9 +393,7 @@ public class PgpDecryptVerify { try { long sigKeyId = sigList.get(i).getKeyID(); signingRing = mProviderHelper.getWrappedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( - Long.toString(sigKeyId) - ) + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) ); signingKey = signingRing.getSubkey(sigKeyId); signatureIndex = i; @@ -581,9 +578,7 @@ public class PgpDecryptVerify { try { long sigKeyId = sigList.get(i).getKeyID(); signingRing = mProviderHelper.getWrappedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( - Long.toString(sigKeyId) - ) + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) ); signingKey = signingRing.getSubkey(sigKeyId); signatureIndex = i; 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 24d090d04..4cb92c368 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -317,7 +317,7 @@ public class PgpSignEncrypt { for (long id : mEncryptionMasterKeyIds) { try { WrappedPublicKeyRing keyRing = mProviderHelper.getWrappedPublicKeyRing( - KeyRings.buildUnifiedKeyRingUri(Long.toString(id))); + KeyRings.buildUnifiedKeyRingUri(id)); WrappedPublicKey key = keyRing.getEncryptionSubKey(); cPk.addMethod(key.getPubKeyEncryptionGenerator()); } catch (PgpGeneralException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index a3c9fab1b..483f762f7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -137,20 +137,24 @@ public class KeychainContract { return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).build(); } - public static Uri buildUnifiedKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build(); + public static Uri buildUnifiedKeyRingUri(long masterKeyId) { + return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)) + .appendPath(PATH_UNIFIED).build(); } public static Uri buildUnifiedKeyRingUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build(); + return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)) + .appendPath(PATH_UNIFIED).build(); } public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) { - return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_EMAIL).appendPath(email).build(); + return CONTENT_URI.buildUpon().appendPath(PATH_FIND) + .appendPath(PATH_BY_EMAIL).appendPath(email).build(); } - public static Uri buildUnifiedKeyRingsFindBySubkeyUri(String subkey) { - return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_SUBKEY).appendPath(subkey).build(); + public static Uri buildUnifiedKeyRingsFindBySubkeyUri(long subkey) { + return CONTENT_URI.buildUpon().appendPath(PATH_FIND) + .appendPath(PATH_BY_SUBKEY).appendPath(Long.toString(subkey)).build(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index be7bd1556..2f6cded91 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -644,7 +644,7 @@ public class KeychainProvider extends ContentProvider { } if(keyId != null) { - uri = KeyRings.buildGenericKeyRingUri(keyId.toString()); + uri = KeyRings.buildGenericKeyRingUri(keyId); rowUri = uri; } 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 be769dfbe..d97260298 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -144,7 +144,7 @@ public class ProviderHelper { public HashMap getUnifiedData(long masterKeyId, String[] proj, int[] types) throws NotFoundException { - return getGenericData(KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj, types); + return getGenericData(KeyRings.buildUnifiedKeyRingUri(masterKeyId), proj, types); } /** @@ -202,8 +202,7 @@ public class ProviderHelper { } public WrappedPublicKeyRing getWrappedPublicKeyRing(long id) throws NotFoundException { - return (WrappedPublicKeyRing) getWrappedKeyRing( - KeyRings.buildUnifiedKeyRingUri(Long.toString(id)), false); + return (WrappedPublicKeyRing) getWrappedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), false); } public WrappedPublicKeyRing getWrappedPublicKeyRing(Uri queryUri) throws NotFoundException { @@ -211,8 +210,7 @@ public class ProviderHelper { } public WrappedSecretKeyRing getWrappedSecretKeyRing(long id) throws NotFoundException { - return (WrappedSecretKeyRing) getWrappedKeyRing( - KeyRings.buildUnifiedKeyRingUri(Long.toString(id)), true); + return (WrappedSecretKeyRing) getWrappedKeyRing(KeyRings.buildUnifiedKeyRingUri(id), true); } public WrappedSecretKeyRing getWrappedSecretKeyRing(Uri queryUri) throws NotFoundException { 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 d8a52ee83..17c277026 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -426,7 +426,7 @@ public class OpenPgpService extends RemoteService { // also return PendingIntent that opens the key view activity Intent intent = new Intent(getBaseContext(), ViewKeyActivity.class); - intent.setData(KeyRings.buildGenericKeyRingUri(Long.toString(masterKeyId))); + intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, intent, 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 ef9adaf08..17ba9df5c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -179,7 +179,7 @@ public class PassphraseCacheService extends Service { try { Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + keyId); WrappedSecretKeyRing key = new ProviderHelper(this).getWrappedSecretKeyRing( - KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId))); + KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId)); // no passphrase needed? just add empty string and return it, then if (!key.hasPassphrase()) { Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 630b23645..ae380552a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -587,8 +587,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener Intent data = new Intent(); // return uri pointing to new created key - Uri uri = KeyRings.buildGenericKeyRingUri( - String.valueOf(getMasterKeyId())); + Uri uri = KeyRings.buildGenericKeyRingUri(getMasterKeyId()); data.setData(uri); setResult(RESULT_OK, data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index 86067086c..c0ed87a95 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -32,8 +32,9 @@ import com.beardedhen.androidbootstrap.BootstrapButton; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; @@ -147,12 +148,13 @@ public class EncryptAsymmetricFragment extends Fragment { // not sure if we need to distinguish between different subkeys here? if (preselectedSignatureKeyId != 0) { try { - WrappedPublicKeyRing keyring = - providerHelper.getWrappedPublicKeyRing(preselectedSignatureKeyId); + CachedPublicKeyRing keyring = + providerHelper.getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingUri(preselectedSignatureKeyId)); if(keyring.hasAnySecret()) { setSignatureKeyId(keyring.getMasterKeyId()); } - } catch (ProviderHelper.NotFoundException e) { + } catch (PgpGeneralException e) { Log.e(Constants.TAG, "key not found!", e); } } @@ -163,7 +165,7 @@ public class EncryptAsymmetricFragment extends Fragment { try { long id = providerHelper.getMasterKeyId( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( - Long.toString(preselectedEncryptionKeyIds[i])) + preselectedEncryptionKeyIds[i]) ); goodIds.add(id); } catch (ProviderHelper.NotFoundException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 3fd958bcc..a3f4b0753 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -308,7 +308,7 @@ public class KeyListFragment extends LoaderFragment public void onItemClick(AdapterView adapterView, View view, int position, long id) { Intent viewIntent = new Intent(getActivity(), ViewKeyActivity.class); viewIntent.setData( - KeyRings.buildGenericKeyRingUri(Long.toString(mAdapter.getMasterKeyId(position)))); + KeyRings.buildGenericKeyRingUri(mAdapter.getMasterKeyId(position))); startActivity(viewIntent); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java index 38a0c8478..9ddc8e3e1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java @@ -84,7 +84,7 @@ public class SelectSecretKeyFragment extends ListFragment implements @Override public void onItemClick(AdapterView adapterView, View view, int position, long id) { long masterKeyId = mAdapter.getMasterKeyId(position); - Uri result = KeyRings.buildGenericKeyRingUri(String.valueOf(masterKeyId)); + Uri result = KeyRings.buildGenericKeyRingUri(masterKeyId); // return data to activity, which results in finishing it mActivity.afterListSelection(result); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java index 8db750917..fe2ecf3a3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java @@ -132,7 +132,7 @@ public class SelectSecretKeyLayoutFragment extends Fragment implements LoaderMan //For AppSettingsFragment public void selectKey(long masterKeyId) { - Uri buildUri = KeychainContract.KeyRings.buildGenericKeyRingUri(String.valueOf(masterKeyId)); + Uri buildUri = KeychainContract.KeyRings.buildGenericKeyRingUri(masterKeyId); mReceivedUri = buildUri; getActivity().getSupportLoaderManager().restartLoader(LOADER_ID, null, this); } 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 48beb9cf5..e6d090062 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -212,11 +212,9 @@ public class ViewCertActivity extends ActionBarActivity try { ProviderHelper providerHelper = new ProviderHelper(ViewCertActivity.this); long signerMasterKeyId = providerHelper.getMasterKeyId( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(mCertifierKeyId)) - ); - viewIntent.setData(KeyRings.buildGenericKeyRingUri( - Long.toString(signerMasterKeyId)) + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(mCertifierKeyId) ); + viewIntent.setData(KeyRings.buildGenericKeyRingUri(signerMasterKeyId)); startActivity(viewIntent); } catch (ProviderHelper.NotFoundException e) { // TODO notify user of this, maybe offer download? -- cgit v1.2.3 From 6d7daec37f9ac7efbdd687c97ca45f9c9ddc5602 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 21 May 2014 21:41:51 +0200 Subject: wrapped-key-ring: use CachedKeyRing where possible --- .../keychain/helper/ExportHelper.java | 6 +++-- .../keychain/provider/CachedPublicKeyRing.java | 24 ++++++++++++++++++-- .../keychain/provider/ProviderHelper.java | 26 ---------------------- .../remote/ui/AccountSettingsFragment.java | 6 +++-- .../keychain/ui/EncryptAsymmetricFragment.java | 6 ++--- .../keychain/ui/ViewCertActivity.java | 8 +++---- .../keychain/ui/ViewKeyMainFragment.java | 10 ++++++--- 7 files changed, 44 insertions(+), 42 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java index 31b88856f..16ef28311 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java @@ -31,6 +31,7 @@ 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.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; @@ -51,14 +52,15 @@ public class ExportHelper { public void deleteKey(Uri dataUri, Handler deleteHandler) { try { - long masterKeyId = new ProviderHelper(mActivity).extractOrGetMasterKeyId(dataUri); + long masterKeyId = new ProviderHelper(mActivity).getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); // Create a new Messenger for the communication back Messenger messenger = new Messenger(deleteHandler); DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, new long[]{ masterKeyId }); deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog"); - } catch (ProviderHelper.NotFoundException e) { + } catch (PgpGeneralException e) { Log.e(Constants.TAG, "key not found!", e); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java index 6f7623d65..ed1988336 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java @@ -2,8 +2,10 @@ package org.sufficientlysecure.keychain.provider; import android.net.Uri; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.Log; public class CachedPublicKeyRing extends KeyRing { @@ -17,12 +19,30 @@ public class CachedPublicKeyRing extends KeyRing { public long getMasterKeyId() throws PgpGeneralException { try { - return mProviderHelper.getMasterKeyId(mUri); - } catch(ProviderHelper.NotFoundException e) { + Object data = mProviderHelper.getGenericData(mUri, + KeychainContract.KeyRings.MASTER_KEY_ID, ProviderHelper.FIELD_TYPE_INTEGER); + return (Long) data; + } catch (ProviderHelper.NotFoundException e) { throw new PgpGeneralException(e); } } + /** + * Find the master key id related to a given query. The id will either be extracted from the + * query, which should work for all specific /key_rings/ queries, or will be queried if it can't. + */ + public long extractOrGetMasterKeyId() throws PgpGeneralException { + // try extracting from the uri first + String firstSegment = mUri.getPathSegments().get(1); + if (!firstSegment.equals("find")) try { + return Long.parseLong(firstSegment); + } catch (NumberFormatException e) { + // didn't work? oh well. + Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying..."); + } + return getMasterKeyId(); + } + public String getPrimaryUserId() throws PgpGeneralException { try { Object data = mProviderHelper.getGenericData(mUri, 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 d97260298..4df86ee9b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -147,32 +147,6 @@ public class ProviderHelper { return getGenericData(KeyRings.buildUnifiedKeyRingUri(masterKeyId), proj, types); } - /** - * Find the master key id related to a given query. The id will either be extracted from the - * query, which should work for all specific /key_rings/ queries, or will be queried if it can't. - */ - public long extractOrGetMasterKeyId(Uri queryUri) - throws NotFoundException { - // try extracting from the uri first - String firstSegment = queryUri.getPathSegments().get(1); - if (!firstSegment.equals("find")) try { - return Long.parseLong(firstSegment); - } catch (NumberFormatException e) { - // didn't work? oh well. - Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying..."); - } - return getMasterKeyId(queryUri); - } - - public long getMasterKeyId(Uri queryUri) throws NotFoundException { - Object data = getGenericData(queryUri, KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER); - if (data != null) { - return (Long) data; - } else { - throw new NotFoundException(); - } - } - @Deprecated public LongSparseArray getPGPKeyRings(Uri queryUri) { Cursor cursor = mContentResolver.query(queryUri, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java index 20223e319..cb58f8734 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java @@ -33,6 +33,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.ui.EditKeyActivity; @@ -179,9 +180,10 @@ public class AccountSettingsFragment extends Fragment implements // select newly created key try { long masterKeyId = new ProviderHelper(getActivity()) - .extractOrGetMasterKeyId(data.getData()); + .getCachedPublicKeyRing(data.getData()) + .extractOrGetMasterKeyId(); mSelectKeyFragment.selectKey(masterKeyId); - } catch (ProviderHelper.NotFoundException e) { + } catch (PgpGeneralException e) { Log.e(Constants.TAG, "key not found!", e); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index c0ed87a95..03483575c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -163,12 +163,12 @@ public class EncryptAsymmetricFragment extends Fragment { Vector goodIds = new Vector(); for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) { try { - long id = providerHelper.getMasterKeyId( + long id = providerHelper.getCachedPublicKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( preselectedEncryptionKeyIds[i]) - ); + ).getMasterKeyId(); goodIds.add(id); - } catch (ProviderHelper.NotFoundException e) { + } catch (PgpGeneralException e) { Log.e(Constants.TAG, "key not found!", e); } } 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 e6d090062..465815f14 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -42,6 +42,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -211,12 +212,11 @@ public class ViewCertActivity extends ActionBarActivity try { ProviderHelper providerHelper = new ProviderHelper(ViewCertActivity.this); - long signerMasterKeyId = providerHelper.getMasterKeyId( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(mCertifierKeyId) - ); + long signerMasterKeyId = providerHelper.getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(mCertifierKeyId)).getMasterKeyId(); viewIntent.setData(KeyRings.buildGenericKeyRingUri(signerMasterKeyId)); startActivity(viewIntent); - } catch (ProviderHelper.NotFoundException e) { + } catch (PgpGeneralException e) { // TODO notify user of this, maybe offer download? Log.e(Constants.TAG, "key not found!", e); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 026417776..c16bb82af 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -32,7 +32,9 @@ import android.widget.ListView; import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R;import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -235,14 +237,16 @@ public class ViewKeyMainFragment extends LoaderFragment implements return; } try { - long keyId = new ProviderHelper(getActivity()).extractOrGetMasterKeyId(dataUri); + long keyId = new ProviderHelper(getActivity()) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); long[] encryptionKeyIds = new long[]{keyId}; Intent intent = new Intent(getActivity(), EncryptActivity.class); intent.setAction(EncryptActivity.ACTION_ENCRYPT); intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); // used instead of startActivity set actionbar based on callingPackage startActivityForResult(intent, 0); - } catch (ProviderHelper.NotFoundException e) { + } catch (PgpGeneralException e) { Log.e(Constants.TAG, "key not found!", e); } } -- cgit v1.2.3 From cd0aba9d43403877df2130a54bde8ab51c8030d7 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 22 May 2014 13:05:02 +0200 Subject: wrapped-key-ring: encapsulate key flags --- .../keychain/pgp/UncachedSecretKey.java | 7 +++++ .../keychain/ui/widget/KeyEditor.java | 35 ++++++++++++---------- .../keychain/ui/widget/SectionView.java | 3 +- 3 files changed, 27 insertions(+), 18 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java index 82224c6cf..0e14a7fd3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKey.java @@ -1,5 +1,6 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPSecretKey; import java.io.IOException; @@ -7,6 +8,12 @@ import java.io.OutputStream; public class UncachedSecretKey extends UncachedPublicKey { + public static final int CERTIFY_OTHER = KeyFlags.CERTIFY_OTHER; + public static final int SIGN_DATA = KeyFlags.SIGN_DATA; + public static final int ENCRYPT_COMMS = KeyFlags.ENCRYPT_COMMS; + public static final int ENCRYPT_STORAGE = KeyFlags.ENCRYPT_STORAGE; + public static final int AUTHENTICATION = KeyFlags.AUTHENTICATION; + final PGPSecretKey mSecretKey; public UncachedSecretKey(PGPSecretKey secretKey) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index e1a603787..40fe7665c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -38,7 +38,6 @@ import android.widget.TextView; import com.beardedhen.androidbootstrap.BootstrapButton; -import org.spongycastle.bcpg.sig.KeyFlags; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; @@ -244,11 +243,15 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { mIsNewKey = isNewKey; if (isNewKey) { mUsage = usage; - mChkCertify.setChecked((usage & KeyFlags.CERTIFY_OTHER) == KeyFlags.CERTIFY_OTHER); - mChkSign.setChecked((usage & KeyFlags.SIGN_DATA) == KeyFlags.SIGN_DATA); - mChkEncrypt.setChecked(((usage & KeyFlags.ENCRYPT_COMMS) == KeyFlags.ENCRYPT_COMMS) || - ((usage & KeyFlags.ENCRYPT_STORAGE) == KeyFlags.ENCRYPT_STORAGE)); - mChkAuthenticate.setChecked((usage & KeyFlags.AUTHENTICATION) == KeyFlags.AUTHENTICATION); + mChkCertify.setChecked( + (usage & UncachedSecretKey.CERTIFY_OTHER) == UncachedSecretKey.CERTIFY_OTHER); + mChkSign.setChecked( + (usage & UncachedSecretKey.SIGN_DATA) == UncachedSecretKey.SIGN_DATA); + mChkEncrypt.setChecked( + ((usage & UncachedSecretKey.ENCRYPT_COMMS) == UncachedSecretKey.ENCRYPT_COMMS) || + ((usage & UncachedSecretKey.ENCRYPT_STORAGE) == UncachedSecretKey.ENCRYPT_STORAGE)); + mChkAuthenticate.setChecked( + (usage & UncachedSecretKey.AUTHENTICATION) == UncachedSecretKey.AUTHENTICATION); } else { mUsage = key.getKeyUsage(); mOriginalUsage = mUsage; @@ -319,16 +322,16 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } public int getUsage() { - mUsage = (mUsage & ~KeyFlags.CERTIFY_OTHER) | - (mChkCertify.isChecked() ? KeyFlags.CERTIFY_OTHER : 0); - mUsage = (mUsage & ~KeyFlags.SIGN_DATA) | - (mChkSign.isChecked() ? KeyFlags.SIGN_DATA : 0); - mUsage = (mUsage & ~KeyFlags.ENCRYPT_COMMS) | - (mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_COMMS : 0); - mUsage = (mUsage & ~KeyFlags.ENCRYPT_STORAGE) | - (mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_STORAGE : 0); - mUsage = (mUsage & ~KeyFlags.AUTHENTICATION) | - (mChkAuthenticate.isChecked() ? KeyFlags.AUTHENTICATION : 0); + mUsage = (mUsage & ~UncachedSecretKey.CERTIFY_OTHER) | + (mChkCertify.isChecked() ? UncachedSecretKey.CERTIFY_OTHER : 0); + mUsage = (mUsage & ~UncachedSecretKey.SIGN_DATA) | + (mChkSign.isChecked() ? UncachedSecretKey.SIGN_DATA : 0); + mUsage = (mUsage & ~UncachedSecretKey.ENCRYPT_COMMS) | + (mChkEncrypt.isChecked() ? UncachedSecretKey.ENCRYPT_COMMS : 0); + mUsage = (mUsage & ~UncachedSecretKey.ENCRYPT_STORAGE) | + (mChkEncrypt.isChecked() ? UncachedSecretKey.ENCRYPT_STORAGE : 0); + mUsage = (mUsage & ~UncachedSecretKey.AUTHENTICATION) | + (mChkAuthenticate.isChecked() ? UncachedSecretKey.AUTHENTICATION : 0); return mUsage; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 35ebfcd58..3e8e18ce5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -35,7 +35,6 @@ import android.widget.TextView; import com.beardedhen.androidbootstrap.BootstrapButton; -import org.spongycastle.openpgp.PGPKeyFlags; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; @@ -420,7 +419,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor view.setEditorListener(SectionView.this); int usage = 0; if (mEditors.getChildCount() == 0) { - usage = PGPKeyFlags.CAN_CERTIFY; + usage = UncachedSecretKey.CERTIFY_OTHER; } view.setValue(newKey, newKey.isMasterKey(), usage, true); mEditors.addView(view); -- cgit v1.2.3 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') 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 From 91a8a6c2d1f243f0a3f13b11fd1f920b34717116 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 23 May 2014 16:48:03 +0200 Subject: wrapped-key-ring: use UncachedKeyRing in ImportKeysListLoader --- .../keychain/ui/adapter/ImportKeysListLoader.java | 36 +++++----------------- 1 file changed, 8 insertions(+), 28 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index b6c829677..46b50ac98 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -20,18 +20,16 @@ package org.sufficientlysecure.keychain.ui.adapter; import android.content.Context; import android.support.v4.content.AsyncTaskLoader; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.PositionAwareInputStream; import java.io.BufferedInputStream; -import java.io.InputStream; import java.util.ArrayList; +import java.util.List; public class ImportKeysListLoader extends AsyncTaskLoader>> { @@ -116,7 +114,6 @@ public class ImportKeysListLoader private void generateListOfKeyrings(InputData inputData) { boolean isEmpty = true; - int nonPgpCounter = 0; PositionAwareInputStream progressIn = new PositionAwareInputStream( inputData.getInputStream()); @@ -129,28 +126,16 @@ public class ImportKeysListLoader // read all available blocks... (asc files can contain many blocks with BEGIN END) while (bufferedInput.available() > 0) { - isEmpty = false; - InputStream in = PGPUtil.getDecoderStream(bufferedInput); - PGPObjectFactory objectFactory = new PGPObjectFactory(in); - - // 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) { - PGPKeyRing newKeyring = (PGPKeyRing) obj; - addToData(newKeyring); - } else { - Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); - nonPgpCounter++; - } + // todo deal with non-keyring objects? + List rings = UncachedKeyRing.fromStream(bufferedInput); + for(UncachedKeyRing key : rings) { + addToData(key); + isEmpty = false; } } } catch (Exception e) { Log.e(Constants.TAG, "Exception on parsing key file!", e); mEntryListWrapper = new AsyncTaskResultWrapper>(mData, e); - nonPgpCounter = 0; } if (isEmpty) { @@ -158,14 +143,9 @@ public class ImportKeysListLoader mEntryListWrapper = new AsyncTaskResultWrapper> (mData, new FileHasNoContent()); } - - if (nonPgpCounter > 0) { - mEntryListWrapper = new AsyncTaskResultWrapper> - (mData, new NonPgpPart(nonPgpCounter)); - } } - private void addToData(PGPKeyRing keyring) { + private void addToData(UncachedKeyRing keyring) { ImportKeysListEntry item = new ImportKeysListEntry(getContext(), keyring); mData.add(item); } -- cgit v1.2.3 From c107fc668fb6ef1be2e2775fd2143fb2235942b2 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 23 May 2014 16:48:41 +0200 Subject: introduce WrappedSignature for the ViewCert* ui code --- .../keychain/pgp/WrappedSignature.java | 124 +++++++++++++++++++++ .../keychain/ui/ViewCertActivity.java | 44 ++++---- .../keychain/ui/ViewKeyCertsFragment.java | 12 +- 3 files changed, 149 insertions(+), 31 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java new file mode 100644 index 000000000..cdadbca7f --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -0,0 +1,124 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.bcpg.SignatureSubpacket; +import org.spongycastle.bcpg.SignatureSubpacketTags; +import org.spongycastle.bcpg.sig.RevocationReason; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.security.SignatureException; + +public class WrappedSignature { + + public static final int DEFAULT_CERTIFICATION = PGPSignature.DEFAULT_CERTIFICATION; + public static final int NO_CERTIFICATION = PGPSignature.NO_CERTIFICATION; + public static final int CASUAL_CERTIFICATION = PGPSignature.CASUAL_CERTIFICATION; + public static final int POSITIVE_CERTIFICATION = PGPSignature.POSITIVE_CERTIFICATION; + public static final int CERTIFICATION_REVOCATION = PGPSignature.CERTIFICATION_REVOCATION; + + final PGPSignature mSig; + + protected WrappedSignature(PGPSignature sig) { + mSig = sig; + } + + public long getKeyId() { + return mSig.getKeyID(); + } + + public int getKeyAlgorithm() { + return mSig.getKeyAlgorithm(); + } + + public void init(WrappedPublicKey key) throws PgpGeneralException { + try { + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + mSig.init(contentVerifierBuilderProvider, key.getPublicKey()); + } catch(PGPException e) { + throw new PgpGeneralException(e); + } + } + + public void update(byte[] data, int offset, int length) throws PgpGeneralException { + try { + mSig.update(data, offset, length); + } catch(SignatureException e) { + throw new PgpGeneralException(e); + } + } + + public void update(byte data) throws PgpGeneralException { + try { + mSig.update(data); + } catch(SignatureException e) { + throw new PgpGeneralException(e); + } + } + + public boolean verify() throws PgpGeneralException { + try { + return mSig.verify(); + } catch(SignatureException e) { + throw new PgpGeneralException(e); + } catch(PGPException e) { + throw new PgpGeneralException(e); + } + } + + public boolean isRevocation() { + return mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.REVOCATION_REASON); + } + + public String getRevocationReason() throws PgpGeneralException { + if(!isRevocation()) { + throw new PgpGeneralException("Not a revocation signature."); + } + SignatureSubpacket p = mSig.getHashedSubPackets().getSubpacket( + SignatureSubpacketTags.REVOCATION_REASON); + // For some reason, this is missing in SignatureSubpacketInputStream:146 + if (!(p instanceof RevocationReason)) { + p = new RevocationReason(false, p.getData()); + } + return ((RevocationReason) p).getRevocationDescription(); + } + + /** 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(WrappedPublicKey key, String uid) throws PgpGeneralException { + try { + return mSig.verifyCertification(uid, key.getPublicKey()); + } catch (SignatureException e) { + throw new PgpGeneralException("Error!", e); + } catch (PGPException e) { + throw new PgpGeneralException("Error!", e); + } + } + + public static WrappedSignature fromBytes(byte[] data) { + PGPObjectFactory factory = new PGPObjectFactory(data); + PGPSignatureList signatures = null; + try { + if ((signatures = (PGPSignatureList) factory.nextObject()) == null || signatures.isEmpty()) { + Log.e(Constants.TAG, "No signatures given!"); + return null; + } + } catch (IOException e) { + Log.e(Constants.TAG, "Error while converting to PGPSignature!", e); + return null; + } + + return new WrappedSignature(signatures.get(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 465815f14..ae0206ab1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -32,16 +32,11 @@ import android.view.MenuItem; import android.view.View; import android.widget.TextView; -import org.spongycastle.bcpg.SignatureSubpacket; -import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.bcpg.sig.RevocationReason; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPSignature; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -144,23 +139,25 @@ public class ViewCertActivity extends ActionBarActivity mCertifierUid.setText(R.string.unknown_uid); } - PGPSignature sig = PgpConversionHelper.BytesToPGPSignature(data.getBlob(INDEX_DATA)); + WrappedSignature sig = WrappedSignature.fromBytes(data.getBlob(INDEX_DATA)); try { ProviderHelper providerHelper = new ProviderHelper(this); - WrappedPublicKeyRing signeeRing = providerHelper.getWrappedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID)); - WrappedPublicKeyRing signerRing = providerHelper.getWrappedPublicKeyRing(sig.getKeyID()); + WrappedPublicKeyRing signeeRing = + providerHelper.getWrappedPublicKeyRing(data.getLong(INDEX_MASTER_KEY_ID)); + WrappedPublicKeyRing signerRing = + providerHelper.getWrappedPublicKeyRing(sig.getKeyId()); try { - signerRing.getSubkey().initSignature(sig); - if (signeeRing.getSubkey().verifySignature(sig, signeeUid)) { + sig.init(signerRing.getSubkey()); + if (sig.verifySignature(signeeRing.getSubkey(), signeeUid)) { mStatus.setText(R.string.cert_verify_ok); mStatus.setTextColor(getResources().getColor(R.color.bbutton_success)); } else { mStatus.setText(R.string.cert_verify_failed); mStatus.setTextColor(getResources().getColor(R.color.alert)); } - } catch (PGPException e) { + } catch (PgpGeneralException e) { mStatus.setText(R.string.cert_verify_error); mStatus.setTextColor(getResources().getColor(R.color.alert)); } @@ -174,29 +171,26 @@ public class ViewCertActivity extends ActionBarActivity mRowReason.setVisibility(View.GONE); switch (data.getInt(INDEX_TYPE)) { - case PGPSignature.DEFAULT_CERTIFICATION: + case WrappedSignature.DEFAULT_CERTIFICATION: mType.setText(R.string.cert_default); break; - case PGPSignature.NO_CERTIFICATION: + case WrappedSignature.NO_CERTIFICATION: mType.setText(R.string.cert_none); break; - case PGPSignature.CASUAL_CERTIFICATION: + case WrappedSignature.CASUAL_CERTIFICATION: mType.setText(R.string.cert_casual); break; - case PGPSignature.POSITIVE_CERTIFICATION: + case WrappedSignature.POSITIVE_CERTIFICATION: mType.setText(R.string.cert_positive); break; - case PGPSignature.CERTIFICATION_REVOCATION: { + case WrappedSignature.CERTIFICATION_REVOCATION: { mType.setText(R.string.cert_revoke); - if (sig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.REVOCATION_REASON)) { - SignatureSubpacket p = sig.getHashedSubPackets().getSubpacket( - SignatureSubpacketTags.REVOCATION_REASON); - // For some reason, this is missing in SignatureSubpacketInputStream:146 - if (!(p instanceof RevocationReason)) { - p = new RevocationReason(false, p.getData()); + if (sig.isRevocation()) { + try { + mReason.setText(sig.getRevocationReason()); + } catch(PgpGeneralException e) { + mReason.setText(R.string.none); } - String reason = ((RevocationReason) p).getRevocationDescription(); - mReason.setText(reason); mRowReason.setVisibility(View.VISIBLE); } break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java index d5658586d..3cd43638a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java @@ -33,10 +33,10 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.TextView; -import org.spongycastle.openpgp.PGPSignature; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.util.Log; @@ -227,19 +227,19 @@ public class ViewKeyCertsFragment extends LoaderFragment wSignerKeyId.setText(signerKeyId); switch (cursor.getInt(mIndexType)) { - case PGPSignature.DEFAULT_CERTIFICATION: // 0x10 + case WrappedSignature.DEFAULT_CERTIFICATION: // 0x10 wSignStatus.setText(R.string.cert_default); break; - case PGPSignature.NO_CERTIFICATION: // 0x11 + case WrappedSignature.NO_CERTIFICATION: // 0x11 wSignStatus.setText(R.string.cert_none); break; - case PGPSignature.CASUAL_CERTIFICATION: // 0x12 + case WrappedSignature.CASUAL_CERTIFICATION: // 0x12 wSignStatus.setText(R.string.cert_casual); break; - case PGPSignature.POSITIVE_CERTIFICATION: // 0x13 + case WrappedSignature.POSITIVE_CERTIFICATION: // 0x13 wSignStatus.setText(R.string.cert_positive); break; - case PGPSignature.CERTIFICATION_REVOCATION: // 0x30 + case WrappedSignature.CERTIFICATION_REVOCATION: // 0x30 wSignStatus.setText(R.string.cert_revoke); break; } -- cgit v1.2.3 From 97af8b2a01af74069d72ca25539cb7465a6440f0 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 23 May 2014 17:04:15 +0200 Subject: wrapped-key-ring: forgot a part in PgpDecryptVerify --- .../org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 abe7d0fb1..c009d1b5c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -35,6 +35,7 @@ import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; import org.sufficientlysecure.keychain.Constants; @@ -417,7 +418,10 @@ public class PgpDecryptVerify { } signatureResultBuilder.signatureKeyCertified(signingRing.getVerified() > 0); - signingKey.initSignature(signature); + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); } else { // no key in our database -> return "unknown pub key" status including the first key id if (!sigList.isEmpty()) { @@ -604,7 +608,10 @@ public class PgpDecryptVerify { } signatureResultBuilder.signatureKeyCertified(signingRing.getVerified() > 0); - signingKey.initSignature(signature); + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); } else { // no key in our database -> return "unknown pub key" status including the first key id if (!sigList.isEmpty()) { -- cgit v1.2.3 From 4a6aaf1e836bd3833c67418a3b77f647b2d8b782 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 27 May 2014 13:49:39 +0200 Subject: fix missing userIds in ImportKeysListEntry --- .../keychain/keyimport/ImportKeysListEntry.java | 3 +-- .../org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 2d8a97809..0187fe52a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -229,8 +229,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable { */ @SuppressWarnings("unchecked") 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 = ring.getEncoded(); @@ -245,6 +243,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { UncachedPublicKey key = ring.getPublicKey(); mPrimaryUserId = key.getPrimaryUserId(); + userIds = key.getUnorderedUserIds(); // if there was no user id flagged as primary, use the first one if (mPrimaryUserId == null) { 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 7f6fae4a6..5dbe4b316 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -71,9 +71,7 @@ public class UncachedPublicKey { } 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)) { @@ -94,6 +92,14 @@ public class UncachedPublicKey { return null; } + public ArrayList getUnorderedUserIds() { + ArrayList userIds = new ArrayList(); + for (String userId : new IterableIterator(mPublicKey.getUserIDs())) { + userIds.add(userId); + } + return userIds; + } + public boolean isElGamalEncrypt() { return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT; } -- cgit v1.2.3 From ce1c3d1a1ee7f8d9b482419801aee494928741d2 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 9 May 2014 14:06:23 +0200 Subject: rename SaveKeyringParcel to OldSaveKeyringParcel --- .../keychain/pgp/PgpKeyOperation.java | 6 +- .../keychain/service/KeychainIntentService.java | 2 +- .../keychain/service/OldSaveKeyringParcel.java | 128 +++++++++++++++++++++ .../keychain/service/SaveKeyringParcel.java | 123 -------------------- .../keychain/ui/EditKeyActivity.java | 4 +- 5 files changed, 134 insertions(+), 129 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OldSaveKeyringParcel.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java (limited to 'OpenKeychain/src/main/java') 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 5e7134dc6..f49e0af4b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -48,7 +48,7 @@ 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.SaveKeyringParcel; +import org.sufficientlysecure.keychain.service.OldSaveKeyringParcel; import org.sufficientlysecure.keychain.util.Primes; import java.io.IOException; @@ -193,7 +193,7 @@ public class PgpKeyOperation { } public UncachedKeyRing buildNewSecretKey( - SaveKeyringParcel saveParcel) + OldSaveKeyringParcel saveParcel) throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { int usageId = saveParcel.keysUsages.get(0); @@ -338,7 +338,7 @@ public class PgpKeyOperation { public Pair buildSecretKey(WrappedSecretKeyRing wmKR, WrappedPublicKeyRing wpKR, - SaveKeyringParcel saveParcel) + OldSaveKeyringParcel saveParcel) throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { PGPSecretKeyRing mKR = wmKR.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 250e1cdda..c2fc4334a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -497,7 +497,7 @@ public class KeychainIntentService extends IntentService } else if (ACTION_SAVE_KEYRING.equals(action)) { try { /* Input */ - SaveKeyringParcel saveParcel = data.getParcelable(SAVE_KEYRING_PARCEL); + OldSaveKeyringParcel saveParcel = data.getParcelable(SAVE_KEYRING_PARCEL); String oldPassphrase = saveParcel.oldPassphrase; String newPassphrase = saveParcel.newPassphrase; boolean canSign = true; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OldSaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OldSaveKeyringParcel.java new file mode 100644 index 000000000..b722393ad --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OldSaveKeyringParcel.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2014 Ash Hughes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.service; + +import android.os.Parcel; +import android.os.Parcelable; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; +import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; +import org.sufficientlysecure.keychain.util.IterableIterator; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Calendar; + +/** Class for parcelling data between ui and services. + * This class is outdated and scheduled for removal, pending a rewrite of the + * EditKeyActivity and save keyring routines. + */ +@Deprecated +public class OldSaveKeyringParcel implements Parcelable { + + public ArrayList userIds; + public ArrayList originalIDs; + public ArrayList deletedIDs; + public boolean[] newIDs; + public boolean primaryIDChanged; + public boolean[] moddedKeys; + public ArrayList deletedKeys; + public ArrayList keysExpiryDates; + public ArrayList keysUsages; + public String newPassphrase; + public String oldPassphrase; + public boolean[] newKeys; + public ArrayList keys; + public String originalPrimaryID; + + public OldSaveKeyringParcel() {} + + private OldSaveKeyringParcel(Parcel source) { + userIds = (ArrayList) source.readSerializable(); + originalIDs = (ArrayList) source.readSerializable(); + deletedIDs = (ArrayList) source.readSerializable(); + newIDs = source.createBooleanArray(); + primaryIDChanged = source.readByte() != 0; + moddedKeys = source.createBooleanArray(); + byte[] tmp = source.createByteArray(); + if (tmp == null) { + deletedKeys = null; + } else { + deletedKeys = PgpConversionHelper.BytesToPGPSecretKeyList(tmp); + } + keysExpiryDates = (ArrayList) source.readSerializable(); + keysUsages = source.readArrayList(Integer.class.getClassLoader()); + newPassphrase = source.readString(); + oldPassphrase = source.readString(); + newKeys = source.createBooleanArray(); + keys = PgpConversionHelper.BytesToPGPSecretKeyList(source.createByteArray()); + originalPrimaryID = source.readString(); + } + + @Override + public void writeToParcel(Parcel destination, int flags) { + destination.writeSerializable(userIds); //might not be the best method to store. + destination.writeSerializable(originalIDs); + destination.writeSerializable(deletedIDs); + destination.writeBooleanArray(newIDs); + destination.writeByte((byte) (primaryIDChanged ? 1 : 0)); + destination.writeBooleanArray(moddedKeys); + destination.writeByteArray(encodeArrayList(deletedKeys)); + destination.writeSerializable(keysExpiryDates); + destination.writeList(keysUsages); + destination.writeString(newPassphrase); + destination.writeString(oldPassphrase); + destination.writeBooleanArray(newKeys); + destination.writeByteArray(encodeArrayList(keys)); + destination.writeString(originalPrimaryID); + } + + public static final Creator CREATOR = new Creator() { + public OldSaveKeyringParcel createFromParcel(final Parcel source) { + return new OldSaveKeyringParcel(source); + } + + public OldSaveKeyringParcel[] newArray(final int size) { + return new OldSaveKeyringParcel[size]; + } + }; + + private static byte[] encodeArrayList(ArrayList list) { + if(list.isEmpty()) { + return null; + } + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + for(UncachedSecretKey key : new IterableIterator(list.iterator())) { + try { + key.encodeSecretKey(os); + } catch (IOException e) { + Log.e(Constants.TAG, "Error while converting ArrayList to byte[]!", e); + } + } + return os.toByteArray(); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java deleted file mode 100644 index 60fdf895d..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2014 Ash Hughes - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.service; - -import android.os.Parcel; -import android.os.Parcelable; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; -import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Calendar; - -public class SaveKeyringParcel implements Parcelable { - - public ArrayList userIds; - public ArrayList originalIDs; - public ArrayList deletedIDs; - public boolean[] newIDs; - public boolean primaryIDChanged; - public boolean[] moddedKeys; - public ArrayList deletedKeys; - public ArrayList keysExpiryDates; - public ArrayList keysUsages; - public String newPassphrase; - public String oldPassphrase; - public boolean[] newKeys; - public ArrayList keys; - public String originalPrimaryID; - - public SaveKeyringParcel() {} - - private SaveKeyringParcel(Parcel source) { - userIds = (ArrayList) source.readSerializable(); - originalIDs = (ArrayList) source.readSerializable(); - deletedIDs = (ArrayList) source.readSerializable(); - newIDs = source.createBooleanArray(); - primaryIDChanged = source.readByte() != 0; - moddedKeys = source.createBooleanArray(); - byte[] tmp = source.createByteArray(); - if (tmp == null) { - deletedKeys = null; - } else { - deletedKeys = PgpConversionHelper.BytesToPGPSecretKeyList(tmp); - } - keysExpiryDates = (ArrayList) source.readSerializable(); - keysUsages = source.readArrayList(Integer.class.getClassLoader()); - newPassphrase = source.readString(); - oldPassphrase = source.readString(); - newKeys = source.createBooleanArray(); - keys = PgpConversionHelper.BytesToPGPSecretKeyList(source.createByteArray()); - originalPrimaryID = source.readString(); - } - - @Override - public void writeToParcel(Parcel destination, int flags) { - destination.writeSerializable(userIds); //might not be the best method to store. - destination.writeSerializable(originalIDs); - destination.writeSerializable(deletedIDs); - destination.writeBooleanArray(newIDs); - destination.writeByte((byte) (primaryIDChanged ? 1 : 0)); - destination.writeBooleanArray(moddedKeys); - destination.writeByteArray(encodeArrayList(deletedKeys)); - destination.writeSerializable(keysExpiryDates); - destination.writeList(keysUsages); - destination.writeString(newPassphrase); - destination.writeString(oldPassphrase); - destination.writeBooleanArray(newKeys); - destination.writeByteArray(encodeArrayList(keys)); - destination.writeString(originalPrimaryID); - } - - public static final Creator CREATOR = new Creator() { - public SaveKeyringParcel createFromParcel(final Parcel source) { - return new SaveKeyringParcel(source); - } - - public SaveKeyringParcel[] newArray(final int size) { - return new SaveKeyringParcel[size]; - } - }; - - private static byte[] encodeArrayList(ArrayList list) { - if(list.isEmpty()) { - return null; - } - - ByteArrayOutputStream os = new ByteArrayOutputStream(); - for(UncachedSecretKey key : new IterableIterator(list.iterator())) { - try { - key.encodeSecretKey(os); - } catch (IOException e) { - Log.e(Constants.TAG, "Error while converting ArrayList to byte[]!", e); - } - } - return os.toByteArray(); - } - - @Override - public int describeContents() { - return 0; - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index ae380552a..d9c7a1736 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -57,8 +57,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.OldSaveKeyringParcel; import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; @@ -553,7 +553,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING); - SaveKeyringParcel saveParams = new SaveKeyringParcel(); + OldSaveKeyringParcel saveParams = new OldSaveKeyringParcel(); saveParams.userIds = getUserIds(mUserIdsView); saveParams.originalIDs = mUserIdsView.getOriginalIDs(); saveParams.deletedIDs = mUserIdsView.getDeletedIDs(); -- cgit v1.2.3 From 6415290b2d059752ebcfd74fa2c514aa5e5ef875 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 9 May 2014 15:30:14 +0200 Subject: introduce new SaveKeyringParcel --- .../keychain/service/SaveKeyringParcel.java | 113 +++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java new file mode 100644 index 000000000..fffcdacc8 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -0,0 +1,113 @@ +package org.sufficientlysecure.keychain.service; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.Serializable; +import java.util.HashMap; + +/** This class is a a transferable representation for a collection of changes + * to be done on a keyring. + * + * This class should include all types of operations supported in the backend. + * + * All changes are done in a differential manner. Besides the two key + * identification attributes, all attributes may be null, which indicates no + * change to the keyring. + * + * Application of operations in the backend should be fail-fast, which means an + * error in any included operation (for example revocation of a non-existent + * subkey) will cause the operation as a whole to fail. + */ +public class SaveKeyringParcel implements Parcelable { + + // the master key id to be edited + private final long mMasterKeyId; + // the key fingerprint, for safety + private final byte[] mFingerprint; + + public String newPassphrase; + + public String[] addUserIds; + public SubkeyAdd[] addSubKeys; + + public HashMap changeSubKeys; + public String changePrimaryUserId; + + public String[] revokeUserIds; + public long[] revokeSubKeys; + + public SaveKeyringParcel(long masterKeyId, byte[] fingerprint) { + mMasterKeyId = masterKeyId; + mFingerprint = fingerprint; + } + + // performance gain for using Parcelable here would probably be negligible, + // use Serializable instead. + public static class SubkeyAdd implements Serializable { + public final int mKeysize; + public final int mFlags; + public final Long mExpiry; + public SubkeyAdd(int keysize, int flags, long expiry) { + mKeysize = keysize; + mFlags = flags; + mExpiry = expiry; + } + } + + public static class SubkeyChange implements Serializable { + public final long mKeyId; + public final Integer mFlags; + public final Long mExpiry; + public SubkeyChange(long keyId, int flags, long expiry) { + mKeyId = keyId; + mFlags = flags; + mExpiry = expiry; + } + } + + public SaveKeyringParcel(Parcel source) { + mMasterKeyId = source.readLong(); + mFingerprint = source.createByteArray(); + + addUserIds = source.createStringArray(); + addSubKeys = (SubkeyAdd[]) source.readSerializable(); + + changeSubKeys = (HashMap) source.readSerializable(); + changePrimaryUserId = source.readString(); + + revokeUserIds = source.createStringArray(); + revokeSubKeys = source.createLongArray(); + } + + @Override + public void writeToParcel(Parcel destination, int flags) { + destination.writeLong(mMasterKeyId); + destination.writeByteArray(mFingerprint); + + destination.writeStringArray(addUserIds); + destination.writeSerializable(addSubKeys); + + destination.writeSerializable(changeSubKeys); + destination.writeString(changePrimaryUserId); + + destination.writeStringArray(revokeUserIds); + destination.writeLongArray(revokeSubKeys); + } + + public static final Creator CREATOR = new Creator() { + public SaveKeyringParcel createFromParcel(final Parcel source) { + return new SaveKeyringParcel(source); + } + + public SaveKeyringParcel[] newArray(final int size) { + return new SaveKeyringParcel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + +} -- cgit v1.2.3 From a53da491c09fc7db814d4c2358ffe5dc9fe888bc Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 May 2014 15:37:55 +0200 Subject: new savekeyring operation (mostly stub) --- .../keychain/pgp/PgpConversionHelper.java | 24 -- .../keychain/pgp/PgpImportExport.java | 12 +- .../keychain/pgp/PgpKeyOperation.java | 338 ++++++++++++++++++++- .../keychain/pgp/UncachedKeyRing.java | 49 ++- .../keychain/pgp/UncachedPublicKey.java | 21 +- .../keychain/pgp/UncachedSecretKeyRing.java | 28 +- .../keychain/pgp/WrappedKeyRing.java | 7 + .../keychain/pgp/WrappedSecretKeyRing.java | 4 + .../keychain/pgp/WrappedSignature.java | 77 +++-- .../keychain/provider/KeychainDatabase.java | 34 +-- .../keychain/provider/ProviderHelper.java | 265 +++++----------- .../keychain/service/KeychainIntentService.java | 29 +- .../keychain/service/PassphraseCacheService.java | 48 +-- .../keychain/service/SaveKeyringParcel.java | 9 +- .../keychain/ui/ViewKeyShareFragment.java | 4 + .../ui/dialog/PassphraseDialogFragment.java | 2 +- 16 files changed, 595 insertions(+), 356 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java index 63e2ff2f2..ea3c72fd0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java @@ -21,8 +21,6 @@ import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureList; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.Log; @@ -122,26 +120,4 @@ public class PgpConversionHelper { return new UncachedSecretKey(secKey); } - /** - * Convert from byte[] to PGPSignature - * - * @param sigBytes - * @return - */ - public static PGPSignature BytesToPGPSignature(byte[] sigBytes) { - PGPObjectFactory factory = new PGPObjectFactory(sigBytes); - PGPSignatureList signatures = null; - try { - if ((signatures = (PGPSignatureList) factory.nextObject()) == null || signatures.isEmpty()) { - Log.e(Constants.TAG, "No signatures given!"); - return null; - } - } catch (IOException e) { - Log.e(Constants.TAG, "Error while converting to PGPSignature!", e); - return null; - } - - return signatures.get(0); - } - } 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 e858012f5..268906037 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -257,7 +257,8 @@ public class PgpImportExport { updateProgress(progress * 100 / masterKeyIdsSize, 100); try { - PGPSecretKeyRing secretKeyRing = mProviderHelper.getPGPSecretKeyRing(secretKeyMasterId); + WrappedSecretKeyRing secretKeyRing = + mProviderHelper.getWrappedSecretKeyRing(secretKeyMasterId); secretKeyRing.encode(arOutStream); } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); @@ -287,18 +288,13 @@ public class PgpImportExport { public int storeKeyRingInCache(UncachedKeyRing ring, UncachedKeyRing secretRing) { int status; try { - // TODO make sure these are correctly typed! - PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) ring.getRing(); - PGPSecretKeyRing secretKeyRing = null; - if(secretRing != null) { - secretKeyRing = (PGPSecretKeyRing) secretRing.getRing(); - } + UncachedSecretKeyRing secretKeyRing = null; // see what type we have. we can either have a secret + public keyring, or just public if (secretKeyRing != null) { mProviderHelper.saveKeyRing(ring, secretRing); status = RETURN_OK; } else { - mProviderHelper.saveKeyRing(publicKeyRing); + mProviderHelper.saveKeyRing(ring); status = RETURN_OK; } } catch (IOException 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 f49e0af4b..3e296edb9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -35,6 +35,7 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureGenerator; import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; @@ -49,6 +50,8 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.service.OldSaveKeyringParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Primes; import java.io.IOException; @@ -60,9 +63,11 @@ import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.SignatureException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.Iterator; +import java.util.List; import java.util.TimeZone; /** @@ -644,7 +649,7 @@ public class PgpKeyOperation { for(String uid : new IterableIterator(secretKeyRing.getPublicKey().getUserIDs())) { for(PGPSignature sig : new IterableIterator( - secretKeyRing.getPublicKey().getSignaturesForID(uid))) { + secretKeyRing.getPublicKey().getSignaturesForId(uid))) { Log.d(Constants.TAG, "sig: " + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid); } @@ -655,7 +660,7 @@ public class PgpKeyOperation { for(String uid : new IterableIterator(publicKeyRing.getPublicKey().getUserIDs())) { for(PGPSignature sig : new IterableIterator( - publicKeyRing.getPublicKey().getSignaturesForID(uid))) { + publicKeyRing.getPublicKey().getSignaturesForId(uid))) { Log.d(Constants.TAG, "sig: " + PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid); } @@ -668,6 +673,335 @@ public class PgpKeyOperation { } + public Pair buildSecretKey(PGPSecretKeyRing sKR, + PGPPublicKeyRing pKR, + SaveKeyringParcel saveParcel, + String passphrase) + throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { + + updateProgress(R.string.progress_building_key, 0, 100); + + // sort these, so we can use binarySearch later on + Arrays.sort(saveParcel.revokeSubKeys); + Arrays.sort(saveParcel.revokeUserIds); + + /* + * What's gonna happen here: + * + * 1. Unlock private key + * + * 2. Create new secret key ring + * + * 3. Copy subkeys + * - Generate revocation if requested + * - Copy old cert, or generate new if change requested + * + * 4. Generate and add new subkeys + * + * 5. Copy user ids + * - Generate revocation if requested + * - Copy old cert, or generate new if primary user id status changed + * + * 6. Add new user ids + * + * 7. Generate PublicKeyRing from SecretKeyRing + * + * 8. Return pair (PublicKeyRing,SecretKeyRing) + * + */ + + // 1. Unlock private key + updateProgress(R.string.progress_building_key, 0, 100); + + PGPPublicKey masterPublicKey = sKR.getPublicKey(); + PGPPrivateKey masterPrivateKey; { + PGPSecretKey masterKey = sKR.getSecretKey(); + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor); + } + + // 2. Create new secret key ring + updateProgress(R.string.progress_certifying_master_key, 20, 100); + + // Note we do NOT use PGPKeyRingGeneraor, it's just one level too high and does stuff + // we want to do manually. Instead, we simply use a list of secret keys. + ArrayList secretKeys = new ArrayList(); + ArrayList publicKeys = new ArrayList(); + + // 3. Copy subkeys + // - Generate revocation if requested + // - Copy old cert, or generate new if change requested + for (PGPSecretKey sKey : new IterableIterator(sKR.getSecretKeys())) { + PGPPublicKey pKey = sKey.getPublicKey(); + if (Arrays.binarySearch(saveParcel.revokeSubKeys, sKey.getKeyID()) >= 0) { + // add revocation signature to key, if there is none yet + if (!pKey.getSignaturesOfType(PGPSignature.SUBKEY_REVOCATION).hasNext()) { + // generate revocation signature + } + } + if (saveParcel.changeSubKeys.containsKey(sKey.getKeyID())) { + // change subkey flags? + SaveKeyringParcel.SubkeyChange change = saveParcel.changeSubKeys.get(sKey.getKeyID()); + // remove old subkey binding signature(s?) + for (PGPSignature sig : new IterableIterator( + pKey.getSignaturesOfType(PGPSignature.SUBKEY_BINDING))) { + pKey = PGPPublicKey.removeCertification(pKey, sig); + } + + // generate and add new signature + PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, + sKey, pKey, change.mFlags, change.mExpiry, passphrase); + pKey = PGPPublicKey.addCertification(pKey, sig); + } + secretKeys.add(PGPSecretKey.replacePublicKey(sKey, pKey)); + publicKeys.add(pKey); + } + + // 4. Generate and add new subkeys + // TODO + + // 5. Copy user ids + for (String userId : new IterableIterator(masterPublicKey.getUserIDs())) { + // - Copy old cert, or generate new if primary user id status changed + boolean certified = false, revoked = false; + for (PGPSignature sig : new IterableIterator( + masterPublicKey.getSignaturesForID(userId))) { + // We know there are only revocation and certification types in here. + switch(sig.getSignatureType()) { + case PGPSignature.CERTIFICATION_REVOCATION: + revoked = true; + continue; + + case PGPSignature.DEFAULT_CERTIFICATION: + case PGPSignature.NO_CERTIFICATION: + case PGPSignature.CASUAL_CERTIFICATION: + case PGPSignature.POSITIVE_CERTIFICATION: + // Already got one? Remove this one, then. + if (certified) { + masterPublicKey = PGPPublicKey.removeCertification( + masterPublicKey, userId, sig); + continue; + } + boolean primary = userId.equals(saveParcel.changePrimaryUserId); + // Generate a new one under certain circumstances + if (saveParcel.changePrimaryUserId != null && + sig.getHashedSubPackets().isPrimaryUserID() != primary) { + PGPSignature cert = generateUserIdSignature( + masterPrivateKey, masterPublicKey, userId, primary); + PGPPublicKey.addCertification(masterPublicKey, userId, cert); + } + certified = true; + } + } + // - Generate revocation if requested + if (!revoked && Arrays.binarySearch(saveParcel.revokeUserIds, userId) >= 0) { + PGPSignature cert = generateRevocationSignature(masterPrivateKey, + masterPublicKey, userId); + masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert); + } + } + + // 6. Add new user ids + for(String userId : saveParcel.addUserIds) { + PGPSignature cert = generateUserIdSignature(masterPrivateKey, + masterPublicKey, userId, userId.equals(saveParcel.changePrimaryUserId)); + masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert); + } + + // 7. Generate PublicKeyRing from SecretKeyRing + updateProgress(R.string.progress_building_master_key, 30, 100); + PGPSecretKeyRing ring = new PGPSecretKeyRing(secretKeys); + + // Copy all non-self uid certificates + for (String userId : new IterableIterator(masterPublicKey.getUserIDs())) { + // - Copy old cert, or generate new if primary user id status changed + boolean certified = false, revoked = false; + for (PGPSignature sig : new IterableIterator( + masterPublicKey.getSignaturesForID(userId))) { + } + } + + for (PGPPublicKey newKey : publicKeys) { + PGPPublicKey oldKey = pKR.getPublicKey(newKey.getKeyID()); + for (PGPSignature sig : new IterableIterator( + oldKey.getSignatures())) { + } + } + + // If requested, set new passphrase + if (saveParcel.newPassphrase != null) { + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build() + .get(HashAlgorithmTags.SHA1); + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + // Build key encryptor based on new passphrase + PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder( + PGPEncryptedData.CAST5, sha1Calc) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( + saveParcel.newPassphrase.toCharArray()); + + sKR = PGPSecretKeyRing.copyWithNewPassword(sKR, keyDecryptor, keyEncryptorNew); + } + + // 8. Return pair (PublicKeyRing,SecretKeyRing) + + return new Pair(sKR, pKR); + + } + + private static PGPSignature generateUserIdSignature( + PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary) + throws IOException, PGPException, SignatureException { + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + pKey.getAlgorithm(), PGPUtil.SHA1) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); + subHashedPacketsGen.setSignatureCreationTime(false, new Date()); + subHashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS); + subHashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS); + subHashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS); + subHashedPacketsGen.setPrimaryUserID(false, primary); + sGen.setHashedSubpackets(subHashedPacketsGen.generate()); + sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey); + return sGen.generateCertification(userId, pKey); + } + + private static PGPSignature generateRevocationSignature( + PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId) + throws IOException, PGPException, SignatureException { + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + pKey.getAlgorithm(), PGPUtil.SHA1) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); + subHashedPacketsGen.setSignatureCreationTime(false, new Date()); + sGen.setHashedSubpackets(subHashedPacketsGen.generate()); + sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey); + return sGen.generateCertification(userId, pKey); + } + + private static PGPSignature generateSubkeyBindingSignature( + PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, + PGPSecretKey sKey, PGPPublicKey pKey, + int flags, Long expiry, String passphrase) + throws PgpGeneralMsgIdException, IOException, PGPException, SignatureException { + + // date for signing + Date todayDate = new Date(); + PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); + + // If this key can sign, we need a primary key binding signature + if ((flags & KeyFlags.SIGN_DATA) != 0) { + + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( + passphrase.toCharArray()); + PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor); + + // cross-certify signing keys + PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); + subHashedPacketsGen.setSignatureCreationTime(false, todayDate); + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + pKey.getAlgorithm(), PGPUtil.SHA1) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey); + sGen.setHashedSubpackets(subHashedPacketsGen.generate()); + PGPSignature certification = sGen.generateCertification(masterPublicKey, pKey); + unhashedPacketsGen.setEmbeddedSignature(false, certification); + } + + PGPSignatureSubpacketGenerator hashedPacketsGen; + { + hashedPacketsGen = new PGPSignatureSubpacketGenerator(); + hashedPacketsGen.setSignatureCreationTime(false, todayDate); + hashedPacketsGen.setKeyFlags(false, flags); + } + + if (expiry != null) { + Calendar creationDate = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + creationDate.setTime(pKey.getCreationTime()); + // note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c + // here we purposefully ignore partial days in each date - long type has + // no fractional part! + long numDays = (expiry / 86400000) - + (creationDate.getTimeInMillis() / 86400000); + if (numDays <= 0) { + throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); + } + hashedPacketsGen.setKeyExpirationTime(false, expiry - creationDate.getTimeInMillis()); + } else { + hashedPacketsGen.setKeyExpirationTime(false, 0); + } + + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + pKey.getAlgorithm(), PGPUtil.SHA1) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey); + sGen.setHashedSubpackets(hashedPacketsGen.generate()); + sGen.setUnhashedSubpackets(unhashedPacketsGen.generate()); + + return sGen.generateCertification(masterPublicKey, pKey); + + } + + + /** + * Certify the given pubkeyid with the given masterkeyid. + * + * @param certificationKey Certifying key + * @param publicKey public key to certify + * @param userIds User IDs to certify, must not be null or empty + * @param passphrase Passphrase of the secret key + * @return A keyring with added certifications + */ + public PGPPublicKey certifyKey(PGPSecretKey certificationKey, PGPPublicKey publicKey, + List userIds, String passphrase) + throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException, + PGPException, SignatureException { + + // create a signatureGenerator from the supplied masterKeyId and passphrase + PGPSignatureGenerator signatureGenerator; + { + + if (certificationKey == null) { + throw new PgpGeneralMsgIdException(R.string.error_no_signature_key); + } + + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor); + if (signaturePrivateKey == null) { + throw new PgpGeneralMsgIdException(R.string.error_could_not_extract_private_key); + } + + // TODO: SHA256 fixed? + JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( + certificationKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + + signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); + signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, signaturePrivateKey); + } + + { // supply signatureGenerator with a SubpacketVector + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + PGPSignatureSubpacketVector packetVector = spGen.generate(); + signatureGenerator.setHashedSubpackets(packetVector); + } + + // fetch public key ring, add the certification and return it + for (String userId : new IterableIterator(userIds.iterator())) { + PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); + publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); + } + + return publicKey; + } + /** * Simple static subclass that stores two values. *

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 06f890fb4..8bacb32c0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -1,8 +1,9 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; @@ -13,6 +14,8 @@ import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.util.Iterator; import java.util.List; import java.util.Vector; @@ -26,6 +29,10 @@ public class UncachedKeyRing { mIsSecret = ring instanceof PGPSecretKeyRing; } + public long getMasterKeyId() { + return mRing.getPublicKey().getKeyID(); + } + /* TODO don't use this */ @Deprecated public PGPKeyRing getRing() { @@ -36,6 +43,21 @@ public class UncachedKeyRing { return new UncachedPublicKey(mRing.getPublicKey()); } + public Iterator getPublicKeys() { + final Iterator it = mRing.getPublicKeys(); + return new Iterator() { + public void remove() { + it.remove(); + } + public UncachedPublicKey next() { + return new UncachedPublicKey(it.next()); + } + public boolean hasNext() { + return it.hasNext(); + } + }; + } + public boolean isSecret() { return mIsSecret; } @@ -50,6 +72,15 @@ public class UncachedKeyRing { public static UncachedKeyRing decodePubkeyFromData(byte[] data) throws PgpGeneralException, IOException { + UncachedKeyRing ring = decodeFromData(data); + if(ring.isSecret()) { + throw new PgpGeneralException("Object not recognized as PGPPublicKeyRing!"); + } + return ring; + } + + public static UncachedKeyRing decodeFromData(byte[] data) + throws PgpGeneralException, IOException { BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(data)); if (bufferedInput.available() > 0) { @@ -58,13 +89,14 @@ public class UncachedKeyRing { // get first object in block Object obj; - if ((obj = objectFactory.nextObject()) != null && obj instanceof PGPPublicKeyRing) { - return new UncachedKeyRing((PGPPublicKeyRing) obj); + if ((obj = objectFactory.nextObject()) != null && obj instanceof PGPKeyRing) { + // the constructor will take care of the public/secret part + return new UncachedKeyRing((PGPKeyRing) obj); } else { - throw new PgpGeneralException("Object not recognized as PGPPublicKeyRing!"); + throw new PgpGeneralException("Object not recognized as PGPKeyRing!"); } } else { - throw new PgpGeneralException("Object not recognized as PGPPublicKeyRing!"); + throw new PgpGeneralException("Object not recognized as PGPKeyRing!"); } } @@ -89,4 +121,11 @@ public class UncachedKeyRing { return result; } + public void encodeArmored(OutputStream out, String version) throws IOException { + ArmoredOutputStream aos = new ArmoredOutputStream(out); + aos.setHeader("Version", version); + aos.write(mRing.getEncoded()); + aos.close(); + } + } 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 5dbe4b316..e3db03bf6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.Iterator; import java.util.List; public class UncachedPublicKey { @@ -173,8 +174,24 @@ public class UncachedPublicKey { return mPublicKey.getFingerprint(); } - // Note that this method has package visibility - no access outside the pgp package! - PGPPublicKey getPublicKey() { + // TODO This method should have package visibility - no access outside the pgp package! + // (It's still used in ProviderHelper at this point) + public PGPPublicKey getPublicKey() { return mPublicKey; } + + public Iterator getSignaturesForId(String userId) { + final Iterator it = mPublicKey.getSignaturesForID(userId); + return new Iterator() { + public void remove() { + it.remove(); + } + public WrappedSignature next() { + return new WrappedSignature(it.next()); + } + public boolean hasNext() { + return it.hasNext(); + } + }; + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java index bda9ebbcf..ca784fbde 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java @@ -1,19 +1,33 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.S2K; +import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.util.IterableIterator; -public class UncachedSecretKeyRing { +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; - final PGPSecretKeyRing mSecretRing; +public class UncachedSecretKeyRing extends UncachedKeyRing { UncachedSecretKeyRing(PGPSecretKeyRing secretRing) { - mSecretRing = secretRing; + super(secretRing); } - // Breaking the pattern here, for key import! - // TODO reduce this from public to default visibility! - public PGPSecretKeyRing getSecretKeyRing() { - return mSecretRing; + public ArrayList getAvailableSubkeys() { + ArrayList result = new ArrayList(); + // 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; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java index 94eb91420..6e7b2a49e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java @@ -5,6 +5,9 @@ import org.spongycastle.openpgp.PGPPublicKey; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.util.IterableIterator; +import java.io.IOException; +import java.io.OutputStream; + public abstract class WrappedKeyRing extends KeyRing { private final boolean mHasAnySecret; @@ -76,6 +79,10 @@ public abstract class WrappedKeyRing extends KeyRing { } } + public void encode(OutputStream stream) throws IOException { + getRing().encode(stream); + } + abstract PGPKeyRing getRing(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java index c94b7dfba..656430969 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java @@ -120,4 +120,8 @@ public class WrappedSecretKeyRing extends WrappedKeyRing { }); } + public UncachedSecretKeyRing getUncached() { + return new UncachedSecretKeyRing(mRing); + } + } 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 cdadbca7f..9f26439d2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -5,6 +5,7 @@ import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.bcpg.sig.RevocationReason; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; @@ -14,6 +15,7 @@ import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; import java.security.SignatureException; +import java.util.Date; public class WrappedSignature { @@ -33,16 +35,57 @@ public class WrappedSignature { return mSig.getKeyID(); } + public int getSignatureType() { + return mSig.getSignatureType(); + } + public int getKeyAlgorithm() { return mSig.getKeyAlgorithm(); } + public Date getCreationTime() { + return mSig.getCreationTime(); + } + + public byte[] getEncoded() throws IOException { + return mSig.getEncoded(); + } + + public boolean isRevocation() { + return mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.REVOCATION_REASON); + } + + public boolean isPrimaryUserId() { + return mSig.getHashedSubPackets().isPrimaryUserID(); + } + + public String getRevocationReason() throws PgpGeneralException { + if(!isRevocation()) { + throw new PgpGeneralException("Not a revocation signature."); + } + SignatureSubpacket p = mSig.getHashedSubPackets().getSubpacket( + SignatureSubpacketTags.REVOCATION_REASON); + // For some reason, this is missing in SignatureSubpacketInputStream:146 + if (!(p instanceof RevocationReason)) { + p = new RevocationReason(false, p.getData()); + } + return ((RevocationReason) p).getRevocationDescription(); + } + public void init(WrappedPublicKey key) throws PgpGeneralException { + init(key.getPublicKey()); + } + + public void init(UncachedPublicKey key) throws PgpGeneralException { + init(key.getPublicKey()); + } + + protected void init(PGPPublicKey key) throws PgpGeneralException { try { JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - mSig.init(contentVerifierBuilderProvider, key.getPublicKey()); + mSig.init(contentVerifierBuilderProvider, key); } catch(PGPException e) { throw new PgpGeneralException(e); } @@ -74,30 +117,9 @@ public class WrappedSignature { } } - public boolean isRevocation() { - return mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.REVOCATION_REASON); - } - - public String getRevocationReason() throws PgpGeneralException { - if(!isRevocation()) { - throw new PgpGeneralException("Not a revocation signature."); - } - SignatureSubpacket p = mSig.getHashedSubPackets().getSubpacket( - SignatureSubpacketTags.REVOCATION_REASON); - // For some reason, this is missing in SignatureSubpacketInputStream:146 - if (!(p instanceof RevocationReason)) { - p = new RevocationReason(false, p.getData()); - } - return ((RevocationReason) p).getRevocationDescription(); - } - - /** 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(WrappedPublicKey key, String uid) throws PgpGeneralException { + protected boolean verifySignature(PGPPublicKey key, String uid) throws PgpGeneralException { try { - return mSig.verifyCertification(uid, key.getPublicKey()); + return mSig.verifyCertification(uid, key); } catch (SignatureException e) { throw new PgpGeneralException("Error!", e); } catch (PGPException e) { @@ -105,6 +127,13 @@ 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 { + return verifySignature(key.getPublicKey(), uid); + } + public static WrappedSignature fromBytes(byte[] data) { PGPObjectFactory factory = new PGPObjectFactory(data); PGPSignatureList signatures = null; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 68726d3e0..ed8171587 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -23,11 +23,9 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.provider.BaseColumns; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKeyRing; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAccountsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns; @@ -256,6 +254,8 @@ public class KeychainDatabase extends SQLiteOpenHelper { }.getReadableDatabase(); Cursor cursor = null; + ProviderHelper providerHelper = new ProviderHelper(context); + try { // we insert in two steps: first, all public keys that have secret keys cursor = db.rawQuery("SELECT key_ring_data FROM key_rings WHERE type = 1 OR EXISTS (" @@ -266,14 +266,11 @@ public class KeychainDatabase extends SQLiteOpenHelper { for (int i = 0; i < cursor.getCount(); i++) { cursor.moveToPosition(i); byte[] data = cursor.getBlob(0); - PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data); - ProviderHelper providerHelper = new ProviderHelper(context); - if (ring instanceof PGPPublicKeyRing) - providerHelper.saveKeyRing((PGPPublicKeyRing) ring); - else if (ring instanceof PGPSecretKeyRing) - providerHelper.saveKeyRing((PGPSecretKeyRing) ring); - else { - Log.e(Constants.TAG, "Unknown blob data type!"); + try { + UncachedKeyRing ring = UncachedKeyRing.decodeFromData(data); + providerHelper.saveKeyRing(ring); + } catch(PgpGeneralException e) { + Log.e(Constants.TAG, "Error decoding keyring blob!"); } } } @@ -293,14 +290,11 @@ public class KeychainDatabase extends SQLiteOpenHelper { for (int i = 0; i < cursor.getCount(); i++) { cursor.moveToPosition(i); byte[] data = cursor.getBlob(0); - PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data); - ProviderHelper providerHelper = new ProviderHelper(context); - if (ring instanceof PGPPublicKeyRing) { - providerHelper.saveKeyRing((PGPPublicKeyRing) ring); - } else if (ring instanceof PGPSecretKeyRing) { - providerHelper.saveKeyRing((PGPSecretKeyRing) ring); - } else { - Log.e(Constants.TAG, "Unknown blob data type!"); + try { + UncachedKeyRing ring = UncachedKeyRing.decodeFromData(data); + providerHelper.saveKeyRing(ring); + } catch(PgpGeneralException e) { + Log.e(Constants.TAG, "Error decoding keyring blob!"); } } } 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 67d11f9f0..b6f75e00d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -23,30 +23,21 @@ import android.content.ContentValues; import android.content.Context; import android.content.OperationApplicationException; import android.database.Cursor; -import android.database.DatabaseUtils; import android.net.Uri; import android.os.RemoteException; import android.support.v4.util.LongSparseArray; -import org.spongycastle.bcpg.ArmoredOutputStream; -import org.spongycastle.bcpg.S2K; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedSignature; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; @@ -60,7 +51,6 @@ import org.sufficientlysecure.keychain.util.Log; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.security.SignatureException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -147,19 +137,26 @@ public class ProviderHelper { return getGenericData(KeyRings.buildUnifiedKeyRingUri(masterKeyId), proj, types); } - @Deprecated - public LongSparseArray getPGPKeyRings(Uri queryUri) { + private LongSparseArray getUncachedMasterKeys(Uri queryUri) { Cursor cursor = mContentResolver.query(queryUri, new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA}, null, null, null); - LongSparseArray result = new LongSparseArray(cursor.getCount()); + LongSparseArray result = + new LongSparseArray(cursor.getCount()); try { if (cursor != null && cursor.moveToFirst()) do { long masterKeyId = cursor.getLong(0); byte[] data = cursor.getBlob(1); if (data != null) { - result.put(masterKeyId, PgpConversionHelper.BytesToPGPKeyRing(data)); + try { + result.put(masterKeyId, + UncachedKeyRing.decodePubkeyFromData(data).getPublicKey()); + } catch(PgpGeneralException e) { + Log.e(Constants.TAG, "Error parsing keyring, skipping."); + } catch(IOException e) { + Log.e(Constants.TAG, "IO error, skipping keyring"); + } } } while (cursor.moveToNext()); } finally { @@ -194,12 +191,13 @@ public class ProviderHelper { private KeyRing getWrappedKeyRing(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 - KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED, - // and of course, ring data - secret ? KeyRings.PRIVKEY_DATA : KeyRings.PUBKEY_DATA - }, null, null, null); + new String[]{ + // we pick from cache only information that is not easily available from keyrings + KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED, + // and of course, ring data + secret ? KeyRings.PRIVKEY_DATA : KeyRings.PUBKEY_DATA + }, null, null, null + ); try { if (cursor != null && cursor.moveToFirst()) { @@ -219,37 +217,18 @@ public class ProviderHelper { } } - @Deprecated - public PGPKeyRing getPGPKeyRing(Uri queryUri) throws NotFoundException { - LongSparseArray result = getPGPKeyRings(queryUri); - if (result.size() == 0) { - throw new NotFoundException("PGPKeyRing object not found!"); - } else { - return result.valueAt(0); - } - } - - /** - * Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId - */ - @Deprecated - public PGPSecretKeyRing getPGPSecretKeyRing(long masterKeyId) throws NotFoundException { - Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)); - return (PGPSecretKeyRing) getPGPKeyRing(queryUri); - } - /** * Saves PGPPublicKeyRing with its keys and userIds in DB */ @SuppressWarnings("unchecked") - public void saveKeyRing(PGPPublicKeyRing keyRing) throws IOException { - PGPPublicKey masterKey = keyRing.getPublicKey(); - long masterKeyId = masterKey.getKeyID(); + public void saveKeyRing(UncachedKeyRing keyRing) throws IOException { + UncachedPublicKey masterKey = keyRing.getPublicKey(); + long masterKeyId = masterKey.getKeyId(); // IF there is a secret key, preserve it! - PGPSecretKeyRing secretRing = null; + UncachedSecretKeyRing secretRing = null; try { - secretRing = getPGPSecretKeyRing(masterKeyId); + secretRing = getWrappedSecretKeyRing(masterKeyId).getUncached(); } catch (NotFoundException e) { Log.e(Constants.TAG, "key not found!"); } @@ -272,36 +251,38 @@ public class ProviderHelper { ArrayList operations = new ArrayList(); int rank = 0; - for (PGPPublicKey key : new IterableIterator(keyRing.getPublicKeys())) { + for (UncachedPublicKey key : new IterableIterator(keyRing.getPublicKeys())) { operations.add(buildPublicKeyOperations(masterKeyId, key, rank)); ++rank; } // get a list of owned secret keys, for verification filtering - LongSparseArray allKeyRings = getPGPKeyRings(KeyRingData.buildSecretKeyRingUri()); + LongSparseArray allKeyRings = + getUncachedMasterKeys(KeyRingData.buildSecretKeyRingUri()); // special case: available secret keys verify themselves! - if (secretRing != null) - allKeyRings.put(secretRing.getSecretKey().getKeyID(), secretRing); + if (secretRing != null) { + allKeyRings.put(secretRing.getMasterKeyId(), secretRing.getPublicKey()); + } // classify and order user ids. primary are moved to the front, revoked to the back, // otherwise the order in the keyfile is preserved. List uids = new ArrayList(); - for (String userId : new IterableIterator(masterKey.getUserIDs())) { + for (String userId : new IterableIterator( + masterKey.getUnorderedUserIds().iterator())) { UserIdItem item = new UserIdItem(); uids.add(item); item.userId = userId; // look through signatures for this specific key - for (PGPSignature cert : new IterableIterator( - masterKey.getSignaturesForID(userId))) { - long certId = cert.getKeyID(); + for (WrappedSignature cert : new IterableIterator( + masterKey.getSignaturesForId(userId))) { + long certId = cert.getKeyId(); try { // self signature if (certId == masterKeyId) { - cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), masterKey); - if (!cert.verifyCertification(userId, masterKey)) { + cert.init(masterKey); + if (!cert.verifySignature(masterKey, userId)) { // not verified?! dang! TODO notify user? this is kinda serious... Log.e(Constants.TAG, "Could not verify self signature for " + userId + "!"); continue; @@ -310,31 +291,22 @@ public class ProviderHelper { if (item.selfCert == null || item.selfCert.getCreationTime().before(cert.getCreationTime())) { item.selfCert = cert; - item.isPrimary = cert.getHashedSubPackets().isPrimaryUserID(); - item.isRevoked = - cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION; + item.isPrimary = cert.isPrimaryUserId(); + item.isRevoked = cert.isRevocation(); } } // verify signatures from known private keys if (allKeyRings.indexOfKey(certId) >= 0) { - // mark them as verified - cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), - allKeyRings.get(certId).getPublicKey()); - if (cert.verifyCertification(userId, masterKey)) { + cert.init(allKeyRings.get(certId)); + if (cert.verifySignature(masterKey, userId)) { item.trustedCerts.add(cert); } } - } catch (SignatureException e) { - Log.e(Constants.TAG, "Signature verification failed! " - + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID()) - + " from " - + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e); - } catch (PGPException e) { + } catch (PgpGeneralException e) { Log.e(Constants.TAG, "Signature verification failed! " - + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID()) + + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyId()) + " from " - + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e); + + PgpKeyHelper.convertKeyIdToHex(cert.getKeyId()), e); } } } @@ -380,8 +352,8 @@ public class ProviderHelper { String userId; boolean isPrimary = false; boolean isRevoked = false; - PGPSignature selfCert; - List trustedCerts = new ArrayList(); + WrappedSignature selfCert; + List trustedCerts = new ArrayList(); @Override public int compareTo(UserIdItem o) { @@ -401,18 +373,8 @@ public class ProviderHelper { * Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring * is already in the database! */ - public void saveKeyRing(UncachedSecretKeyRing wrappedRing) throws IOException { - // TODO split up getters - PGPSecretKeyRing keyRing = wrappedRing.getSecretKeyRing(); - saveKeyRing(keyRing); - } - - /** - * Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring - * is already in the database! - */ - public void saveKeyRing(PGPSecretKeyRing keyRing) throws IOException { - long masterKeyId = keyRing.getSecretKey().getKeyID(); + public void saveKeyRing(UncachedSecretKeyRing keyRing) throws IOException { + long masterKeyId = keyRing.getMasterKeyId(); { Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId)); @@ -424,14 +386,10 @@ public class ProviderHelper { values.put(Keys.HAS_SECRET, 1); // then, mark exactly the keys we have available - for (PGPSecretKey sub : new IterableIterator(keyRing.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) { - mContentResolver.update(uri, values, Keys.KEY_ID + " = ?", new String[]{ - Long.toString(sub.getKeyID()) - }); - } + for (Long sub : new IterableIterator(keyRing.getAvailableSubkeys().iterator())) { + mContentResolver.update(uri, values, Keys.KEY_ID + " = ?", new String[] { + Long.toString(sub) + }); } // this implicitly leaves all keys which were not in the secret key ring // with has_secret = 0 @@ -449,11 +407,6 @@ public class ProviderHelper { } - 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 */ @@ -464,32 +417,32 @@ public class ProviderHelper { mContentResolver.delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null); // save public keyring - saveKeyRing((PGPPublicKeyRing) pubRing.getRing()); - saveKeyRing((PGPSecretKeyRing) secRing.getRing()); + saveKeyRing(pubRing); + saveKeyRing(secRing); } /** * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing */ private ContentProviderOperation - buildPublicKeyOperations(long masterKeyId, PGPPublicKey key, int rank) throws IOException { + buildPublicKeyOperations(long masterKeyId, UncachedPublicKey key, int rank) throws IOException { ContentValues values = new ContentValues(); values.put(Keys.MASTER_KEY_ID, masterKeyId); values.put(Keys.RANK, rank); - values.put(Keys.KEY_ID, key.getKeyID()); + values.put(Keys.KEY_ID, key.getKeyId()); values.put(Keys.KEY_SIZE, key.getBitStrength()); values.put(Keys.ALGORITHM, key.getAlgorithm()); values.put(Keys.FINGERPRINT, key.getFingerprint()); - values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key))); - values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key))); - values.put(Keys.CAN_ENCRYPT, PgpKeyHelper.isEncryptionKey(key)); - values.put(Keys.IS_REVOKED, key.isRevoked()); + values.put(Keys.CAN_CERTIFY, key.canCertify()); + values.put(Keys.CAN_SIGN, key.canSign()); + values.put(Keys.CAN_ENCRYPT, key.canEncrypt()); + values.put(Keys.IS_REVOKED, key.maybeRevoked()); - values.put(Keys.CREATION, PgpKeyHelper.getCreationDate(key).getTime() / 1000); - Date expiryDate = PgpKeyHelper.getExpiryDate(key); + values.put(Keys.CREATION, key.getCreationTime().getTime() / 1000); + Date expiryDate = key.getExpiryTime(); if (expiryDate != null) { values.put(Keys.EXPIRY, expiryDate.getTime() / 1000); } @@ -503,11 +456,12 @@ public class ProviderHelper { * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing */ private ContentProviderOperation - buildCertOperations(long masterKeyId, int rank, PGPSignature cert, int verified) throws IOException { + buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, int verified) + throws IOException { ContentValues values = new ContentValues(); values.put(Certs.MASTER_KEY_ID, masterKeyId); values.put(Certs.RANK, rank); - values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyID()); + values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyId()); values.put(Certs.TYPE, cert.getSignatureType()); values.put(Certs.CREATION, cert.getCreationTime().getTime() / 1000); values.put(Certs.VERIFIED, verified); @@ -535,23 +489,11 @@ public class ProviderHelper { return ContentProviderOperation.newInsert(uri).withValues(values).build(); } - private String getKeyRingAsArmoredString(byte[] data) throws IOException { - Object keyRing = null; - if (data != null) { - keyRing = PgpConversionHelper.BytesToPGPKeyRing(data); - } + private String getKeyRingAsArmoredString(byte[] data) throws IOException, PgpGeneralException { + UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(data); ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ArmoredOutputStream aos = new ArmoredOutputStream(bos); - aos.setHeader("Version", PgpHelper.getFullVersion(mContext)); - - if (keyRing instanceof PGPSecretKeyRing) { - aos.write(((PGPSecretKeyRing) keyRing).getEncoded()); - } else if (keyRing instanceof PGPPublicKeyRing) { - aos.write(((PGPPublicKeyRing) keyRing).getEncoded()); - } - aos.close(); - + keyRing.encodeArmored(bos, PgpHelper.getFullVersion(mContext)); String armoredKey = bos.toString("UTF-8"); Log.d(Constants.TAG, "armoredKey:" + armoredKey); @@ -560,77 +502,12 @@ public class ProviderHelper { } public String getKeyRingAsArmoredString(Uri uri) - throws NotFoundException, IOException { + throws NotFoundException, IOException, PgpGeneralException { byte[] data = (byte[]) getGenericData( uri, KeyRingData.KEY_RING_DATA, ProviderHelper.FIELD_TYPE_BLOB); return getKeyRingAsArmoredString(data); } - /** - * TODO: currently not used, but will be needed to upload many keys at once! - * - * @param masterKeyIds - * @return - * @throws IOException - */ - public ArrayList getKeyRingsAsArmoredString(long[] masterKeyIds) - throws IOException { - ArrayList output = new ArrayList(); - - if (masterKeyIds == null || masterKeyIds.length == 0) { - Log.e(Constants.TAG, "No master keys given!"); - return output; - } - - // Build a cursor for the selected masterKeyIds - Cursor cursor; - { - String inMasterKeyList = KeyRingData.MASTER_KEY_ID + " IN ("; - for (int i = 0; i < masterKeyIds.length; ++i) { - if (i != 0) { - inMasterKeyList += ", "; - } - inMasterKeyList += DatabaseUtils.sqlEscapeString("" + masterKeyIds[i]); - } - inMasterKeyList += ")"; - - cursor = mContentResolver.query(KeyRingData.buildPublicKeyRingUri(), new String[]{ - KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA - }, inMasterKeyList, null, null); - } - - try { - if (cursor != null) { - int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID); - int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA); - if (cursor.moveToFirst()) { - do { - Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol)); - - byte[] data = cursor.getBlob(dataCol); - - // get actual keyring data blob and write it to ByteArrayOutputStream - try { - output.add(getKeyRingAsArmoredString(data)); - } catch (IOException e) { - Log.e(Constants.TAG, "IOException", e); - } - } while (cursor.moveToNext()); - } - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - - if (output.size() > 0) { - return output; - } else { - return null; - } - } - public ArrayList getRegisteredApiApps() { Cursor cursor = mContentResolver.query(ApiApps.CONTENT_URI, null, null, null, null); 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 c2fc4334a..69eab9d4e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -26,16 +26,13 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; -import org.spongycastle.bcpg.sig.KeyFlags; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; +import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.WrappedSecretKey; import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; @@ -594,21 +591,21 @@ public class KeychainIntentService extends IntentService buf = keyOperations.createKey(Constants.choice.algorithm.rsa, 4096, passphrase, true); os.write(buf); - keyUsageList.add(KeyFlags.CERTIFY_OTHER); + keyUsageList.add(UncachedSecretKey.CERTIFY_OTHER); keysCreated++; setProgress(keysCreated, keysTotal); buf = keyOperations.createKey(Constants.choice.algorithm.rsa, 4096, passphrase, false); os.write(buf); - keyUsageList.add(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE); + keyUsageList.add(UncachedSecretKey.ENCRYPT_COMMS | UncachedSecretKey.ENCRYPT_STORAGE); keysCreated++; setProgress(keysCreated, keysTotal); buf = keyOperations.createKey(Constants.choice.algorithm.rsa, 4096, passphrase, false); os.write(buf); - keyUsageList.add(KeyFlags.SIGN_DATA); + keyUsageList.add(UncachedSecretKey.SIGN_DATA); keysCreated++; setProgress(keysCreated, keysTotal); @@ -749,23 +746,15 @@ public class KeychainIntentService extends IntentService byte[] downloadedKeyBytes = server.get(keybaseId).getBytes(); // create PGPKeyRing object based on downloaded armored key - PGPKeyRing downloadedKey = null; + UncachedKeyRing downloadedKey = null; BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes)); if (bufferedInput.available() > 0) { - InputStream in = PGPUtil.getDecoderStream(bufferedInput); - PGPObjectFactory objectFactory = new PGPObjectFactory(in); - - // get first object in block - Object obj; - if ((obj = objectFactory.nextObject()) != null) { - - if (obj instanceof PGPKeyRing) { - downloadedKey = (PGPKeyRing) obj; - } else { - throw new PgpGeneralException("Object not recognized as PGPKeyRing!"); - } + List rings = UncachedKeyRing.fromStream(bufferedInput); + if(rings.isEmpty()) { + throw new PgpGeneralException("No keys in result!"); } + downloadedKey = rings.get(0); } // save key bytes in entry object for doing the 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 17ba9df5c..d42bae67a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -34,12 +34,6 @@ import android.os.Messenger; import android.os.RemoteException; import android.support.v4.util.LongSparseArray; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing; @@ -48,7 +42,6 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; import java.util.Date; -import java.util.Iterator; /** * This service runs in its own process, but is available to all other processes as the main @@ -191,7 +184,8 @@ public class PassphraseCacheService extends Service { // get cached passphrase String cachedPassphrase = mPassphraseCache.get(keyId); if (cachedPassphrase == null) { - // this is an error + Log.d(TAG, "Passphrase not (yet) cached, returning null"); + // not really an error, just means the passphrase is not cached but not empty either return null; } @@ -206,44 +200,6 @@ public class PassphraseCacheService extends Service { } } - @Deprecated - public static boolean hasPassphrase(PGPSecretKeyRing secretKeyRing) { - PGPSecretKey secretKey = null; - boolean foundValidKey = false; - for (Iterator keys = secretKeyRing.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; - } - } - - /** - * Checks if key has a passphrase. - * - * @param secretKeyId - * @return true if it has a passphrase - */ - @Deprecated - public static boolean hasPassphrase(Context context, long secretKeyId) - throws ProviderHelper.NotFoundException { - return new ProviderHelper(context).getWrappedSecretKeyRing(secretKeyId).hasPassphrase(); - } - /** * Register BroadcastReceiver that is unregistered when service is destroyed. This * BroadcastReceiver hears on intents with ACTION_PASSPHRASE_CACHE_SERVICE to then timeout diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index fffcdacc8..3514ab2e5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -13,7 +13,8 @@ import java.util.HashMap; * * All changes are done in a differential manner. Besides the two key * identification attributes, all attributes may be null, which indicates no - * change to the keyring. + * change to the keyring. This is also the reason why boxed values are used + * instead of primitives in the subclasses. * * Application of operations in the backend should be fail-fast, which means an * error in any included operation (for example revocation of a non-existent @@ -45,10 +46,12 @@ public class SaveKeyringParcel implements Parcelable { // performance gain for using Parcelable here would probably be negligible, // use Serializable instead. public static class SubkeyAdd implements Serializable { + public final int mAlgorithm; public final int mKeysize; public final int mFlags; public final Long mExpiry; - public SubkeyAdd(int keysize, int flags, long expiry) { + public SubkeyAdd(int algorithm, int keysize, int flags, Long expiry) { + mAlgorithm = algorithm; mKeysize = keysize; mFlags = flags; mExpiry = expiry; @@ -59,7 +62,7 @@ public class SaveKeyringParcel implements Parcelable { public final long mKeyId; public final Integer mFlags; public final Long mExpiry; - public SubkeyChange(long keyId, int flags, long expiry) { + public SubkeyChange(long keyId, Integer flags, Long expiry) { mKeyId = keyId; mFlags = flags; mExpiry = expiry; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java index b3655133d..a264a804f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java @@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; @@ -190,6 +191,9 @@ public class ViewKeyShareFragment extends LoaderFragment implements } startActivity(Intent.createChooser(sendIntent, title)); } + } catch (PgpGeneralException e) { + Log.e(Constants.TAG, "error processing key!", e); + AppMsg.makeText(getActivity(), R.string.error_key_processing, AppMsg.STYLE_ALERT).show(); } catch (IOException e) { Log.e(Constants.TAG, "error processing key!", e); AppMsg.makeText(getActivity(), R.string.error_key_processing, AppMsg.STYLE_ALERT).show(); 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 e7bcd2bc0..5f47ee13c 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 @@ -102,7 +102,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).getWrappedSecretKeyRing(secretKeyId).hasPassphrase()) { throw new PgpGeneralException("No passphrase! No passphrase dialog needed!"); } } catch(ProviderHelper.NotFoundException e) { -- cgit v1.2.3 From ed8b62c32b704ce2150bfdf7d4047c67648423a1 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 28 May 2014 21:52:45 +0200 Subject: wrapped-key-ring: no UncachedSecretKeyRing after all --- .../keychain/pgp/PgpImportExport.java | 6 ++-- .../keychain/pgp/UncachedKeyRing.java | 26 +++++++++++++++-- .../keychain/pgp/UncachedSecretKeyRing.java | 33 ---------------------- .../keychain/pgp/WrappedPublicKeyRing.java | 15 +++++++++- .../keychain/pgp/WrappedSecretKeyRing.java | 24 ++++++++++++---- .../keychain/provider/KeychainDatabase.java | 4 +-- .../keychain/provider/KeychainProvider.java | 2 +- .../keychain/provider/ProviderHelper.java | 17 ++++++----- .../keychain/service/KeychainIntentService.java | 9 +++--- 9 files changed, 75 insertions(+), 61 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java (limited to 'OpenKeychain/src/main/java') 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 268906037..91bb89995 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -168,7 +168,7 @@ public class PgpImportExport { status = storeKeyRingInCache(new UncachedKeyRing(newPubRing), new UncachedKeyRing(secretKeyRing)); } else { - status = storeKeyRingInCache(new UncachedKeyRing((PGPPublicKeyRing) keyring)); + status = storeKeyRingInCache(new UncachedKeyRing(keyring)); } if (status == RETURN_ERROR) { @@ -288,13 +288,13 @@ public class PgpImportExport { public int storeKeyRingInCache(UncachedKeyRing ring, UncachedKeyRing secretRing) { int status; try { - UncachedSecretKeyRing secretKeyRing = null; + UncachedKeyRing secretKeyRing = null; // see what type we have. we can either have a secret + public keyring, or just public if (secretKeyRing != null) { mProviderHelper.saveKeyRing(ring, secretRing); status = RETURN_OK; } else { - mProviderHelper.saveKeyRing(ring); + mProviderHelper.savePublicKeyRing(ring); status = RETURN_OK; } } catch (IOException 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 8bacb32c0..e17d07390 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -1,13 +1,16 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.bcpg.S2K; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSecretKey; 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.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import java.io.BufferedInputStream; @@ -15,6 +18,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Vector; @@ -70,7 +74,7 @@ public class UncachedKeyRing { return mRing.getPublicKey().getFingerprint(); } - public static UncachedKeyRing decodePubkeyFromData(byte[] data) + public static UncachedKeyRing decodePublicFromData(byte[] data) throws PgpGeneralException, IOException { UncachedKeyRing ring = decodeFromData(data); if(ring.isSecret()) { @@ -90,7 +94,6 @@ public class UncachedKeyRing { // get first object in block Object obj; if ((obj = objectFactory.nextObject()) != null && obj instanceof PGPKeyRing) { - // the constructor will take care of the public/secret part return new UncachedKeyRing((PGPKeyRing) obj); } else { throw new PgpGeneralException("Object not recognized as PGPKeyRing!"); @@ -128,4 +131,23 @@ public class UncachedKeyRing { aos.close(); } + public ArrayList getAvailableSubkeys() { + if(!isSecret()) { + throw new RuntimeException("Tried to find available subkeys from non-secret keys. " + + "This is a programming error and should never happen!"); + } + + ArrayList result = new ArrayList(); + // 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; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java deleted file mode 100644 index ca784fbde..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedSecretKeyRing.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.bcpg.S2K; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.util.IterableIterator; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; - -public class UncachedSecretKeyRing extends UncachedKeyRing { - - UncachedSecretKeyRing(PGPSecretKeyRing secretRing) { - super(secretRing); - } - - public ArrayList getAvailableSubkeys() { - ArrayList result = new ArrayList(); - // 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; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java index 624382165..99dc99436 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java @@ -3,6 +3,8 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPKeyRing; +import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSignature; @@ -12,6 +14,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProv 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.security.SignatureException; @@ -30,7 +33,17 @@ public class WrappedPublicKeyRing extends WrappedKeyRing { PGPPublicKeyRing getRing() { if(mRing == null) { - mRing = (PGPPublicKeyRing) PgpConversionHelper.BytesToPGPKeyRing(mPubKey); + PGPObjectFactory factory = new PGPObjectFactory(mPubKey); + 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 = (PGPPublicKeyRing) keyRing; } return mRing; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java index 656430969..91d4286f4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java @@ -1,7 +1,10 @@ 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.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; @@ -11,6 +14,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.util.IterableIterator; +import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; import java.security.NoSuchProviderException; @@ -23,7 +27,17 @@ public class WrappedSecretKeyRing extends WrappedKeyRing { public WrappedSecretKeyRing(byte[] blob, boolean isRevoked, int verified) { super(isRevoked, verified); - mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob); + 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() { @@ -77,7 +91,7 @@ public class WrappedSecretKeyRing extends WrappedKeyRing { } } - public UncachedSecretKeyRing changeSecretKeyPassphrase(String oldPassphrase, + public UncachedKeyRing changeSecretKeyPassphrase(String oldPassphrase, String newPassphrase) throws IOException, PGPException, NoSuchProviderException { @@ -96,7 +110,7 @@ public class WrappedSecretKeyRing extends WrappedKeyRing { new JcePBESecretKeyEncryptorBuilder(mRing.getSecretKey() .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray())); - return new UncachedSecretKeyRing(newKeyRing); + return new UncachedKeyRing(newKeyRing); } @@ -120,8 +134,8 @@ public class WrappedSecretKeyRing extends WrappedKeyRing { }); } - public UncachedSecretKeyRing getUncached() { - return new UncachedSecretKeyRing(mRing); + public UncachedKeyRing getUncached() { + return new UncachedKeyRing(mRing); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index ed8171587..ceaa93f9b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -268,7 +268,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { byte[] data = cursor.getBlob(0); try { UncachedKeyRing ring = UncachedKeyRing.decodeFromData(data); - providerHelper.saveKeyRing(ring); + providerHelper.savePublicKeyRing(ring); } catch(PgpGeneralException e) { Log.e(Constants.TAG, "Error decoding keyring blob!"); } @@ -292,7 +292,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { byte[] data = cursor.getBlob(0); try { UncachedKeyRing ring = UncachedKeyRing.decodeFromData(data); - providerHelper.saveKeyRing(ring); + providerHelper.savePublicKeyRing(ring); } catch(PgpGeneralException e) { Log.e(Constants.TAG, "Error decoding keyring blob!"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 2f6cded91..b651069e9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -621,7 +621,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RING_CERTS: // we replace here, keeping only the latest signature - // TODO this would be better handled in saveKeyRing directly! + // TODO this would be better handled in savePublicKeyRing directly! db.replaceOrThrow(Tables.CERTS, null, values); keyId = values.getAsLong(Certs.MASTER_KEY_ID); break; 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 b6f75e00d..55e8c77d1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -35,7 +35,6 @@ import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; -import org.sufficientlysecure.keychain.pgp.UncachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; @@ -151,7 +150,7 @@ public class ProviderHelper { if (data != null) { try { result.put(masterKeyId, - UncachedKeyRing.decodePubkeyFromData(data).getPublicKey()); + UncachedKeyRing.decodePublicFromData(data).getPublicKey()); } catch(PgpGeneralException e) { Log.e(Constants.TAG, "Error parsing keyring, skipping."); } catch(IOException e) { @@ -221,12 +220,12 @@ public class ProviderHelper { * Saves PGPPublicKeyRing with its keys and userIds in DB */ @SuppressWarnings("unchecked") - public void saveKeyRing(UncachedKeyRing keyRing) throws IOException { + public void savePublicKeyRing(UncachedKeyRing keyRing) throws IOException { UncachedPublicKey masterKey = keyRing.getPublicKey(); long masterKeyId = masterKey.getKeyId(); // IF there is a secret key, preserve it! - UncachedSecretKeyRing secretRing = null; + UncachedKeyRing secretRing = null; try { secretRing = getWrappedSecretKeyRing(masterKeyId).getUncached(); } catch (NotFoundException e) { @@ -343,7 +342,7 @@ public class ProviderHelper { // Save the saved keyring (if any) if (secretRing != null) { - saveKeyRing(secretRing); + saveSecretKeyRing(secretRing); } } @@ -373,7 +372,7 @@ public class ProviderHelper { * Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring * is already in the database! */ - public void saveKeyRing(UncachedSecretKeyRing keyRing) throws IOException { + public void saveSecretKeyRing(UncachedKeyRing keyRing) throws IOException { long masterKeyId = keyRing.getMasterKeyId(); { @@ -413,12 +412,12 @@ public class ProviderHelper { 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) + // delete secret keyring (so it isn't unnecessarily saved by public-savePublicKeyRing below) mContentResolver.delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null); // save public keyring - saveKeyRing(pubRing); - saveKeyRing(secRing); + savePublicKeyRing(pubRing); + savePublicKeyRing(secRing); } /** 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 69eab9d4e..2655e9aa0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -45,7 +45,6 @@ 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.UncachedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -514,10 +513,10 @@ public class KeychainIntentService extends IntentService if (!canSign) { setProgress(R.string.progress_building_key, 0, 100); WrappedSecretKeyRing keyRing = providerHelper.getWrappedSecretKeyRing(masterKeyId); - UncachedSecretKeyRing newKeyRing = + UncachedKeyRing newKeyRing = keyRing.changeSecretKeyPassphrase(oldPassphrase, newPassphrase); setProgress(R.string.progress_saving_key_ring, 50, 100); - providerHelper.saveKeyRing(newKeyRing); + providerHelper.saveSecretKeyRing(newKeyRing); setProgress(R.string.progress_done, 100, 100); } else { PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100)); @@ -533,7 +532,7 @@ public class KeychainIntentService extends IntentService UncachedKeyRing ring = keyOperations.buildNewSecretKey(saveParcel); //new Keyring // save the pair setProgress(R.string.progress_saving_key_ring, 90, 100); - providerHelper.saveKeyRing(ring); + providerHelper.savePublicKeyRing(ring); } setProgress(R.string.progress_done, 100, 100); @@ -795,7 +794,7 @@ public class KeychainIntentService extends IntentService // create PGPKeyRing object based on downloaded armored key UncachedKeyRing downloadedKey = - UncachedKeyRing.decodePubkeyFromData(downloadedKeyBytes); + UncachedKeyRing.decodePublicFromData(downloadedKeyBytes); // verify downloaded key by comparing fingerprints if (entry.getFingerprintHex() != null) { -- cgit v1.2.3 From e27048fe73eab25561cd53e64e96960afeb37aac Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 30 May 2014 17:11:54 +0200 Subject: wrapped-key-ring: move key data around in ParcelableKeyRing instead of ImportKeysListEntry --- .../keychain/keyimport/ImportKeysListEntry.java | 24 ----- .../keychain/keyimport/ParcelableKeyRing.java | 51 +++++++++++ .../keychain/pgp/PgpConversionHelper.java | 20 ---- .../keychain/pgp/PgpImportExport.java | 102 +++++---------------- .../keychain/service/KeychainIntentService.java | 54 +++-------- .../keychain/ui/ImportKeysActivity.java | 9 +- .../keychain/ui/ImportKeysListFragment.java | 23 ++++- .../keychain/ui/adapter/ImportKeysAdapter.java | 3 +- .../keychain/ui/adapter/ImportKeysListLoader.java | 16 ++-- 9 files changed, 119 insertions(+), 183 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java (limited to 'OpenKeychain/src/main/java') 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 0187fe52a..c43f72235 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -21,13 +21,10 @@ import android.content.Context; import android.os.Parcel; import android.os.Parcelable; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; -import org.sufficientlysecure.keychain.util.Log; -import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; @@ -50,8 +47,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable { private boolean mSelected; - private byte[] mBytes = new byte[]{}; - public int describeContents() { return 0; } @@ -69,8 +64,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable { dest.writeString(algorithm); dest.writeByte((byte) (secretKey ? 1 : 0)); dest.writeByte((byte) (mSelected ? 1 : 0)); - dest.writeInt(mBytes.length); - dest.writeByteArray(mBytes); dest.writeString(mExtraData); } @@ -89,8 +82,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable { vr.algorithm = source.readString(); vr.secretKey = source.readByte() == 1; vr.mSelected = source.readByte() == 1; - vr.mBytes = new byte[source.readInt()]; - source.readByteArray(vr.mBytes); vr.mExtraData = source.readString(); return vr; @@ -105,14 +96,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable { return keyIdHex; } - public byte[] getBytes() { - return mBytes; - } - - public void setBytes(byte[] bytes) { - this.mBytes = bytes; - } - public boolean isSelected() { return mSelected; } @@ -229,13 +212,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable { */ @SuppressWarnings("unchecked") public ImportKeysListEntry(Context context, UncachedKeyRing ring) { - // save actual key object into entry, used to import it later - try { - this.mBytes = ring.getEncoded(); - } catch (IOException e) { - Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e); - } - // selected is default this.mSelected = true; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java new file mode 100644 index 000000000..3d3b6339a --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java @@ -0,0 +1,51 @@ +package org.sufficientlysecure.keychain.keyimport; + +import android.os.Parcel; +import android.os.Parcelable; + +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; + +import java.io.IOException; + +/** This is a trivial wrapper around UncachedKeyRing which implements Parcelable. It exists + * for the sole purpose of keeping spongycastle and android imports in separate packages. + */ +public class ParcelableKeyRing implements Parcelable { + + final byte[] mBytes; + final String mExpectedFingerprint; + + public ParcelableKeyRing(byte[] bytes) { + mBytes = bytes; + mExpectedFingerprint = null; + } + public ParcelableKeyRing(byte[] bytes, String expectedFingerprint) { + mBytes = bytes; + mExpectedFingerprint = expectedFingerprint; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(mBytes); + dest.writeString(mExpectedFingerprint); + } + + public static final Creator CREATOR = new Creator() { + public ParcelableKeyRing createFromParcel(final Parcel source) { + return new ParcelableKeyRing(source.createByteArray()); + } + + public ParcelableKeyRing[] newArray(final int size) { + return new ParcelableKeyRing[size]; + } + }; + + + public int describeContents() { + return 0; + } + + public UncachedKeyRing getUncachedKeyRing() throws PgpGeneralException, IOException { + return UncachedKeyRing.decodeFromData(mBytes); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java index ea3c72fd0..591ccdc8e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java @@ -30,26 +30,6 @@ import java.util.Iterator; public class PgpConversionHelper { - /** - * Convert from byte[] to PGPKeyRing - * - * @param keysBytes - * @return - */ - public static PGPKeyRing BytesToPGPKeyRing(byte[] keysBytes) { - PGPObjectFactory factory = new PGPObjectFactory(keysBytes); - 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); - } - - return keyRing; - } - /** * Convert from byte[] to ArrayList * 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 91bb89995..1e58c188f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -24,20 +24,14 @@ import android.os.Environment; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; -import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException; import org.sufficientlysecure.keychain.util.Log; @@ -62,7 +56,6 @@ public class PgpImportExport { private ProviderHelper mProviderHelper; public static final int RETURN_OK = 0; - public static final int RETURN_ERROR = -1; public static final int RETURN_BAD = -2; public static final int RETURN_UPDATED = 1; @@ -133,7 +126,7 @@ public class PgpImportExport { /** * Imports keys from given data. If keyIds is given only those are imported */ - public Bundle importKeyRings(List entries) + public Bundle importKeyRings(List entries) throws PgpGeneralException, PGPException, IOException { Bundle returnData = new Bundle(); @@ -144,55 +137,26 @@ public class PgpImportExport { int badKeys = 0; int position = 0; - try { - for (ImportKeysListEntry entry : entries) { - Object obj = PgpConversionHelper.BytesToPGPKeyRing(entry.getBytes()); - - if (obj instanceof PGPKeyRing) { - PGPKeyRing keyring = (PGPKeyRing) obj; - int status; - // TODO Better try to get this one from the db first! - if(keyring instanceof PGPSecretKeyRing) { - PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring; - // TODO: preserve certifications - // (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?) - PGPPublicKeyRing newPubRing = null; - for (PGPPublicKey key : new IterableIterator( - secretKeyRing.getPublicKeys())) { - if (newPubRing == null) { - newPubRing = new PGPPublicKeyRing(key.getEncoded(), - new JcaKeyFingerprintCalculator()); - } - newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key); - } - status = storeKeyRingInCache(new UncachedKeyRing(newPubRing), - new UncachedKeyRing(secretKeyRing)); - } else { - status = storeKeyRingInCache(new UncachedKeyRing(keyring)); - } - - if (status == RETURN_ERROR) { - throw new PgpGeneralException( - mContext.getString(R.string.error_saving_keys)); - } - - // update the counts to display to the user at the end - if (status == RETURN_UPDATED) { - ++oldKeys; - } else if (status == RETURN_OK) { - ++newKeys; - } else if (status == RETURN_BAD) { - ++badKeys; - } - } else { - Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); - } - - position++; - updateProgress(position / entries.size() * 100, 100); + for (ParcelableKeyRing entry : entries) { + try { + UncachedKeyRing key = entry.getUncachedKeyRing(); + + mProviderHelper.savePublicKeyRing(key); + /*switch(status) { + case RETURN_UPDATED: oldKeys++; break; + case RETURN_OK: newKeys++; break; + case RETURN_BAD: badKeys++; break; + }*/ + // TODO proper import feedback + newKeys += 1; + + } catch (PgpGeneralException e) { + Log.e(Constants.TAG, "Encountered bad key on import!", e); + ++badKeys; } - } catch (Exception e) { - Log.e(Constants.TAG, "Exception on parsing key file!", e); + // update progress + position++; + updateProgress(position / entries.size() * 100, 100); } returnData.putInt(KeychainIntentService.RESULT_IMPORT_ADDED, newKeys); @@ -280,28 +244,4 @@ public class PgpImportExport { return returnData; } - public int storeKeyRingInCache(UncachedKeyRing ring) { - return storeKeyRingInCache(ring, null); - } - - @SuppressWarnings("unchecked") - public int storeKeyRingInCache(UncachedKeyRing ring, UncachedKeyRing secretRing) { - int status; - try { - UncachedKeyRing secretKeyRing = null; - // see what type we have. we can either have a secret + public keyring, or just public - if (secretKeyRing != null) { - mProviderHelper.saveKeyRing(ring, secretRing); - status = RETURN_OK; - } else { - mProviderHelper.savePublicKeyRing(ring); - status = RETURN_OK; - } - } catch (IOException e) { - status = RETURN_ERROR; - } - - return status; - } - } 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 2655e9aa0..c1e7dddb5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.WrappedSecretKey; @@ -40,7 +41,6 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpImportExport; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.Progressable; @@ -56,7 +56,6 @@ import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; -import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -645,7 +644,7 @@ public class KeychainIntentService extends IntentService } } else if (ACTION_IMPORT_KEYRING.equals(action)) { try { - List entries = data.getParcelableArrayList(IMPORT_KEY_LIST); + List entries = data.getParcelableArrayList(IMPORT_KEY_LIST); PgpImportExport pgpImportExport = new PgpImportExport(this, this); Bundle resultData = pgpImportExport.importKeyRings(entries); @@ -739,32 +738,21 @@ public class KeychainIntentService extends IntentService try { KeybaseKeyserver server = new KeybaseKeyserver(); + ArrayList keyRings = new ArrayList(entries.size()); for (ImportKeysListEntry entry : entries) { // the keybase handle is in userId(1) String keybaseId = entry.getExtraData(); byte[] downloadedKeyBytes = server.get(keybaseId).getBytes(); - // create PGPKeyRing object based on downloaded armored key - UncachedKeyRing downloadedKey = null; - BufferedInputStream bufferedInput = - new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes)); - if (bufferedInput.available() > 0) { - List rings = UncachedKeyRing.fromStream(bufferedInput); - if(rings.isEmpty()) { - throw new PgpGeneralException("No keys in result!"); - } - downloadedKey = rings.get(0); - } - // save key bytes in entry object for doing the // actual import afterwards - entry.setBytes(downloadedKey.getEncoded()); + keyRings.add(new ParcelableKeyRing(downloadedKeyBytes)); } Intent importIntent = new Intent(this, KeychainIntentService.class); importIntent.setAction(ACTION_IMPORT_KEYRING); Bundle importData = new Bundle(); - importData.putParcelableArrayList(IMPORT_KEY_LIST, entries); + importData.putParcelableArrayList(IMPORT_KEY_LIST, keyRings); importIntent.putExtra(EXTRA_DATA, importData); importIntent.putExtra(EXTRA_MESSENGER, mMessenger); @@ -778,11 +766,12 @@ public class KeychainIntentService extends IntentService } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action)) { try { ArrayList entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST); - String keyServer = data.getString(DOWNLOAD_KEY_SERVER); // this downloads the keys and places them into the ImportKeysListEntry entries + String keyServer = data.getString(DOWNLOAD_KEY_SERVER); HkpKeyserver server = new HkpKeyserver(keyServer); + ArrayList keyRings = new ArrayList(entries.size()); for (ImportKeysListEntry entry : entries) { // if available use complete fingerprint for get request byte[] downloadedKeyBytes; @@ -792,32 +781,15 @@ public class KeychainIntentService extends IntentService downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); } - // create PGPKeyRing object based on downloaded armored key - UncachedKeyRing downloadedKey = - UncachedKeyRing.decodePublicFromData(downloadedKeyBytes); - - // verify downloaded key by comparing fingerprints - if (entry.getFingerprintHex() != null) { - String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex( - downloadedKey.getFingerprint()); - if (downloadedKeyFp.equals(entry.getFingerprintHex())) { - Log.d(Constants.TAG, "fingerprint of downloaded key is the same as " + - "the requested fingerprint!"); - } else { - throw new PgpGeneralException("fingerprint of downloaded key is " + - "NOT the same as the requested fingerprint!"); - } - } - // save key bytes in entry object for doing the // actual import afterwards - entry.setBytes(downloadedKeyBytes); + keyRings.add(new ParcelableKeyRing(downloadedKeyBytes, entry.getFingerprintHex())); } Intent importIntent = new Intent(this, KeychainIntentService.class); importIntent.setAction(ACTION_IMPORT_KEYRING); Bundle importData = new Bundle(); - importData.putParcelableArrayList(IMPORT_KEY_LIST, entries); + importData.putParcelableArrayList(IMPORT_KEY_LIST, keyRings); importIntent.putExtra(EXTRA_DATA, importData); importIntent.putExtra(EXTRA_MESSENGER, mMessenger); @@ -853,13 +825,9 @@ public class KeychainIntentService extends IntentService UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds); // store the signed key in our local cache - PgpImportExport pgpImportExport = new PgpImportExport(this, null); - int retval = pgpImportExport.storeKeyRingInCache(newRing); - if (retval != PgpImportExport.RETURN_OK && retval != PgpImportExport.RETURN_UPDATED) { - throw new PgpGeneralException("Failed to store signed key in local cache"); - } - + providerHelper.savePublicKeyRing(newRing); sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); + } catch (Exception e) { sendErrorToHandler(e); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 35076287b..d33d450f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -42,6 +42,7 @@ import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; @@ -415,8 +416,8 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O // fill values for this action Bundle data = new Bundle(); - // get selected key entries - ArrayList selectedEntries = mListFragment.getSelectedData(); + // get DATA from selected key entries + ArrayList selectedEntries = mListFragment.getSelectedData(); data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, selectedEntries); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -442,7 +443,7 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O data.putString(KeychainIntentService.DOWNLOAD_KEY_SERVER, mListFragment.getKeyServer()); // get selected key entries - ArrayList selectedEntries = mListFragment.getSelectedData(); + ArrayList selectedEntries = mListFragment.getSelectedEntries(); data.putParcelableArrayList(KeychainIntentService.DOWNLOAD_KEY_LIST, selectedEntries); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -466,7 +467,7 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O Bundle data = new Bundle(); // get selected key entries - ArrayList selectedEntries = mListFragment.getSelectedData(); + ArrayList selectedEntries = mListFragment.getSelectedEntries(); data.putParcelableArrayList(KeychainIntentService.DOWNLOAD_KEY_LIST, selectedEntries); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index e93d717e1..8f0a715bf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -23,6 +23,7 @@ import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; +import android.support.v4.util.LongSparseArray; import android.view.View; import android.widget.ListView; @@ -31,6 +32,7 @@ import com.devspark.appmsg.AppMsg; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; @@ -67,6 +69,8 @@ public class ImportKeysListFragment extends ListFragment implements private static final int LOADER_ID_SERVER_QUERY = 1; private static final int LOADER_ID_KEYBASE = 2; + private LongSparseArray mCachedKeyData; + public byte[] getKeyBytes() { return mKeyBytes; } @@ -91,8 +95,16 @@ public class ImportKeysListFragment extends ListFragment implements return mAdapter.getData(); } - public ArrayList getSelectedData() { - return mAdapter.getSelectedData(); + public ArrayList getSelectedData() { + ArrayList result = new ArrayList(); + for(ImportKeysListEntry entry : getSelectedEntries()) { + result.add(mCachedKeyData.get(entry.getKeyId())); + } + return result; + } + + public ArrayList getSelectedEntries() { + return mAdapter.getSelectedEntries(); } /** @@ -120,8 +132,7 @@ public class ImportKeysListFragment extends ListFragment implements mActivity = getActivity(); - // Give some text to display if there is no data. In a real - // application this would come from a resource. + // Give some text to display if there is no data. setEmptyText(mActivity.getString(R.string.error_nothing_import)); // Create an empty adapter we will use to display the loaded data. @@ -252,11 +263,15 @@ public class ImportKeysListFragment extends ListFragment implements Exception error = data.getError(); + // free old cached key data + mCachedKeyData = null; + switch (loader.getId()) { case LOADER_ID_BYTES: if (error == null) { // No error + mCachedKeyData = ((ImportKeysListLoader) loader).getParcelableRings(); } else if (error instanceof ImportKeysListLoader.FileHasNoContent) { AppMsg.makeText(getActivity(), R.string.error_import_file_no_content, AppMsg.STYLE_ALERT).show(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 9573efdfe..114c6afae 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -32,6 +32,7 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.util.Highlighter; @@ -83,7 +84,7 @@ public class ImportKeysAdapter extends ArrayAdapter { return mData; } - public ArrayList getSelectedData() { + public ArrayList getSelectedEntries() { ArrayList selectedData = new ArrayList(); for (ImportKeysListEntry entry : mData) { if (entry.isSelected()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 46b50ac98..03a82696d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -19,9 +19,11 @@ package org.sufficientlysecure.keychain.ui.adapter; import android.content.Context; import android.support.v4.content.AsyncTaskLoader; +import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; @@ -54,6 +56,7 @@ public class ImportKeysListLoader final InputData mInputData; ArrayList mData = new ArrayList(); + LongSparseArray mParcelableRings = new LongSparseArray(); AsyncTaskResultWrapper> mEntryListWrapper; public ImportKeysListLoader(Context context, InputData inputData) { @@ -105,6 +108,10 @@ public class ImportKeysListLoader super.deliverResult(data); } + public LongSparseArray getParcelableRings() { + return mParcelableRings; + } + /** * Reads all PGPKeyRing objects from input * @@ -129,7 +136,9 @@ public class ImportKeysListLoader // todo deal with non-keyring objects? List rings = UncachedKeyRing.fromStream(bufferedInput); for(UncachedKeyRing key : rings) { - addToData(key); + ImportKeysListEntry item = new ImportKeysListEntry(getContext(), key); + mData.add(item); + mParcelableRings.put(key.getMasterKeyId(), new ParcelableKeyRing(key.getEncoded())); isEmpty = false; } } @@ -145,9 +154,4 @@ public class ImportKeysListLoader } } - private void addToData(UncachedKeyRing keyring) { - ImportKeysListEntry item = new ImportKeysListEntry(getContext(), keyring); - mData.add(item); - } - } -- cgit v1.2.3 From d891f753393d26bbf3c1f766deddf71f6c9ce5ae Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 31 May 2014 12:58:35 +0200 Subject: make everything work again --- .../sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 5 +++-- .../keychain/provider/ProviderHelper.java | 16 ++++++++++++++-- .../keychain/service/KeychainIntentService.java | 9 +++++---- 3 files changed, 22 insertions(+), 8 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 3e296edb9..44fc4c8c9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -197,7 +197,7 @@ public class PgpKeyOperation { } } - public UncachedKeyRing buildNewSecretKey( + public Pair buildNewSecretKey( OldSaveKeyringParcel saveParcel) throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { @@ -336,8 +336,9 @@ public class PgpKeyOperation { } PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing(); + PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing(); - return new UncachedKeyRing(secretKeyRing); + return new Pair(new UncachedKeyRing(secretKeyRing), new UncachedKeyRing(publicKeyRing)); } 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 55e8c77d1..043c40b25 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -187,7 +187,6 @@ public class ProviderHelper { return (WrappedSecretKeyRing) getWrappedKeyRing(queryUri, true); } - private KeyRing getWrappedKeyRing(Uri queryUri, boolean secret) throws NotFoundException { Cursor cursor = mContentResolver.query(queryUri, new String[]{ @@ -203,6 +202,9 @@ public class ProviderHelper { boolean hasAnySecret = cursor.getInt(0) > 0; int verified = cursor.getInt(1); byte[] blob = cursor.getBlob(2); + if(secret &! hasAnySecret) { + throw new NotFoundException("Secret key not available!"); + } return secret ? new WrappedSecretKeyRing(blob, hasAnySecret, verified) : new WrappedPublicKeyRing(blob, hasAnySecret, verified); @@ -221,6 +223,11 @@ public class ProviderHelper { */ @SuppressWarnings("unchecked") public void savePublicKeyRing(UncachedKeyRing keyRing) throws IOException { + if (keyRing.isSecret()) { + throw new RuntimeException("Tried to save secret keyring as public! " + + "This is a bug, please file a bug report."); + } + UncachedPublicKey masterKey = keyRing.getPublicKey(); long masterKeyId = masterKey.getKeyId(); @@ -373,6 +380,11 @@ public class ProviderHelper { * is already in the database! */ public void saveSecretKeyRing(UncachedKeyRing keyRing) throws IOException { + if (!keyRing.isSecret()) { + throw new RuntimeException("Tried to save publkc keyring as secret! " + + "This is a bug, please file a bug report."); + } + long masterKeyId = keyRing.getMasterKeyId(); { @@ -417,7 +429,7 @@ public class ProviderHelper { // save public keyring savePublicKeyRing(pubRing); - savePublicKeyRing(secRing); + saveSecretKeyRing(secRing); } /** 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 c1e7dddb5..38f40db29 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -520,18 +520,19 @@ public class KeychainIntentService extends IntentService } else { PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100)); try { - WrappedSecretKeyRing privkey = providerHelper.getWrappedSecretKeyRing(masterKeyId); + WrappedSecretKeyRing seckey = providerHelper.getWrappedSecretKeyRing(masterKeyId); WrappedPublicKeyRing pubkey = providerHelper.getWrappedPublicKeyRing(masterKeyId); PgpKeyOperation.Pair pair = - keyOperations.buildSecretKey(privkey, pubkey, saveParcel); // edit existing + keyOperations.buildSecretKey(seckey, pubkey, saveParcel); // edit existing setProgress(R.string.progress_saving_key_ring, 90, 100); providerHelper.saveKeyRing(pair.first, pair.second); } catch (ProviderHelper.NotFoundException e) { - UncachedKeyRing ring = keyOperations.buildNewSecretKey(saveParcel); //new Keyring + PgpKeyOperation.Pair pair = + keyOperations.buildNewSecretKey(saveParcel); //new Keyring // save the pair setProgress(R.string.progress_saving_key_ring, 90, 100); - providerHelper.savePublicKeyRing(ring); + providerHelper.saveKeyRing(pair.first, pair.second); } setProgress(R.string.progress_done, 100, 100); -- cgit v1.2.3 From 58edc0af674f273578a76febd9dfaad95e3380f9 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 31 May 2014 13:10:41 +0200 Subject: wrapped-key-ring: add documentation --- .../org/sufficientlysecure/keychain/pgp/KeyRing.java | 11 +++++++++++ .../keychain/pgp/UncachedKeyRing.java | 18 ++++++++++++++++++ .../keychain/pgp/WrappedKeyRing.java | 9 +++++++++ .../keychain/pgp/WrappedPublicKey.java | 17 ++++++++++------- .../keychain/pgp/WrappedSecretKey.java | 11 +++++++++++ .../keychain/pgp/WrappedSignature.java | 8 ++++++++ .../keychain/provider/CachedPublicKeyRing.java | 16 ++++++++++++++++ 7 files changed, 83 insertions(+), 7 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 cfbad89b7..dc0c722b9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java @@ -2,6 +2,17 @@ package org.sufficientlysecure.keychain.pgp; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +/** An abstract KeyRing. + * + * This is an abstract class for all KeyRing constructs. It serves as a common + * denominator of available information, two implementations wrapping the same + * keyring should in all cases agree on the output of all methods described + * here. + * + * @see org.sufficientlysecure.keychain.pgp.WrappedKeyRing + * @see org.sufficientlysecure.keychain.provider.CachedPublicKeyRing + * + */ public abstract class KeyRing { abstract public long getMasterKeyId() throws PgpGeneralException; 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 e17d07390..02e5411ca 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -23,6 +23,23 @@ import java.util.Iterator; import java.util.List; import java.util.Vector; +/** Wrapper around PGPKeyRing class, to be constructed from bytes. + * + * This class and its relatives UncachedPublicKey and UncachedSecretKey are + * used to move around pgp key rings in non crypto related (UI, mostly) code. + * It should be used for simple inspection only until it saved in the database, + * all actual crypto operations should work with WrappedKeyRings exclusively. + * + * This class is also special in that it can hold either the PGPPublicKeyRing + * or PGPSecretKeyRing derivate of the PGPKeyRing class, since these are + * 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 org.sufficientlysecure.keychain.pgp.UncachedPublicKey + * @see org.sufficientlysecure.keychain.pgp.UncachedSecretKey + * + */ public class UncachedKeyRing { final PGPKeyRing mRing; @@ -62,6 +79,7 @@ public class UncachedKeyRing { }; } + /** Returns the dynamic (though final) property if this is a secret keyring or not. */ public boolean isSecret() { return mIsSecret; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java index 6e7b2a49e..2b6049894 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java @@ -8,6 +8,15 @@ 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; 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 32c6910be..69a4fbdee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKey.java @@ -1,16 +1,19 @@ package org.sufficientlysecure.keychain.pgp; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPOnePassSignature; import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; -import java.security.SignatureException; - +/** 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 diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java index a03e10098..ef8044a9b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java @@ -26,6 +26,17 @@ 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; 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 9f26439d2..1b7a5e8ba 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -17,6 +17,14 @@ import java.io.IOException; import java.security.SignatureException; import java.util.Date; +/** OpenKeychain wrapper around PGPSignature objects. + * + * This is a mostly simple wrapper around a single bouncycastle PGPSignature + * object. It exposes high level getters for all relevant information, methods + * for verification of various signatures (uid binding, subkey binding, generic + * bytes), and a static method for construction from bytes. + * + */ public class WrappedSignature { public static final int DEFAULT_CERTIFICATION = PGPSignature.DEFAULT_CERTIFICATION; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java index ed1988336..48d40430a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java @@ -7,6 +7,22 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.util.Log; +/** This implementation of KeyRing provides a cached view of PublicKeyRing + * objects based on database queries exclusively. + * + * This class should be used where only few points of data but no actual + * cryptographic operations are required about a PublicKeyRing which is already + * in the database. This happens commonly in UI code, where parsing of a PGP + * key for examination would be a very expensive operation. + * + * Each getter method is implemented using a more or less expensive database + * query, while object construction is (almost) free. A common pattern is + * mProviderHelper.getCachedKeyRing(uri).getterMethod() + * + * TODO Ensure that the values returned here always match the ones returned by + * the parsed KeyRing! + * + */ public class CachedPublicKeyRing extends KeyRing { final ProviderHelper mProviderHelper; -- cgit v1.2.3