diff options
Diffstat (limited to 'OpenKeychain')
7 files changed, 118 insertions, 125 deletions
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<String> userIds) + throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException, + PGPException, SignatureException { + + if(mPrivateKey == null) { + throw new PrivateKeyNotUnlockedException(); + } + + // create a signatureGenerator from the supplied masterKeyId and passphrase + PGPSignatureGenerator signatureGenerator; + { + // TODO: SHA256 fixed? + JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( + 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<String>(userIds.iterator())) { + PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); + publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); + } + + PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey); + + return new UncachedKeyRing(ring); + } + static class PrivateKeyNotUnlockedException extends RuntimeException { // this exception is a programming error which happens when an operation which requires // the private key is called without a previous call to unlock() 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<PGPPublicKey>( + secretKeyRing.getPublicKeys())) { + if (newPubRing == null) { + newPubRing = new PGPPublicKeyRing(key.getEncoded(), + new JcaKeyFingerprintCalculator()); + } + newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key); + } + status = storeKeyRingInCache(new UncachedKeyRing(newPubRing ,secretKeyRing)); + } else { + status = storeKeyRingInCache(new UncachedKeyRing((PGPPublicKeyRing) keyring)); + } if (status == RETURN_ERROR) { throw new PgpGeneralException( @@ -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<PGPSecretKey>( - secretKeyRing.getSecretKeys())) { - if (!testSecretKey.isMasterKey()) { - if (testSecretKey.isPrivateKeyEmpty()) { - // this is bad, something is very wrong... - save = false; - status = RETURN_BAD; - } - } - } - - if (save) { - // TODO: preserve certifications - // (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?) - PGPPublicKeyRing newPubRing = null; - for (PGPPublicKey key : new IterableIterator<PGPPublicKey>( - secretKeyRing.getPublicKeys())) { - if (newPubRing == null) { - newPubRing = new PGPPublicKeyRing(key.getEncoded(), - new JcaKeyFingerprintCalculator()); - } - newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key); - } - if (newPubRing != null) { - mProviderHelper.saveKeyRing(newPubRing); - } - mProviderHelper.saveKeyRing(secretKeyRing); - status = RETURN_OK; - } - } else if (keyring instanceof PGPPublicKeyRing) { - PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring; + PGPSecretKeyRing secretKeyRing = keyring.getSecretRing(); + PGPPublicKeyRing publicKeyRing = keyring.getPublicRing(); + // see what type we have. we can either have a secret + public keyring, or just public + if (secretKeyRing != null) { + mProviderHelper.saveKeyRing(publicKeyRing, secretKeyRing); + status = RETURN_OK; + } else { mProviderHelper.saveKeyRing(publicKeyRing); status = RETURN_OK; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/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 @@ -691,59 +691,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<String> userIds, String passphrase) - throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException, - PGPException, SignatureException { - - // create a signatureGenerator from the supplied masterKeyId and passphrase - PGPSignatureGenerator signatureGenerator; - { - - if (certificationKey == null) { - throw new PgpGeneralMsgIdException(R.string.error_no_signature_key); - } - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); - PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor); - if (signaturePrivateKey == null) { - throw new PgpGeneralMsgIdException(R.string.error_could_not_extract_private_key); - } - - // TODO: SHA256 fixed? - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - certificationKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, signaturePrivateKey); - } - - { // supply signatureGenerator with a SubpacketVector - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - PGPSignatureSubpacketVector packetVector = spGen.generate(); - signatureGenerator.setHashedSubpackets(packetVector); - } - - // fetch public key ring, add the certification and return it - for (String userId : new IterableIterator<String>(userIds.iterator())) { - PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); - publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); - } - - return publicKey; - } - - /** * Simple static subclass that stores two values. * <p/> * This is only used to return a pair of values in one function above. We specifically don't use 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<ImportKeysListEntry> 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"); } |