From 034deaacba5cdccf422fbba26d6244c0a4cf2554 Mon Sep 17 00:00:00 2001 From: Ashley Hughes Date: Fri, 21 Feb 2014 15:01:59 +0000 Subject: initial split into two functions --- .../keychain/pgp/PgpKeyOperation.java | 178 ++++++++++++++++++--- 1 file changed, 154 insertions(+), 24 deletions(-) (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain') 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 c57718540..6055aebfc 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 @@ -198,12 +198,158 @@ public class PgpKeyOperation { } - public void buildSecretKey(ArrayList userIds, ArrayList OriginalIDs, ArrayList deletedIDs, ArrayList keys, boolean[] modded_keys, ArrayList deleted_keys, ArrayList keysExpiryDates, ArrayList keysUsages, String newPassPhrase, String oldPassPhrase) throws PgpGeneralException, + private void buildNewSecretKey(ArrayList userIds, ArrayList keys, ArrayList keysExpiryDates, ArrayList keysUsages, String newPassPhrase, String oldPassPhrase) throws PgpGeneralException, PGPException, SignatureException, IOException { - Log.d(Constants.TAG, "userIds: " + userIds.toString()); + int usageId = keysUsages.get(0); + boolean canSign; + String mainUserId = userIds.get(0); + + PGPSecretKey masterKey = keys.get(0); + + // 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); + + updateProgress(R.string.progress_certifying_master_key, 20, 100); + int user_id_index = 0; + for (String userId : userIds) { + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + + sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey); + + PGPSignature certification = sGen.generateCertification(userId, masterPublicKey); + masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, certification); + user_id_index++; + } + + PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey); + + PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); + PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); + + hashedPacketsGen.setKeyFlags(true, usageId); + + hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS); + hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS); + hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS); + + if (keysExpiryDates.get(0) != null) { + GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + creationDate.setTime(masterPublicKey.getCreationTime()); + GregorianCalendar expiryDate = keysExpiryDates.get(0); + //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)); + hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); + } else { + hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding, + //this happens anyway + } + + updateProgress(R.string.progress_building_master_key, 30, 100); + + // define hashing and signing algos + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get( + HashAlgorithmTags.SHA1); + PGPContentSignerBuilder certificationSignerBuilder = new JcaPGPContentSignerBuilder( + masterKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1); + + // Build key encrypter based on passphrase + PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( + PGPEncryptedData.CAST5, sha1Calc) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( + newPassPhrase.toCharArray()); + + PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, + masterKeyPair, mainUserId, sha1Calc, hashedPacketsGen.generate(), + unhashedPacketsGen.generate(), certificationSignerBuilder, keyEncryptor); + + updateProgress(R.string.progress_adding_sub_keys, 40, 100); + + for (int i = 1; i < keys.size(); ++i) { + updateProgress(40 + 50 * (i - 1) / (keys.size() - 1), 100); + + PGPSecretKey subKey = keys.get(i); + PGPPublicKey subPublicKey = subKey.getPublicKey(); + + PBESecretKeyDecryptor keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( + oldPassPhrase.toCharArray()); + PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2); + + // TODO: now used without algorithm and creation time?! (APG 1) + PGPKeyPair subKeyPair = new PGPKeyPair(subPublicKey, subPrivateKey); + + hashedPacketsGen = new PGPSignatureSubpacketGenerator(); + unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); + + usageId = keysUsages.get(i); + canSign = (usageId & KeyFlags.SIGN_DATA) > 0; //todo - separate function for this + if (canSign) { + Date todayDate = new Date(); //both sig times the same + // cross-certify signing keys + hashedPacketsGen.setSignatureCreationTime(false, todayDate); //set outer creation time + PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); + subHashedPacketsGen.setSignatureCreationTime(false, todayDate); //set inner creation time + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + subPublicKey.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, + subPublicKey); + unhashedPacketsGen.setEmbeddedSignature(false, certification); + } + hashedPacketsGen.setKeyFlags(false, usageId); + + if (keysExpiryDates.get(i) != null) { + GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + creationDate.setTime(subPublicKey.getCreationTime()); + 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)); + hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); + } else { + hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding, + //this happens anyway + } + + keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate()); + } + + 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); + + updateProgress(R.string.progress_done, 100, 100); + } + + public void buildSecretKey(ArrayList userIds, ArrayList OriginalIDs, ArrayList deletedIDs, ArrayList keys, boolean[] modded_keys, ArrayList deleted_keys, ArrayList keysExpiryDates, ArrayList keysUsages, String newPassPhrase, String oldPassPhrase) throws PgpGeneralException, + PGPException, SignatureException, IOException { updateProgress(R.string.progress_building_key, 0, 100); + PGPSecretKey masterKey = keys.get(0); + + PGPSecretKeyRing mKR = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, masterKey.getKeyID()); if (oldPassPhrase == null) { oldPassPhrase = ""; @@ -212,41 +358,25 @@ public class PgpKeyOperation { newPassPhrase = ""; } - updateProgress(R.string.progress_preparing_master_key, 10, 100); + if (mKR == null) + buildNewSecretKey(userIds, keys, keysExpiryDates, keysUsages, newPassPhrase, oldPassPhrase); //new Keyring + + masterKey = mKR.getSecretKey(); + PGPPublicKey masterPublicKey = masterKey.getPublicKey(); int usageId = keysUsages.get(0); boolean canSign; String mainUserId = userIds.get(0); - PGPSecretKey masterKey = keys.get(0); - - // this removes all userIds and certifications previously attached to the masterPublicKey - PGPPublicKey masterPublicKey = masterKey.getPublicKey(); - - // already done by code above: - // PGPPublicKey masterPublicKey = masterKey.getPublicKey(); - // // Somehow, the PGPPublicKey already has an empty certification attached to it when the - // // keyRing is generated the first time, we remove that when it exists, before adding the - // new - // // ones - // PGPPublicKey masterPublicKeyRmCert = PGPPublicKey.removeCertification(masterPublicKey, - // ""); - // if (masterPublicKeyRmCert != null) { - // masterPublicKey = masterPublicKeyRmCert; - // } - - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassPhrase.toCharArray()); PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor); updateProgress(R.string.progress_certifying_master_key, 20, 100); - // TODO: if we are editing a key, keep old certs, don't remake certs we don't have to. int user_id_index = 0; for (String userId : userIds) { - if (OriginalIDs[user_id_index]) { + if (!OriginalIDs.get(user_id_index).equals(userIds.get(user_id_index))) { PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); -- cgit v1.2.3