diff options
Diffstat (limited to 'OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java')
-rw-r--r-- | OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 466 |
1 files changed, 0 insertions, 466 deletions
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java deleted file mode 100644 index 3ec6fd2a8..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -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 org.spongycastle.bcpg.CompressionAlgorithmTags; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; -import org.spongycastle.bcpg.sig.KeyFlags; -import org.spongycastle.jce.provider.BouncyCastleProvider; -import org.spongycastle.jce.spec.ElGamalParameterSpec; -import org.spongycastle.openpgp.PGPEncryptedData; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyPair; -import org.spongycastle.openpgp.PGPKeyRingGenerator; -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.PGPSignatureSubpacketVector; -import org.spongycastle.openpgp.PGPUtil; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; -import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; -import org.spongycastle.openpgp.operator.PGPDigestCalculator; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; -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.util.Log; -import org.sufficientlysecure.keychain.util.Primes; -import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; - -import android.content.Context; - -public class PgpKeyOperation { - private Context mContext; - private ProgressDialogUpdater mProgress; - - private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[] { - SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192, - SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5, - SymmetricKeyAlgorithmTags.TRIPLE_DES }; - private static final int[] PREFERRED_HASH_ALGORITHMS = new int[] { HashAlgorithmTags.SHA1, - HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160 }; - private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[] { - CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2, - CompressionAlgorithmTags.ZIP }; - - public PgpKeyOperation(Context context, ProgressDialogUpdater progress) { - super(); - this.mContext = context; - this.mProgress = progress; - } - - public void updateProgress(int message, int current, int total) { - if (mProgress != null) { - mProgress.setProgress(message, current, total); - } - } - - public void updateProgress(int current, int total) { - if (mProgress != null) { - mProgress.setProgress(current, total); - } - } - - /** - * Creates new secret key. The returned PGPSecretKeyRing contains only one newly generated key - * when this key is the new masterkey. If a masterkey is supplied in the parameters - * PGPSecretKeyRing contains the masterkey and the new key as a subkey (certified by the - * masterkey). - * - * @param algorithmChoice - * @param keySize - * @param passPhrase - * @param masterSecretKey - * @return - * @throws NoSuchAlgorithmException - * @throws PGPException - * @throws NoSuchProviderException - * @throws PgpGeneralException - * @throws InvalidAlgorithmParameterException - */ - public PGPSecretKeyRing createKey(int algorithmChoice, int keySize, String passPhrase, - PGPSecretKey masterSecretKey) throws NoSuchAlgorithmException, PGPException, - NoSuchProviderException, PgpGeneralException, InvalidAlgorithmParameterException { - - if (keySize < 512) { - throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit)); - } - - if (passPhrase == null) { - passPhrase = ""; - } - - int algorithm = 0; - KeyPairGenerator keyGen = null; - - switch (algorithmChoice) { - case Id.choice.algorithm.dsa: { - keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME); - keyGen.initialize(keySize, new SecureRandom()); - algorithm = PGPPublicKey.DSA; - break; - } - - case Id.choice.algorithm.elgamal: { - if (masterSecretKey == null) { - throw new PgpGeneralException( - mContext.getString(R.string.error_master_key_must_not_be_el_gamal)); - } - keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME); - BigInteger p = Primes.getBestPrime(keySize); - BigInteger g = new BigInteger("2"); - - ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g); - - keyGen.initialize(elParams); - algorithm = PGPPublicKey.ELGAMAL_ENCRYPT; - break; - } - - case Id.choice.algorithm.rsa: { - keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME); - keyGen.initialize(keySize, new SecureRandom()); - - algorithm = PGPPublicKey.RSA_GENERAL; - break; - } - - default: { - throw new PgpGeneralException( - mContext.getString(R.string.error_unknown_algorithm_choice)); - } - } - - // build new key pair - PGPKeyPair keyPair = new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date()); - - // define hashing and signing algos - PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get( - HashAlgorithmTags.SHA1); - - // Build key encrypter and decrypter based on passphrase - PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( - PGPEncryptedData.CAST5, sha1Calc) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passPhrase.toCharArray()); - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passPhrase.toCharArray()); - - PGPKeyRingGenerator ringGen = null; - PGPContentSignerBuilder certificationSignerBuilder = null; - if (masterSecretKey == null) { - certificationSignerBuilder = new JcaPGPContentSignerBuilder(keyPair.getPublicKey() - .getAlgorithm(), HashAlgorithmTags.SHA1); - - // build keyRing with only this one master key in it! - ringGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, keyPair, "", - sha1Calc, null, null, certificationSignerBuilder, keyEncryptor); - } else { - PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); - PGPPrivateKey masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor); - PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey); - - certificationSignerBuilder = new JcaPGPContentSignerBuilder(masterKeyPair - .getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1); - - // build keyRing with master key and new key as subkey (certified by masterkey) - ringGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, masterKeyPair, - "", sha1Calc, null, null, certificationSignerBuilder, keyEncryptor); - - ringGen.addSubKey(keyPair); - } - - PGPSecretKeyRing secKeyRing = ringGen.generateSecretKeyRing(); - - return secKeyRing; - } - - public void changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase, - String newPassPhrase) throws IOException, PGPException, PGPException, - NoSuchProviderException { - - updateProgress(R.string.progress_building_key, 0, 100); - if (oldPassPhrase == null) { - oldPassPhrase = ""; - } - if (newPassPhrase == null) { - newPassPhrase = ""; - } - - PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword( - keyRing, - new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassPhrase.toCharArray()), - new JcePBESecretKeyEncryptorBuilder(keyRing.getSecretKey() - .getKeyEncryptionAlgorithm()).build(newPassPhrase.toCharArray())); - - updateProgress(R.string.progress_saving_key_ring, 50, 100); - - ProviderHelper.saveKeyRing(mContext, newKeyRing); - - updateProgress(R.string.progress_done, 100, 100); - - } - - public void buildSecretKey(ArrayList<String> userIds, ArrayList<PGPSecretKey> keys, - ArrayList<Integer> keysUsages, long masterKeyId, String oldPassPhrase, - String newPassPhrase) throws PgpGeneralException, NoSuchProviderException, - PGPException, NoSuchAlgorithmException, SignatureException, IOException { - - Log.d(Constants.TAG, "userIds: " + userIds.toString()); - - updateProgress(R.string.progress_building_key, 0, 100); - - if (oldPassPhrase == null) { - oldPassPhrase = ""; - } - if (newPassPhrase == null) { - newPassPhrase = ""; - } - - updateProgress(R.string.progress_preparing_master_key, 10, 100); - - int usageId = keysUsages.get(0); - boolean canSign = (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt); - boolean canEncrypt = (usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt); - - String mainUserId = userIds.get(0); - - PGPSecretKey masterKey = keys.get(0); - - // this removes all userIds and certifications previously attached to the masterPublicKey - PGPPublicKey tmpKey = masterKey.getPublicKey(); - PGPPublicKey masterPublicKey = new PGPPublicKey(tmpKey.getAlgorithm(), - tmpKey.getKey(new BouncyCastleProvider()), tmpKey.getCreationTime()); - - // 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. - - 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); - } - - PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey); - - PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); - PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); - - int keyFlags = KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA; - if (canEncrypt) { - keyFlags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE; - } - hashedPacketsGen.setKeyFlags(true, keyFlags); - - hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS); - hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS); - hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS); - - // TODO: this doesn't work quite right yet (APG 1) - // if (keyEditor.getExpiryDate() != null) { - // GregorianCalendar creationDate = new GregorianCalendar(); - // creationDate.setTime(getCreationDate(masterKey)); - // GregorianCalendar expiryDate = keyEditor.getExpiryDate(); - // long numDays = Utils.getNumDaysBetween(creationDate, expiryDate); - // if (numDays <= 0) { - // throw new GeneralException( - // context.getString(R.string.error_expiryMustComeAfterCreation)); - // } - // hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400); - // } - - 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(); - - keyFlags = 0; - - usageId = keysUsages.get(i); - canSign = (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt); - canEncrypt = (usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt); - if (canSign) { // TODO: ensure signing times are the same, like gpg - keyFlags |= KeyFlags.SIGN_DATA; - // cross-certify signing keys - 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); - PGPSignature certification = sGen.generateCertification(masterPublicKey, - subPublicKey); - unhashedPacketsGen.setEmbeddedSignature(false, certification); - } - if (canEncrypt) { - keyFlags |= KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE; - } - hashedPacketsGen.setKeyFlags(false, keyFlags); - - // TODO: this doesn't work quite right yet (APG 1) - // if (keyEditor.getExpiryDate() != null) { - // GregorianCalendar creationDate = new GregorianCalendar(); - // creationDate.setTime(getCreationDate(masterKey)); - // GregorianCalendar expiryDate = keyEditor.getExpiryDate(); - // long numDays = Utils.getNumDaysBetween(creationDate, expiryDate); - // if (numDays <= 0) { - // throw new GeneralException( - // context.getString(R.string.error_expiryMustComeAfterCreation)); - // } - // hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400); - // } - - 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 PGPPublicKeyRing signKey(long masterKeyId, long pubKeyId, String passphrase) - throws PgpGeneralException, NoSuchAlgorithmException, NoSuchProviderException, - PGPException, SignatureException { - if (passphrase == null) { - throw new PgpGeneralException("Unable to obtain passphrase"); - } else { - PGPPublicKeyRing pubring = ProviderHelper - .getPGPPublicKeyRingByKeyId(mContext, pubKeyId); - - PGPSecretKey signingKey = PgpKeyHelper.getCertificationKey(mContext, masterKeyId); - if (signingKey == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed)); - } - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); - PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor); - if (signaturePrivateKey == null) { - throw new PgpGeneralException( - mContext.getString(R.string.error_could_not_extract_private_key)); - } - - // TODO: SHA256 fixed? - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - signingKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator( - contentSignerBuilder); - - signatureGenerator.init(PGPSignature.DIRECT_KEY, signaturePrivateKey); - - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - - PGPSignatureSubpacketVector packetVector = spGen.generate(); - signatureGenerator.setHashedSubpackets(packetVector); - - PGPPublicKey signedKey = PGPPublicKey.addCertification(pubring.getPublicKey(pubKeyId), - signatureGenerator.generate()); - pubring = PGPPublicKeyRing.insertPublicKey(pubring, signedKey); - - return pubring; - } - } -} |