diff options
author | Vincent Breitmoser <valodim@mugenguild.com> | 2014-03-22 13:04:31 +0100 |
---|---|---|
committer | Vincent Breitmoser <valodim@mugenguild.com> | 2014-04-01 16:12:57 +0200 |
commit | 6f36b72eee8ed2a0baa768e696bbb6e9632ed795 (patch) | |
tree | a37689ea7c0f54b8f32f0a4e23fb88401eb871cb /OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | |
parent | ebb7f559216fd2f4d82f824e4fa7ceddbfa7cd1c (diff) | |
download | open-keychain-6f36b72eee8ed2a0baa768e696bbb6e9632ed795.tar.gz open-keychain-6f36b72eee8ed2a0baa768e696bbb6e9632ed795.tar.bz2 open-keychain-6f36b72eee8ed2a0baa768e696bbb6e9632ed795.zip |
PgpKeyOperation: factor out all android dependencies
Conflicts:
OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java')
-rw-r--r-- | OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 216 |
1 files changed, 110 insertions, 106 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 592bdec73..520189448 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -17,20 +17,6 @@ package org.sufficientlysecure.keychain.pgp; -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SecureRandom; -import java.security.SignatureException; -import java.util.ArrayList; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Iterator; -import java.util.TimeZone; -import android.content.Context; import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; @@ -46,18 +32,11 @@ import org.spongycastle.openpgp.operator.jcajce.*; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.util.Primes; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; - -import android.content.Context; -import android.util.Pair; import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Primes; -import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import java.io.IOException; import java.math.BigInteger; @@ -69,9 +48,17 @@ import java.util.Iterator; import java.util.List; import java.util.TimeZone; +/** This class is the single place where ALL operations that actually modify a PGP public or secret + * key take place. + * + * Note that no android specific stuff should be done here, ie no imports from com.android. + * + * All operations support progress reporting to a ProgressDialogUpdater passed on initialization. + * This indicator may be null. + * + */ public class PgpKeyOperation { - private final Context mContext; - private final ProgressDialogUpdater mProgress; + private ProgressDialogUpdater mProgress; private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{ SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192, @@ -83,9 +70,8 @@ public class PgpKeyOperation { CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2, CompressionAlgorithmTags.ZIP}; - public PgpKeyOperation(Context context, ProgressDialogUpdater progress) { + public PgpKeyOperation(ProgressDialogUpdater progress) { super(); - this.mContext = context; this.mProgress = progress; } @@ -101,13 +87,29 @@ public class PgpKeyOperation { } } + /** + * Creates new secret key. + * + * @param algorithmChoice + * @param keySize + * @param passphrase + * @param isMasterKey + * @return A newly created PGPSecretKey + * @throws NoSuchAlgorithmException + * @throws PGPException + * @throws NoSuchProviderException + * @throws PgpGeneralMsgIdException + * @throws InvalidAlgorithmParameterException + */ + + // TODO: key flags? public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase, boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, - PgpGeneralException, InvalidAlgorithmParameterException { + PgpGeneralMsgIdException, InvalidAlgorithmParameterException { if (keySize < 512) { - throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit)); + throw new PgpGeneralMsgIdException(R.string.error_key_size_minimum512bit); } if (passphrase == null) { @@ -127,8 +129,7 @@ public class PgpKeyOperation { case Id.choice.algorithm.elgamal: { if (isMasterKey) { - throw new PgpGeneralException( - mContext.getString(R.string.error_master_key_must_not_be_el_gamal)); + throw new PgpGeneralMsgIdException(R.string.error_master_key_must_not_be_el_gamal); } keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME); BigInteger p = Primes.getBestPrime(keySize); @@ -150,8 +151,7 @@ public class PgpKeyOperation { } default: { - throw new PgpGeneralException( - mContext.getString(R.string.error_unknown_algorithm_choice)); + throw new PgpGeneralMsgIdException(R.string.error_unknown_algorithm_choice); } } @@ -171,8 +171,9 @@ public class PgpKeyOperation { sha1Calc, isMasterKey, keyEncryptor); } - public void changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase, - String newPassPhrase) throws IOException, PGPException { + public PGPSecretKeyRing changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase, + String newPassPhrase) throws IOException, PGPException, + NoSuchProviderException { updateProgress(R.string.progress_building_key, 0, 100); if (oldPassPhrase == null) { @@ -190,16 +191,16 @@ public class PgpKeyOperation { new JcePBESecretKeyEncryptorBuilder(keyRing.getSecretKey() .getKeyEncryptionAlgorithm()).build(newPassPhrase.toCharArray())); - updateProgress(R.string.progress_saving_key_ring, 50, 100); - - ProviderHelper.saveKeyRing(mContext, newKeyRing); - - updateProgress(R.string.progress_done, 100, 100); + return newKeyRing; } - private void buildNewSecretKey(ArrayList<String> userIds, ArrayList<PGPSecretKey> keys, ArrayList<GregorianCalendar> keysExpiryDates, ArrayList<Integer> keysUsages, String newPassPhrase, String oldPassPhrase) throws PgpGeneralException, - PGPException, SignatureException, IOException { + private Pair<PGPSecretKeyRing,PGPPublicKeyRing> buildNewSecretKey( + ArrayList<String> userIds, ArrayList<PGPSecretKey> keys, + ArrayList<GregorianCalendar> keysExpiryDates, + ArrayList<Integer> keysUsages, + String newPassPhrase, String oldPassPhrase) + throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { int usageId = keysUsages.get(0); boolean canSign; @@ -210,8 +211,6 @@ public class PgpKeyOperation { // this removes all userIds and certifications previously attached to the masterPublicKey PGPPublicKey masterPublicKey = masterKey.getPublicKey(); - PGPSecretKeyRing mKR = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, masterKey.getKeyID()); - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassPhrase.toCharArray()); PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor); @@ -249,7 +248,7 @@ public class PgpKeyOperation { //here we purposefully ignore partial days in each date - long type has no fractional part! long numDays = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000); if (numDays <= 0) - throw new PgpGeneralException(mContext.getString(R.string.error_expiry_must_come_after_creation)); + throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); } else { hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding, @@ -319,9 +318,11 @@ public class PgpKeyOperation { GregorianCalendar expiryDate = keysExpiryDates.get(i); //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 = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000); - if (numDays <= 0) - throw new PgpGeneralException(mContext.getString(R.string.error_expiry_must_come_after_creation)); + long numDays = + (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000); + if (numDays <= 0) { + throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); + } hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); } else { hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding, @@ -334,23 +335,18 @@ public class PgpKeyOperation { PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing(); PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing(); - updateProgress(R.string.progress_saving_key_ring, 90, 100); - - ProviderHelper.saveKeyRing(mContext, secretKeyRing); - ProviderHelper.saveKeyRing(mContext, publicKeyRing); + return new Pair<PGPSecretKeyRing,PGPPublicKeyRing>(secretKeyRing, publicKeyRing); - updateProgress(R.string.progress_done, 100, 100); } - public void buildSecretKey (SaveKeyringParcel saveParcel)throws PgpGeneralException, - PGPException, SignatureException, IOException { + public Pair<PGPSecretKeyRing,PGPPublicKeyRing> buildSecretKey (PGPSecretKeyRing mKR, + PGPPublicKeyRing pKR, + SaveKeyringParcel saveParcel) + throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { updateProgress(R.string.progress_building_key, 0, 100); PGPSecretKey masterKey = saveParcel.keys.get(0); - PGPSecretKeyRing mKR = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, masterKey.getKeyID()); - PGPPublicKeyRing pKR = ProviderHelper.getPGPPublicKeyRingByKeyId(mContext, masterKey.getKeyID()); - if (saveParcel.oldPassPhrase == null) { saveParcel.oldPassPhrase = ""; } @@ -359,9 +355,8 @@ public class PgpKeyOperation { } if (mKR == null) { - buildNewSecretKey(saveParcel.userIDs, saveParcel.keys, saveParcel.keysExpiryDates, + return buildNewSecretKey(saveParcel.userIDs, saveParcel.keys, saveParcel.keysExpiryDates, saveParcel.keysUsages, saveParcel.newPassPhrase, saveParcel.oldPassPhrase); //new Keyring - return; } /* @@ -430,7 +425,7 @@ public class PgpKeyOperation { //here we purposefully ignore partial days in each date - long type has no fractional part! long numDays = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000); if (numDays <= 0) - throw new PgpGeneralException(mContext.getString(R.string.error_expiry_must_come_after_creation)); + throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); } else { hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding, @@ -592,7 +587,7 @@ public class PgpKeyOperation { //here we purposefully ignore partial days in each date - long type has no fractional part! long numDays = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000); if (numDays <= 0) - throw new PgpGeneralException(mContext.getString(R.string.error_expiry_must_come_after_creation)); + throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); } else { hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding, @@ -637,7 +632,6 @@ public class PgpKeyOperation { //update the passphrase mKR = PGPSecretKeyRing.copyWithNewPassword(mKR, keyDecryptor, keyEncryptorNew); - updateProgress(R.string.progress_saving_key_ring, 90, 100); /* additional handy debug info @@ -660,62 +654,72 @@ public class PgpKeyOperation { */ + return new Pair<PGPSecretKeyRing,PGPPublicKeyRing>(mKR, pKR); - ProviderHelper.saveKeyRing(mContext, mKR); - ProviderHelper.saveKeyRing(mContext, pKR); - - updateProgress(R.string.progress_done, 100, 100); } - public PGPPublicKeyRing certifyKey(long masterKeyId, long pubKeyId, List<String> userIds, String passphrase) - throws PgpGeneralException, NoSuchAlgorithmException, NoSuchProviderException, + /** + * 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 { - if (passphrase == null) { - throw new PgpGeneralException("Unable to obtain passphrase"); - } else { - // create a signatureGenerator from the supplied masterKeyId and passphrase - PGPSignatureGenerator signatureGenerator; { + // create a signatureGenerator from the supplied masterKeyId and passphrase + PGPSignatureGenerator signatureGenerator; { - PGPSecretKey certificationKey = PgpKeyHelper.getCertificationKey(mContext, masterKeyId); - if (certificationKey == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed)); - } + if (certificationKey == null) { + throw new PgpGeneralMsgIdException(R.string.error_signature_failed); + } - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); - PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor); - if (signaturePrivateKey == null) { - throw new PgpGeneralException( - mContext.getString(R.string.error_could_not_extract_private_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); + // 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); - } + 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); - } + { // 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 - PGPPublicKeyRing pubring = ProviderHelper - .getPGPPublicKeyRingByKeyId(mContext, pubKeyId); - PGPPublicKey signedKey = pubring.getPublicKey(pubKeyId); - for(String userId : new IterableIterator<String>(userIds.iterator())) { - PGPSignature sig = signatureGenerator.generateCertification(userId, signedKey); - signedKey = PGPPublicKey.addCertification(signedKey, userId, sig); - } - pubring = PGPPublicKeyRing.insertPublicKey(pubring, signedKey); + // 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; + } - return pubring; + /** Simple static subclass that stores two values. + * + * This is only used to return a pair of values in one function above. We specifically don't use + * com.android.Pair to keep this class free from android dependencies. + */ + public static class Pair<K, V> { + public final K first; + public final V second; + public Pair(K first, V second) { + this.first = first; + this.second = second; } } } |