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 ++---- 9 files changed, 621 insertions(+), 319 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/org/sufficientlysecure/keychain/pgp') 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(); } } -- cgit v1.2.3