aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java200
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java836
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java93
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java218
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java294
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java644
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java769
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java607
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java313
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java26
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java29
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java35
12 files changed, 0 insertions, 4064 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java
deleted file mode 100644
index c6c62d649..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.pgp;
-
-import org.spongycastle.openpgp.PGPKeyRing;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPSignature;
-import org.spongycastle.openpgp.PGPSignatureList;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.util.Log;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-
-public class PgpConversionHelper {
-
- /**
- * Convert from byte[] to PGPKeyRing
- *
- * @param keysBytes
- * @return
- */
- public static PGPKeyRing BytesToPGPKeyRing(byte[] keysBytes) {
- PGPObjectFactory factory = new PGPObjectFactory(keysBytes);
- PGPKeyRing keyRing = null;
- try {
- if ((keyRing = (PGPKeyRing) factory.nextObject()) == null) {
- Log.e(Constants.TAG, "No keys given!");
- }
- } catch (IOException e) {
- Log.e(Constants.TAG, "Error while converting to PGPKeyRing!", e);
- }
-
- return keyRing;
- }
-
- /**
- * Convert from byte[] to ArrayList<PGPSecretKey>
- *
- * @param keysBytes
- * @return
- */
- public static ArrayList<PGPSecretKey> BytesToPGPSecretKeyList(byte[] keysBytes) {
- PGPObjectFactory factory = new PGPObjectFactory(keysBytes);
- Object obj = null;
- ArrayList<PGPSecretKey> keys = new ArrayList<PGPSecretKey>();
- try {
- while ((obj = factory.nextObject()) != null) {
- PGPSecretKey secKey = null;
- if (obj instanceof PGPSecretKey) {
- secKey = (PGPSecretKey) obj;
- if (secKey == null) {
- Log.e(Constants.TAG, "No keys given!");
- }
- keys.add(secKey);
- } else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings
- PGPSecretKeyRing keyRing = null;
- keyRing = (PGPSecretKeyRing) obj;
- if (keyRing == null) {
- Log.e(Constants.TAG, "No keys given!");
- }
- @SuppressWarnings("unchecked")
- Iterator<PGPSecretKey> itr = keyRing.getSecretKeys();
- while (itr.hasNext()) {
- keys.add(itr.next());
- }
- }
- }
- } catch (IOException e) {
- }
-
- return keys;
- }
-
- /**
- * Convert from byte[] to PGPSecretKey
- * <p/>
- * Singles keys are encoded as keyRings with one single key in it by Bouncy Castle
- *
- * @param keyBytes
- * @return
- */
- public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) {
- PGPObjectFactory factory = new PGPObjectFactory(keyBytes);
- Object obj = null;
- try {
- obj = factory.nextObject();
- } catch (IOException e) {
- Log.e(Constants.TAG, "Error while converting to PGPSecretKey!", e);
- }
- PGPSecretKey secKey = null;
- if (obj instanceof PGPSecretKey) {
- if ((secKey = (PGPSecretKey) obj) == null) {
- Log.e(Constants.TAG, "No keys given!");
- }
- } else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings
- PGPSecretKeyRing keyRing = null;
- if ((keyRing = (PGPSecretKeyRing) obj) == null) {
- Log.e(Constants.TAG, "No keys given!");
- }
- secKey = keyRing.getSecretKey();
- }
-
- return secKey;
- }
-
- /**
- * Convert from byte[] to PGPSignature
- *
- * @param sigBytes
- * @return
- */
- public static PGPSignature BytesToPGPSignature(byte[] sigBytes) {
- PGPObjectFactory factory = new PGPObjectFactory(sigBytes);
- PGPSignatureList signatures = null;
- try {
- if ((signatures = (PGPSignatureList) factory.nextObject()) == null || signatures.isEmpty()) {
- Log.e(Constants.TAG, "No signatures given!");
- return null;
- }
- } catch (IOException e) {
- Log.e(Constants.TAG, "Error while converting to PGPSignature!", e);
- return null;
- }
-
- return signatures.get(0);
- }
-
- /**
- * Convert from ArrayList<PGPSecretKey> to byte[]
- *
- * @param keys
- * @return
- */
- public static byte[] PGPSecretKeyArrayListToBytes(ArrayList<PGPSecretKey> keys) {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- for (PGPSecretKey key : keys) {
- try {
- key.encode(os);
- } catch (IOException e) {
- Log.e(Constants.TAG, "Error while converting ArrayList<PGPSecretKey> to byte[]!", e);
- }
- }
-
- return os.toByteArray();
- }
-
- /**
- * Convert from PGPSecretKey to byte[]
- *
- * @param key
- * @return
- */
- public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) {
- try {
- return key.getEncoded();
- } catch (IOException e) {
- Log.e(Constants.TAG, "Encoding failed", e);
-
- return null;
- }
- }
-
- /**
- * Convert from PGPSecretKeyRing to byte[]
- *
- * @param keyRing
- * @return
- */
- public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) {
- try {
- return keyRing.getEncoded();
- } catch (IOException e) {
- Log.e(Constants.TAG, "Encoding failed", e);
-
- return null;
- }
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
deleted file mode 100644
index 8a0bf99d7..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ /dev/null
@@ -1,836 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 android.content.Context;
-
-import org.openintents.openpgp.OpenPgpSignatureResult;
-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;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPLiteralData;
-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.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.util.InputData;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.SignatureException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Set;
-
-/**
- * This class uses a Builder pattern!
- */
-public class PgpDecryptVerify {
- private Context mContext;
- private InputData mData;
- private OutputStream mOutStream;
-
- private ProgressDialogUpdater mProgressDialogUpdater;
- private boolean mAllowSymmetricDecryption;
- private String mPassphrase;
- private Set<Long> mAllowedKeyIds;
-
- private PgpDecryptVerify(Builder builder) {
- // private Constructor can only be called from Builder
- this.mContext = builder.mContext;
- this.mData = builder.mData;
- this.mOutStream = builder.mOutStream;
-
- this.mProgressDialogUpdater = builder.mProgressDialogUpdater;
- this.mAllowSymmetricDecryption = builder.mAllowSymmetricDecryption;
- this.mPassphrase = builder.mPassphrase;
- this.mAllowedKeyIds = builder.mAllowedKeyIds;
- }
-
- public static class Builder {
- // mandatory parameter
- private Context mContext;
- private InputData mData;
- private OutputStream mOutStream;
-
- // optional
- private ProgressDialogUpdater mProgressDialogUpdater = null;
- private boolean mAllowSymmetricDecryption = true;
- private String mPassphrase = null;
- private Set<Long> mAllowedKeyIds = null;
-
- public Builder(Context context, InputData data, OutputStream outStream) {
- this.mContext = context;
- this.mData = data;
- this.mOutStream = outStream;
- }
-
- public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) {
- this.mProgressDialogUpdater = progressDialogUpdater;
- return this;
- }
-
- public Builder allowSymmetricDecryption(boolean allowSymmetricDecryption) {
- this.mAllowSymmetricDecryption = allowSymmetricDecryption;
- return this;
- }
-
- public Builder passphrase(String passphrase) {
- this.mPassphrase = passphrase;
- return this;
- }
-
- /**
- * Allow these key ids alone for decryption.
- * This means only ciphertexts encrypted for one of these private key can be decrypted.
- *
- * @param allowedKeyIds
- * @return
- */
- public Builder allowedKeyIds(Set<Long> allowedKeyIds) {
- this.mAllowedKeyIds = allowedKeyIds;
- return this;
- }
-
- public PgpDecryptVerify build() {
- return new PgpDecryptVerify(this);
- }
- }
-
- public void updateProgress(int message, int current, int total) {
- if (mProgressDialogUpdater != null) {
- mProgressDialogUpdater.setProgress(message, current, total);
- }
- }
-
- public void updateProgress(int current, int total) {
- if (mProgressDialogUpdater != null) {
- mProgressDialogUpdater.setProgress(current, total);
- }
- }
-
- /**
- * Decrypts and/or verifies data based on parameters of class
- *
- * @return
- * @throws IOException
- * @throws PgpGeneralException
- * @throws PGPException
- * @throws SignatureException
- */
- public PgpDecryptVerifyResult execute()
- throws IOException, PgpGeneralException, PGPException, SignatureException {
- // automatically works with ascii armor input and binary
- InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
- if (in instanceof ArmoredInputStream) {
- ArmoredInputStream aIn = (ArmoredInputStream) in;
- // it is ascii armored
- Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine());
-
- if (aIn.isClearText()) {
- // a cleartext signature, verify it with the other method
- return verifyCleartextSignature(aIn);
- }
- // else: ascii armored encryption! go on...
- }
-
- return decryptVerify(in);
- }
-
- /**
- * Decrypt and/or verifies binary or ascii armored pgp
- *
- * @param in
- * @return
- * @throws IOException
- * @throws PgpGeneralException
- * @throws PGPException
- * @throws SignatureException
- */
- private PgpDecryptVerifyResult decryptVerify(InputStream in)
- throws IOException, PgpGeneralException, PGPException, SignatureException {
- PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult();
-
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- PGPEncryptedDataList enc;
- Object o = pgpF.nextObject();
-
- int currentProgress = 0;
- updateProgress(R.string.progress_reading_data, currentProgress, 100);
-
- if (o instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) o;
- } else {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
-
- if (enc == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_invalid_data));
- }
-
- InputStream clear;
- PGPEncryptedData encryptedData;
-
- currentProgress += 5;
-
- PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
- PGPPBEEncryptedData encryptedDataSymmetric = null;
- PGPSecretKey secretKey = null;
- Iterator<?> it = enc.getEncryptedDataObjects();
- boolean symmetricPacketFound = false;
- // find secret key
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPublicKeyEncryptedData) {
- updateProgress(R.string.progress_finding_key, currentProgress, 100);
-
- PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
- long masterKeyId = ProviderHelper.getMasterKeyId(mContext,
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(encData.getKeyID()))
- );
- PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRing(mContext, masterKeyId);
- if (secretKeyRing == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
- }
- secretKey = secretKeyRing.getSecretKey(encData.getKeyID());
- if (secretKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
- }
- // secret key exists in database
-
- // allow only a specific key for decryption?
- if (mAllowedKeyIds != null) {
- Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
- Log.d(Constants.TAG, "allowedKeyIds: " + mAllowedKeyIds);
- Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
-
- if (!mAllowedKeyIds.contains(masterKeyId)) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_no_secret_key_found));
- }
- }
-
- encryptedDataAsymmetric = encData;
-
- // if no passphrase was explicitly set try to get it from the cache service
- if (mPassphrase == null) {
- // returns "" if key has no passphrase
- mPassphrase =
- PassphraseCacheService.getCachedPassphrase(mContext, masterKeyId);
-
- // if passphrase was not cached, return here
- // indicating that a passphrase is missing!
- if (mPassphrase == null) {
- returnData.setKeyIdPassphraseNeeded(masterKeyId);
- returnData.setStatus(PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED);
- return returnData;
- }
- }
-
- // break out of while, only get first object here
- // TODO???: There could be more pgp objects, which are not decrypted!
- break;
- } else if (mAllowSymmetricDecryption && obj instanceof PGPPBEEncryptedData) {
- symmetricPacketFound = true;
-
- encryptedDataSymmetric = (PGPPBEEncryptedData) obj;
-
- // if no passphrase is given, return here
- // indicating that a passphrase is missing!
- if (mPassphrase == null) {
- returnData.setStatus(PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED);
- return returnData;
- }
-
- // break out of while, only get first object here
- // TODO???: There could be more pgp objects, which are not decrypted!
- break;
- }
- }
-
- if (symmetricPacketFound) {
- updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
-
- PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
- PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
- digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- mPassphrase.toCharArray());
-
- clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
-
- encryptedData = encryptedDataSymmetric;
- currentProgress += 5;
- } else {
- if (secretKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
- }
-
- 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 = secretKey.extractPrivateKey(keyDecryptor);
- } catch (PGPException e) {
- throw new PGPException(mContext.getString(R.string.error_wrong_passphrase));
- }
- if (privateKey == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_could_not_extract_private_key));
- }
- currentProgress += 5;
- updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
-
- PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey);
-
- clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
-
- encryptedData = encryptedDataAsymmetric;
- currentProgress += 5;
- }
-
- PGPObjectFactory plainFact = new PGPObjectFactory(clear);
- Object dataChunk = plainFact.nextObject();
- PGPOnePassSignature signature = null;
- OpenPgpSignatureResult signatureResult = null;
- PGPPublicKey signatureKey = null;
- int signatureIndex = -1;
-
- if (dataChunk instanceof PGPCompressedData) {
- updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
-
- PGPObjectFactory fact = new PGPObjectFactory(
- ((PGPCompressedData) dataChunk).getDataStream());
- dataChunk = fact.nextObject();
- plainFact = fact;
- currentProgress += 10;
- }
-
- long signatureKeyId = 0;
- if (dataChunk instanceof PGPOnePassSignatureList) {
- updateProgress(R.string.progress_processing_signature, currentProgress, 100);
-
- signatureResult = new OpenPgpSignatureResult();
- PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
- for (int i = 0; i < sigList.size(); ++i) {
- signature = sigList.get(i);
- signatureKey = ProviderHelper
- .getPGPPublicKeyRing(mContext, signature.getKeyID()).getPublicKey();
- if (signatureKeyId == 0) {
- signatureKeyId = signature.getKeyID();
- }
- if (signatureKey == null) {
- signature = null;
- } else {
- signatureIndex = i;
- signatureKeyId = signature.getKeyID();
- String userId = null;
- PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(
- mContext, signatureKeyId);
- if (signKeyRing != null) {
- userId = PgpKeyHelper.getMainUserId(signKeyRing.getPublicKey());
- }
- signatureResult.setUserId(userId);
- break;
- }
- }
-
- signatureResult.setKeyId(signatureKeyId);
-
- if (signature != null) {
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- signature.init(contentVerifierBuilderProvider, signatureKey);
- } else {
- signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
- }
-
- dataChunk = plainFact.nextObject();
- currentProgress += 10;
- }
-
- if (dataChunk instanceof PGPSignatureList) {
- dataChunk = plainFact.nextObject();
- }
-
- if (dataChunk instanceof PGPLiteralData) {
- updateProgress(R.string.progress_decrypting, currentProgress, 100);
-
- PGPLiteralData literalData = (PGPLiteralData) dataChunk;
-
- byte[] buffer = new byte[1 << 16];
- InputStream dataIn = literalData.getInputStream();
-
- int startProgress = currentProgress;
- int endProgress = 100;
- if (signature != null) {
- endProgress = 90;
- } else if (encryptedData.isIntegrityProtected()) {
- endProgress = 95;
- }
-
- int n;
- // TODO: progress calculation is broken here! Try to rework it based on commented code!
-// int progress = 0;
- long startPos = mData.getStreamPosition();
- while ((n = dataIn.read(buffer)) > 0) {
- mOutStream.write(buffer, 0, n);
-// progress += n;
- if (signature != null) {
- try {
- signature.update(buffer, 0, n);
- } catch (SignatureException e) {
- signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
- signature = null;
- }
- }
- // TODO: dead code?!
- // unknown size, but try to at least have a moving, slowing down progress bar
-// currentProgress = startProgress + (endProgress - startProgress) * progress
-// / (progress + 100000);
- if (mData.getSize() - startPos == 0) {
- currentProgress = endProgress;
- } else {
- currentProgress = (int) (startProgress + (endProgress - startProgress)
- * (mData.getStreamPosition() - startPos) / (mData.getSize() - startPos));
- }
- updateProgress(currentProgress, 100);
- }
-
- if (signature != null) {
- updateProgress(R.string.progress_verifying_signature, 90, 100);
-
- PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject();
- PGPSignature messageSignature = signatureList.get(signatureIndex);
-
- // these are not cleartext signatures!
- // TODO: what about binary signatures?
- signatureResult.setSignatureOnly(false);
-
- //Now check binding signatures
- boolean validKeyBinding = verifyKeyBinding(mContext, messageSignature, signatureKey);
- boolean validSignature = signature.verify(messageSignature);
-
- // TODO: implement CERTIFIED!
- if (validKeyBinding & validSignature) {
- signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED);
- }
- }
- }
-
- if (encryptedData.isIntegrityProtected()) {
- updateProgress(R.string.progress_verifying_integrity, 95, 100);
-
- if (encryptedData.verify()) {
- // passed
- Log.d(Constants.TAG, "Integrity verification: success!");
- } else {
- // failed
- Log.d(Constants.TAG, "Integrity verification: failed!");
- throw new PgpGeneralException(mContext.getString(R.string.error_integrity_check_failed));
- }
- } else {
- // no integrity check
- Log.e(Constants.TAG, "Encrypted data was not integrity protected!");
- // TODO: inform user?
- }
-
- updateProgress(R.string.progress_done, 100, 100);
-
- returnData.setSignatureResult(signatureResult);
- return returnData;
- }
-
- /**
- * This method verifies cleartext signatures
- * as defined in http://tools.ietf.org/html/rfc4880#section-7
- * <p/>
- * The method is heavily based on
- * pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
- *
- * @return
- * @throws IOException
- * @throws PgpGeneralException
- * @throws PGPException
- * @throws SignatureException
- */
- private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn)
- throws IOException, PgpGeneralException, PGPException, SignatureException {
- PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult();
- OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult();
- // cleartext signatures are never encrypted ;)
- signatureResult.setSignatureOnly(true);
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- updateProgress(R.string.progress_done, 0, 100);
-
- ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
- int lookAhead = readInputLine(lineOut, aIn);
- byte[] lineSep = getLineSeparator();
-
- byte[] line = lineOut.toByteArray();
- out.write(line, 0, getLengthWithoutSeparator(line));
- out.write(lineSep);
-
- while (lookAhead != -1 && aIn.isClearText()) {
- lookAhead = readInputLine(lineOut, lookAhead, aIn);
- line = lineOut.toByteArray();
- out.write(line, 0, getLengthWithoutSeparator(line));
- out.write(lineSep);
- }
-
- out.close();
-
- byte[] clearText = out.toByteArray();
- mOutStream.write(clearText);
-
- updateProgress(R.string.progress_processing_signature, 60, 100);
- PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
-
- PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
- if (sigList == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_corrupt_data));
- }
- PGPSignature signature = null;
- long signatureKeyId = 0;
- PGPPublicKey signatureKey = null;
- for (int i = 0; i < sigList.size(); ++i) {
-
- signature = sigList.get(i);
- signatureKeyId = signature.getKeyID();
-
- // find data about this subkey
- HashMap<String, Object> data = ProviderHelper.getGenericData(mContext,
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(signature.getKeyID())),
- new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
- new int[] { ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_STRING });
- // any luck? otherwise, try next.
- if(data.get(KeyRings.MASTER_KEY_ID) == null) {
- signature = null;
- // do NOT reset signatureKeyId, that one is shown when no known one is found!
- continue;
- }
-
- // this one can't fail now (yay database constraints)
- signatureKey = ProviderHelper.getPGPPublicKeyRing(mContext, (Long) data.get(KeyRings.MASTER_KEY_ID)).getPublicKey();
- signatureResult.setUserId((String) data.get(KeyRings.USER_ID));
-
- break;
- }
-
- signatureResult.setKeyId(signatureKeyId);
-
- if (signature == null) {
- signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
- returnData.setSignatureResult(signatureResult);
-
- updateProgress(R.string.progress_done, 100, 100);
- return returnData;
- }
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- signature.init(contentVerifierBuilderProvider, signatureKey);
-
- InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
-
- lookAhead = readInputLine(lineOut, sigIn);
-
- processLine(signature, lineOut.toByteArray());
-
- if (lookAhead != -1) {
- do {
- lookAhead = readInputLine(lineOut, lookAhead, sigIn);
-
- signature.update((byte) '\r');
- signature.update((byte) '\n');
-
- processLine(signature, lineOut.toByteArray());
- } while (lookAhead != -1);
- }
-
- //Now check binding signatures
- boolean validKeyBinding = verifyKeyBinding(mContext, signature, signatureKey);
- boolean validSignature = signature.verify();
-
- if (validSignature & validKeyBinding) {
- signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED);
- }
-
- // TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR????
-
- returnData.setSignatureResult(signatureResult);
-
- updateProgress(R.string.progress_done, 100, 100);
- return returnData;
- }
-
- private static boolean verifyKeyBinding(Context context,
- PGPSignature signature, PGPPublicKey signatureKey) {
- long signatureKeyId = signature.getKeyID();
- boolean validKeyBinding = false;
-
- PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(context,
- signatureKeyId);
- PGPPublicKey mKey = null;
- if (signKeyRing != null) {
- mKey = signKeyRing.getPublicKey();
- }
-
- 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 static 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<PGPSignature> 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 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;
- }
-
- /**
- * Mostly taken from ClearSignedFileProcessor in Bouncy Castle
- *
- * @param sig
- * @param line
- * @throws SignatureException
- */
- private static void processLine(PGPSignature sig, byte[] line)
- throws SignatureException {
- int length = getLengthWithoutWhiteSpace(line);
- if (length > 0) {
- sig.update(line, 0, length);
- }
- }
-
- private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
- throws IOException {
- bOut.reset();
-
- int lookAhead = -1;
- int ch;
-
- while ((ch = fIn.read()) >= 0) {
- bOut.write(ch);
- if (ch == '\r' || ch == '\n') {
- lookAhead = readPassedEOL(bOut, ch, fIn);
- break;
- }
- }
-
- return lookAhead;
- }
-
- private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
- throws IOException {
- bOut.reset();
-
- int ch = lookAhead;
-
- do {
- bOut.write(ch);
- if (ch == '\r' || ch == '\n') {
- lookAhead = readPassedEOL(bOut, ch, fIn);
- break;
- }
- } while ((ch = fIn.read()) >= 0);
-
- if (ch < 0) {
- lookAhead = -1;
- }
-
- return lookAhead;
- }
-
- private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
- throws IOException {
- int lookAhead = fIn.read();
-
- if (lastCh == '\r' && lookAhead == '\n') {
- bOut.write(lookAhead);
- lookAhead = fIn.read();
- }
-
- return lookAhead;
- }
-
- private static int getLengthWithoutSeparator(byte[] line) {
- int end = line.length - 1;
-
- while (end >= 0 && isLineEnding(line[end])) {
- end--;
- }
-
- return end + 1;
- }
-
- private static boolean isLineEnding(byte b) {
- return b == '\r' || b == '\n';
- }
-
- private static int getLengthWithoutWhiteSpace(byte[] line) {
- int end = line.length - 1;
-
- while (end >= 0 && isWhiteSpace(line[end])) {
- end--;
- }
-
- return end + 1;
- }
-
- private static boolean isWhiteSpace(byte b) {
- return b == '\r' || b == '\n' || b == '\t' || b == ' ';
- }
-
- private static byte[] getLineSeparator() {
- String nl = System.getProperty("line.separator");
- byte[] nlBytes = new byte[nl.length()];
-
- for (int i = 0; i != nlBytes.length; i++) {
- nlBytes[i] = (byte) nl.charAt(i);
- }
-
- return nlBytes;
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java
deleted file mode 100644
index ad240e834..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.pgp;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import org.openintents.openpgp.OpenPgpSignatureResult;
-
-public class PgpDecryptVerifyResult implements Parcelable {
- public static final int SUCCESS = 1;
- public static final int KEY_PASSHRASE_NEEDED = 2;
- public static final int SYMMETRIC_PASSHRASE_NEEDED = 3;
-
- int mStatus;
- long mKeyIdPassphraseNeeded;
-
- OpenPgpSignatureResult mSignatureResult;
-
- public int getStatus() {
- return mStatus;
- }
-
- public void setStatus(int mStatus) {
- this.mStatus = mStatus;
- }
-
- public long getKeyIdPassphraseNeeded() {
- return mKeyIdPassphraseNeeded;
- }
-
- public void setKeyIdPassphraseNeeded(long mKeyIdPassphraseNeeded) {
- this.mKeyIdPassphraseNeeded = mKeyIdPassphraseNeeded;
- }
-
- public OpenPgpSignatureResult getSignatureResult() {
- return mSignatureResult;
- }
-
- public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
- this.mSignatureResult = signatureResult;
- }
-
- public PgpDecryptVerifyResult() {
-
- }
-
- public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) {
- this.mStatus = b.mStatus;
- this.mKeyIdPassphraseNeeded = b.mKeyIdPassphraseNeeded;
- this.mSignatureResult = b.mSignatureResult;
- }
-
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mStatus);
- dest.writeLong(mKeyIdPassphraseNeeded);
- dest.writeParcelable(mSignatureResult, 0);
- }
-
- public static final Creator<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() {
- public PgpDecryptVerifyResult createFromParcel(final Parcel source) {
- PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult();
- vr.mStatus = source.readInt();
- vr.mKeyIdPassphraseNeeded = source.readLong();
- vr.mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
- return vr;
- }
-
- public PgpDecryptVerifyResult[] newArray(final int size) {
- return new PgpDecryptVerifyResult[size];
- }
- };
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
deleted file mode 100644
index f884b1776..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
+++ /dev/null
@@ -1,218 +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 android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-
-import org.spongycastle.openpgp.PGPEncryptedDataList;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPUtil;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-import java.security.SecureRandom;
-import java.util.Iterator;
-import java.util.regex.Pattern;
-
-public class PgpHelper {
-
- public static final Pattern PGP_MESSAGE = Pattern.compile(
- ".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL);
-
- public static final Pattern PGP_CLEARTEXT_SIGNATURE = Pattern
- .compile(".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----" +
- "BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
- Pattern.DOTALL);
-
- public static final Pattern PGP_PUBLIC_KEY = Pattern.compile(
- ".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*",
- Pattern.DOTALL);
-
- public static String getVersion(Context context) {
- String version = null;
- try {
- PackageInfo pi = context.getPackageManager().getPackageInfo(Constants.PACKAGE_NAME, 0);
- version = pi.versionName;
- return version;
- } catch (NameNotFoundException e) {
- Log.e(Constants.TAG, "Version could not be retrieved!", e);
- return "0.0.0";
- }
- }
-
- public static String getFullVersion(Context context) {
- return "OpenPGP Keychain v" + getVersion(context);
- }
-
- public static long getDecryptionKeyId(Context context, InputStream inputStream)
- throws PgpGeneralException, NoAsymmetricEncryptionException, IOException {
- InputStream in = PGPUtil.getDecoderStream(inputStream);
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- PGPEncryptedDataList enc;
- Object o = pgpF.nextObject();
-
- // the first object might be a PGP marker packet.
- if (o instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) o;
- } else {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
-
- if (enc == null) {
- throw new PgpGeneralException(context.getString(R.string.error_invalid_data));
- }
-
- // TODO: currently we always only look at the first known key
- // find the secret key
- PGPSecretKey secretKey = null;
- Iterator<?> it = enc.getEncryptedDataObjects();
- boolean gotAsymmetricEncryption = false;
- while (it.hasNext()) {
- Object obj = it.next();
- if (obj instanceof PGPPublicKeyEncryptedData) {
- gotAsymmetricEncryption = true;
- PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) obj;
- secretKey = ProviderHelper.getPGPSecretKeyRing(context, pbe.getKeyID()).getSecretKey();
- if (secretKey != null) {
- break;
- }
- }
- }
-
- if (!gotAsymmetricEncryption) {
- throw new NoAsymmetricEncryptionException();
- }
-
- if (secretKey == null) {
- return Id.key.none;
- }
-
- return secretKey.getKeyID();
- }
-
- public static int getStreamContent(Context context, InputStream inStream) throws IOException {
- InputStream in = PGPUtil.getDecoderStream(inStream);
- PGPObjectFactory pgpF = new PGPObjectFactory(in);
- Object object = pgpF.nextObject();
- while (object != null) {
- if (object instanceof PGPPublicKeyRing || object instanceof PGPSecretKeyRing) {
- return Id.content.keys;
- } else if (object instanceof PGPEncryptedDataList) {
- return Id.content.encrypted_data;
- }
- object = pgpF.nextObject();
- }
-
- return Id.content.unknown;
- }
-
- /**
- * Generate a random filename
- *
- * @param length
- * @return
- */
- public static String generateRandomFilename(int length) {
- SecureRandom random = new SecureRandom();
-
- byte bytes[] = new byte[length];
- random.nextBytes(bytes);
- String result = "";
- for (int i = 0; i < length; ++i) {
- int v = (bytes[i] + 256) % 64;
- if (v < 10) {
- result += (char) ('0' + v);
- } else if (v < 36) {
- result += (char) ('A' + v - 10);
- } else if (v < 62) {
- result += (char) ('a' + v - 36);
- } else if (v == 62) {
- result += '_';
- } else if (v == 63) {
- result += '.';
- }
- }
- return result;
- }
-
- /**
- * Go once through stream to get length of stream. The length is later used to display progress
- * when encrypting/decrypting
- *
- * @param in
- * @return
- * @throws IOException
- */
- public static long getLengthOfStream(InputStream in) throws IOException {
- long size = 0;
- long n = 0;
- byte dummy[] = new byte[0x10000];
- while ((n = in.read(dummy)) > 0) {
- size += n;
- }
- return size;
- }
-
- /**
- * Deletes file securely by overwriting it with random data before deleting it.
- * <p/>
- * TODO: Does this really help on flash storage?
- *
- * @param context
- * @param progress
- * @param file
- * @throws IOException
- */
- public static void deleteFileSecurely(Context context, ProgressDialogUpdater progress, File file)
- throws IOException {
- long length = file.length();
- SecureRandom random = new SecureRandom();
- RandomAccessFile raf = new RandomAccessFile(file, "rws");
- raf.seek(0);
- raf.getFilePointer();
- byte[] data = new byte[1 << 16];
- int pos = 0;
- String msg = context.getString(R.string.progress_deleting_securely, file.getName());
- while (pos < length) {
- if (progress != null) {
- progress.setProgress(msg, (int) (100 * pos / length), 100);
- }
- random.nextBytes(data);
- raf.write(data);
- pos += data.length;
- }
- raf.close();
- file.delete();
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
deleted file mode 100644
index d03f3ccc2..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ /dev/null
@@ -1,294 +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 android.content.Context;
-import android.os.Bundle;
-import android.os.Environment;
-
-import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPKeyRing;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
-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.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
-import org.sufficientlysecure.keychain.util.HkpKeyServer;
-import org.sufficientlysecure.keychain.util.IterableIterator;
-import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
-import org.sufficientlysecure.keychain.util.KeychainServiceListener;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-public class PgpImportExport {
-
- private Context mContext;
- private ProgressDialogUpdater mProgress;
-
- private KeychainServiceListener mKeychainServiceListener;
-
- public PgpImportExport(Context context, ProgressDialogUpdater progress) {
- super();
- this.mContext = context;
- this.mProgress = progress;
- }
-
- public PgpImportExport(Context context,
- ProgressDialogUpdater progress, KeychainServiceListener keychainListener) {
- super();
- this.mContext = context;
- this.mProgress = progress;
- this.mKeychainServiceListener = keychainListener;
- }
-
- public void updateProgress(int message, int current, int total) {
- if (mProgress != null) {
- mProgress.setProgress(message, current, total);
- }
- }
-
- public void updateProgress(String 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);
- }
- }
-
- public boolean uploadKeyRingToServer(HkpKeyServer server, PGPPublicKeyRing keyring) {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ArmoredOutputStream aos = null;
- try {
- aos = new ArmoredOutputStream(bos);
- aos.write(keyring.getEncoded());
- aos.close();
-
- String armoredKey = bos.toString("UTF-8");
- server.add(armoredKey);
-
- return true;
- } catch (IOException e) {
- return false;
- } catch (AddKeyException e) {
- // TODO: tell the user?
- return false;
- } finally {
- try {
- if (aos != null) { aos.close(); }
- if (bos != null) { bos.close(); }
- } catch (IOException e) {
- }
- }
- }
-
- /**
- * Imports keys from given data. If keyIds is given only those are imported
- */
- public Bundle importKeyRings(List<ImportKeysListEntry> entries)
- throws PgpGeneralException, PGPException, IOException {
- Bundle returnData = new Bundle();
-
- updateProgress(R.string.progress_importing, 0, 100);
-
- int newKeys = 0;
- int oldKeys = 0;
- int badKeys = 0;
-
- int position = 0;
- try {
- for (ImportKeysListEntry entry : entries) {
- Object obj = PgpConversionHelper.BytesToPGPKeyRing(entry.getBytes());
-
- if (obj instanceof PGPKeyRing) {
- PGPKeyRing keyring = (PGPKeyRing) obj;
-
- int status = storeKeyRingInCache(keyring);
-
- if (status == Id.return_value.error) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_saving_keys));
- }
-
- // update the counts to display to the user at the end
- if (status == Id.return_value.updated) {
- ++oldKeys;
- } else if (status == Id.return_value.ok) {
- ++newKeys;
- } else if (status == Id.return_value.bad) {
- ++badKeys;
- }
- } else {
- Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!");
- }
-
- position++;
- updateProgress(position / entries.size() * 100, 100);
- }
- } catch (Exception e) {
- Log.e(Constants.TAG, "Exception on parsing key file!", e);
- }
-
- returnData.putInt(KeychainIntentService.RESULT_IMPORT_ADDED, newKeys);
- returnData.putInt(KeychainIntentService.RESULT_IMPORT_UPDATED, oldKeys);
- returnData.putInt(KeychainIntentService.RESULT_IMPORT_BAD, badKeys);
-
- return returnData;
- }
-
- public Bundle exportKeyRings(ArrayList<Long> publicKeyRingMasterIds,
- ArrayList<Long> secretKeyRingMasterIds,
- OutputStream outStream) throws PgpGeneralException,
- PGPException, IOException {
- Bundle returnData = new Bundle();
-
- int masterKeyIdsSize = publicKeyRingMasterIds.size() + secretKeyRingMasterIds.size();
- int progress = 0;
-
- updateProgress(
- mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
- masterKeyIdsSize), 0, 100);
-
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_external_storage_not_ready));
- }
- // For each public masterKey id
- for (long pubKeyMasterId : publicKeyRingMasterIds) {
- progress++;
- // Create an output stream
- ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
- arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext));
-
- updateProgress(progress * 100 / masterKeyIdsSize, 100);
- PGPPublicKeyRing publicKeyRing =
- ProviderHelper.getPGPPublicKeyRing(mContext, pubKeyMasterId);
-
- if (publicKeyRing != null) {
- publicKeyRing.encode(arOutStream);
- }
-
- if (mKeychainServiceListener.hasServiceStopped()) {
- arOutStream.close();
- return null;
- }
-
- arOutStream.close();
- }
-
- // For each secret masterKey id
- for (long secretKeyMasterId : secretKeyRingMasterIds) {
- progress++;
- // Create an output stream
- ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
- arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext));
-
- updateProgress(progress * 100 / masterKeyIdsSize, 100);
- PGPSecretKeyRing secretKeyRing =
- ProviderHelper.getPGPSecretKeyRing(mContext, secretKeyMasterId);
-
- if (secretKeyRing != null) {
- secretKeyRing.encode(arOutStream);
- }
- if (mKeychainServiceListener.hasServiceStopped()) {
- arOutStream.close();
- return null;
- }
-
- arOutStream.close();
- }
-
- returnData.putInt(KeychainIntentService.RESULT_EXPORT, masterKeyIdsSize);
-
- updateProgress(R.string.progress_done, 100, 100);
-
- return returnData;
- }
-
- /**
- * TODO: implement Id.return_value.updated as status when key already existed
- */
- @SuppressWarnings("unchecked")
- public int storeKeyRingInCache(PGPKeyRing keyring) {
- int status = Integer.MIN_VALUE; // out of bounds value (Id.return_value.*)
- 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 = Id.return_value.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) {
- ProviderHelper.saveKeyRing(mContext, newPubRing);
- }
- ProviderHelper.saveKeyRing(mContext, secretKeyRing);
- // TODO: remove status returns, use exceptions!
- status = Id.return_value.ok;
- }
- } else if (keyring instanceof PGPPublicKeyRing) {
- PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring;
- ProviderHelper.saveKeyRing(mContext, publicKeyRing);
- // TODO: remove status returns, use exceptions!
- status = Id.return_value.ok;
- }
- } catch (IOException e) {
- status = Id.return_value.error;
- }
-
- return status;
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
deleted file mode 100644
index 4c786f555..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java
+++ /dev/null
@@ -1,644 +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 android.content.Context;
-import android.graphics.Color;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.style.ForegroundColorSpan;
-
-import org.spongycastle.bcpg.sig.KeyFlags;
-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.PGPSignatureSubpacketVector;
-import org.spongycastle.util.encoders.Hex;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.util.IterableIterator;
-import org.sufficientlysecure.keychain.util.Log;
-
-import java.security.DigestException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.Vector;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class PgpKeyHelper {
-
- private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$");
-
- public static Date getCreationDate(PGPPublicKey key) {
- return key.getCreationTime();
- }
-
- public static Date getCreationDate(PGPSecretKey key) {
- return key.getPublicKey().getCreationTime();
- }
-
- @SuppressWarnings("unchecked")
- public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
- long cnt = 0;
- if (keyRing == null) {
- return null;
- }
- for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
- if (cnt == num) {
- return key;
- }
- cnt++;
- }
-
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) {
- Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>();
-
- for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) {
- if (isEncryptionKey(key)) {
- encryptKeys.add(key);
- }
- }
-
- return encryptKeys;
- }
-
- @SuppressWarnings("unchecked")
- public static Vector<PGPSecretKey> getSigningKeys(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
-
- for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
- if (isSigningKey(key)) {
- signingKeys.add(key);
- }
- }
-
- return signingKeys;
- }
-
- @SuppressWarnings("unchecked")
- public static Vector<PGPSecretKey> getCertificationKeys(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
-
- for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
- if (isCertificationKey(key)) {
- signingKeys.add(key);
- }
- }
-
- return signingKeys;
- }
-
- public static Vector<PGPPublicKey> getUsableEncryptKeys(PGPPublicKeyRing keyRing) {
- Vector<PGPPublicKey> usableKeys = new Vector<PGPPublicKey>();
- Vector<PGPPublicKey> 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;
- }
-
- public static boolean isExpired(PGPPublicKey key) {
- Date creationDate = getCreationDate(key);
- Date expiryDate = getExpiryDate(key);
- Date now = new Date();
- if (now.compareTo(creationDate) >= 0
- && (expiryDate == null || now.compareTo(expiryDate) <= 0)) {
- return false;
- }
- return true;
- }
-
- public static Vector<PGPSecretKey> getUsableCertificationKeys(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
- Vector<PGPSecretKey> signingKeys = getCertificationKeys(keyRing);
- PGPSecretKey masterKey = null;
- for (int i = 0; i < signingKeys.size(); ++i) {
- PGPSecretKey key = signingKeys.get(i);
- if (key.isMasterKey()) {
- masterKey = key;
- } else {
- usableKeys.add(key);
- }
- }
- if (masterKey != null) {
- usableKeys.add(masterKey);
- }
- return usableKeys;
- }
-
- public static Vector<PGPSecretKey> getUsableSigningKeys(PGPSecretKeyRing keyRing) {
- Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
- Vector<PGPSecretKey> signingKeys = getSigningKeys(keyRing);
- PGPSecretKey masterKey = null;
- for (int i = 0; i < signingKeys.size(); ++i) {
- PGPSecretKey key = signingKeys.get(i);
- if (key.isMasterKey()) {
- masterKey = key;
- } else {
- usableKeys.add(key);
- }
- }
- if (masterKey != null) {
- usableKeys.add(masterKey);
- }
- return usableKeys;
- }
-
- public static Date getExpiryDate(PGPPublicKey key) {
- Date creationDate = getCreationDate(key);
- if (key.getValidDays() == 0) {
- // no expiry
- return null;
- }
- Calendar calendar = GregorianCalendar.getInstance();
- calendar.setTime(creationDate);
- calendar.add(Calendar.DATE, key.getValidDays());
-
- return calendar.getTime();
- }
-
- public static Date getExpiryDate(PGPSecretKey key) {
- return getExpiryDate(key.getPublicKey());
- }
-
- public static PGPPublicKey getEncryptPublicKey(Context context, long masterKeyId) {
- PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRing(context, masterKeyId);
- if (keyRing == null) {
- Log.e(Constants.TAG, "keyRing is null!");
- return null;
- }
- Vector<PGPPublicKey> encryptKeys = getUsableEncryptKeys(keyRing);
- if (encryptKeys.size() == 0) {
- Log.e(Constants.TAG, "encryptKeys is null!");
- return null;
- }
- return encryptKeys.get(0);
- }
-
- public static PGPSecretKey getCertificationKey(Context context, long masterKeyId) {
- PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
- if (keyRing == null) {
- return null;
- }
- Vector<PGPSecretKey> signingKeys = getUsableCertificationKeys(keyRing);
- if (signingKeys.size() == 0) {
- return null;
- }
- return signingKeys.get(0);
- }
-
- public static PGPSecretKey getSigningKey(Context context, long masterKeyId) {
- PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
- if (keyRing == null) {
- return null;
- }
- Vector<PGPSecretKey> signingKeys = getUsableSigningKeys(keyRing);
- if (signingKeys.size() == 0) {
- return null;
- }
- return signingKeys.get(0);
- }
-
- @SuppressWarnings("unchecked")
- public static String getMainUserId(PGPPublicKey key) {
- for (String userId : new IterableIterator<String>(key.getUserIDs())) {
- return userId;
- }
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public static String getMainUserId(PGPSecretKey key) {
- for (String userId : new IterableIterator<String>(key.getUserIDs())) {
- return userId;
- }
- return null;
- }
-
- public static String getMainUserIdSafe(Context context, PGPPublicKey key) {
- String userId = getMainUserId(key);
- if (userId == null || userId.equals("")) {
- userId = context.getString(R.string.user_id_no_name);
- }
- return userId;
- }
-
- public static String getMainUserIdSafe(Context context, PGPSecretKey key) {
- String userId = getMainUserId(key);
- if (userId == null || userId.equals("")) {
- userId = context.getString(R.string.user_id_no_name);
- }
- return userId;
- }
-
- public static int getKeyUsage(PGPSecretKey key) {
- return getKeyUsage(key.getPublicKey());
- }
-
- @SuppressWarnings("unchecked")
- private static int getKeyUsage(PGPPublicKey key) {
- int usage = 0;
- if (key.getVersion() >= 4) {
- for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
- continue;
- }
-
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
- if (hashed != null) {
- usage |= hashed.getKeyFlags();
- }
-
- PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
- if (unhashed != null) {
- usage |= unhashed.getKeyFlags();
- }
- }
- }
- return usage;
- }
-
- @SuppressWarnings("unchecked")
- public 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<PGPSignature>(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;
- }
-
- public static boolean isEncryptionKey(PGPSecretKey key) {
- return isEncryptionKey(key.getPublicKey());
- }
-
- @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<PGPSignature>(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;
- }
-
- public static boolean isSigningKey(PGPSecretKey key) {
- return isSigningKey(key.getPublicKey());
- }
-
- @SuppressWarnings("unchecked")
- public static boolean isCertificationKey(PGPPublicKey key) {
- if (key.getVersion() <= 3) {
- return true;
- }
-
- for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
- continue;
- }
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
-
- if (hashed != null && (hashed.getKeyFlags() & KeyFlags.CERTIFY_OTHER) != 0) {
- return true;
- }
-
- PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
-
- if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.CERTIFY_OTHER) != 0) {
- return true;
- }
- }
-
- return false;
- }
-
- public static boolean isAuthenticationKey(PGPSecretKey key) {
- return isAuthenticationKey(key.getPublicKey());
- }
-
- @SuppressWarnings("unchecked")
- public static boolean isAuthenticationKey(PGPPublicKey key) {
- if (key.getVersion() <= 3) {
- return true;
- }
-
- for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
- if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
- continue;
- }
- PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
-
- if (hashed != null && (hashed.getKeyFlags() & KeyFlags.AUTHENTICATION) != 0) {
- return true;
- }
-
- PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
-
- if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.AUTHENTICATION) != 0) {
- return true;
- }
- }
-
- return false;
- }
-
- public static boolean isCertificationKey(PGPSecretKey key) {
- return isCertificationKey(key.getPublicKey());
- }
-
- public static String getAlgorithmInfo(PGPPublicKey key) {
- return getAlgorithmInfo(key.getAlgorithm(), key.getBitStrength());
- }
-
- public static String getAlgorithmInfo(PGPSecretKey key) {
- return getAlgorithmInfo(key.getPublicKey());
- }
-
- public static String getAlgorithmInfo(int algorithm, int keySize) {
- String algorithmStr;
-
- switch (algorithm) {
- case PGPPublicKey.RSA_ENCRYPT:
- case PGPPublicKey.RSA_GENERAL:
- case PGPPublicKey.RSA_SIGN: {
- algorithmStr = "RSA";
- break;
- }
- case PGPPublicKey.DSA: {
- algorithmStr = "DSA";
- break;
- }
-
- case PGPPublicKey.ELGAMAL_ENCRYPT:
- case PGPPublicKey.ELGAMAL_GENERAL: {
- algorithmStr = "ElGamal";
- break;
- }
-
- default: {
- algorithmStr = "Unknown";
- break;
- }
- }
- if(keySize > 0)
- return algorithmStr + ", " + keySize + " bit";
- else
- return algorithmStr;
- }
-
- /**
- * Converts fingerprint to hex (optional: with whitespaces after 4 characters)
- * <p/>
- * Fingerprint is shown using lowercase characters. Studies have shown that humans can
- * better differentiate between numbers and letters when letters are lowercase.
- *
- * @param fingerprint
- * @return
- */
- public static String convertFingerprintToHex(byte[] fingerprint) {
- String hexString = Hex.toHexString(fingerprint);
-
- return hexString;
- }
-
- /**
- * Convert key id from long to 64 bit hex string
- * <p/>
- * V4: "The Key ID is the low-order 64 bits of the fingerprint"
- * <p/>
- * see http://tools.ietf.org/html/rfc4880#section-12.2
- *
- * @param keyId
- * @return
- */
- public static String convertKeyIdToHex(long keyId) {
- long upper = keyId >> 32;
- if (upper == 0) {
- // this is a short key id
- return convertKeyIdToHexShort(keyId);
- }
- return "0x" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId);
- }
-
- public static String convertKeyIdToHexShort(long keyId) {
- return "0x" + convertKeyIdToHex32bit(keyId);
- }
-
- private static String convertKeyIdToHex32bit(long keyId) {
- String hexString = Long.toHexString(keyId & 0xffffffffL).toLowerCase(Locale.US);
- while (hexString.length() < 8) {
- hexString = "0" + hexString;
- }
- return hexString;
- }
-
-
- public static SpannableStringBuilder colorizeFingerprint(String fingerprint) {
- // split by 4 characters
- fingerprint = fingerprint.replaceAll("(.{4})(?!$)", "$1 ");
-
- // add line breaks to have a consistent "image" that can be recognized
- char[] chars = fingerprint.toCharArray();
- chars[24] = '\n';
- fingerprint = String.valueOf(chars);
-
- SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint);
- try {
- // for each 4 characters of the fingerprint + 1 space
- for (int i = 0; i < fingerprint.length(); i += 5) {
- int spanEnd = Math.min(i + 4, fingerprint.length());
- String fourChars = fingerprint.substring(i, spanEnd);
-
- int raw = Integer.parseInt(fourChars, 16);
- byte[] bytes = {(byte) ((raw >> 8) & 0xff - 128), (byte) (raw & 0xff - 128)};
- int[] color = getRgbForData(bytes);
- int r = color[0];
- int g = color[1];
- int b = color[2];
-
- // we cannot change black by multiplication, so adjust it to an almost-black grey,
- // which will then be brightened to the minimal brightness level
- if (r == 0 && g == 0 && b == 0) {
- r = 1;
- g = 1;
- b = 1;
- }
-
- // Convert rgb to brightness
- double brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b;
-
- // If a color is too dark to be seen on black,
- // then brighten it up to a minimal brightness.
- if (brightness < 80) {
- double factor = 80.0 / brightness;
- r = Math.min(255, (int) (r * factor));
- g = Math.min(255, (int) (g * factor));
- b = Math.min(255, (int) (b * factor));
-
- // If it is too light, then darken it to a respective maximal brightness.
- } else if (brightness > 180) {
- double factor = 180.0 / brightness;
- r = (int) (r * factor);
- g = (int) (g * factor);
- b = (int) (b * factor);
- }
-
- // Create a foreground color with the 3 digest integers as RGB
- // and then converting that int to hex to use as a color
- sb.setSpan(new ForegroundColorSpan(Color.rgb(r, g, b)),
- i, spanEnd, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
- }
- } catch (Exception e) {
- Log.e(Constants.TAG, "Colorization failed", e);
- // if anything goes wrong, then just display the fingerprint without colour,
- // instead of partially correct colour or wrong colours
- return new SpannableStringBuilder(fingerprint);
- }
-
- return sb;
- }
-
- /**
- * Converts the given bytes to a unique RGB color using SHA1 algorithm
- *
- * @param bytes
- * @return an integer array containing 3 numeric color representations (Red, Green, Black)
- * @throws java.security.NoSuchAlgorithmException
- * @throws java.security.DigestException
- */
- private static int[] getRgbForData(byte[] bytes) throws NoSuchAlgorithmException, DigestException {
- MessageDigest md = MessageDigest.getInstance("SHA1");
-
- md.update(bytes);
- byte[] digest = md.digest();
-
- int[] result = {((int) digest[0] + 256) % 256,
- ((int) digest[1] + 256) % 256,
- ((int) digest[2] + 256) % 256};
- return result;
- }
-
- /**
- * Splits userId string into naming part, email part, and comment part
- *
- * @param userId
- * @return array with naming (0), email (1), comment (2)
- */
- public static String[] splitUserId(String userId) {
- String[] result = new String[]{null, null, null};
-
- if (userId == null || userId.equals("")) {
- return result;
- }
-
- /*
- * User ID matching:
- * http://fiddle.re/t4p6f
- *
- * test cases:
- * "Max Mustermann (this is a comment) <max@example.com>"
- * "Max Mustermann <max@example.com>"
- * "Max Mustermann (this is a comment)"
- * "Max Mustermann [this is nothing]"
- */
- Matcher matcher = USER_ID_PATTERN.matcher(userId);
- if (matcher.matches()) {
- result[0] = matcher.group(1);
- result[1] = matcher.group(3);
- result[2] = matcher.group(2);
- }
-
- return result;
- }
-
-}
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
deleted file mode 100644
index 48b959738..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ /dev/null
@@ -1,769 +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 android.util.Pair;
-
-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.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.PgpGeneralMsgIdException;
-import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
-import org.sufficientlysecure.keychain.util.IterableIterator;
-import org.sufficientlysecure.keychain.util.Primes;
-import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-
-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.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 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(ProgressDialogUpdater progress) {
- super();
- this.mProgress = progress;
- }
-
- void updateProgress(int message, int current, int total) {
- if (mProgress != null) {
- mProgress.setProgress(message, current, total);
- }
- }
-
- void updateProgress(int current, int total) {
- if (mProgress != null) {
- mProgress.setProgress(current, total);
- }
- }
-
- /**
- * 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,
- PgpGeneralMsgIdException, InvalidAlgorithmParameterException {
-
- if (keySize < 512) {
- throw new PgpGeneralMsgIdException(R.string.error_key_size_minimum512bit);
- }
-
- if (passphrase == null) {
- passphrase = "";
- }
-
- int algorithm;
- KeyPairGenerator keyGen;
-
- 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 (isMasterKey) {
- 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);
- 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 PgpGeneralMsgIdException(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());
-
- return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
- sha1Calc, isMasterKey, keyEncryptor);
- }
-
- public PGPSecretKeyRing changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassphrase,
- String newPassphrase)
- throws IOException, 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()));
-
- return newKeyRing;
-
- }
-
- 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;
- 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();
-
- 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);
-
- 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();
-
- 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 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,
- // 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 + 40 * (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 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,
- // this happens anyway
- }
-
- keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate());
- }
-
- PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing();
- PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing();
-
- return new Pair<PGPSecretKeyRing, PGPPublicKeyRing>(secretKeyRing, publicKeyRing);
-
- }
-
- 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);
-
- if (saveParcel.oldPassphrase == null) {
- saveParcel.oldPassphrase = "";
- }
- if (saveParcel.newPassphrase == null) {
- saveParcel.newPassphrase = "";
- }
-
- if (mKR == null) {
- return buildNewSecretKey(saveParcel.userIDs, saveParcel.keys, saveParcel.keysExpiryDates,
- saveParcel.keysUsages, saveParcel.newPassphrase, saveParcel.oldPassphrase); //new Keyring
- }
-
- /*
- IDs - NB This might not need to happen later, if we change the way the primary ID is chosen
- remove deleted ids
- if the primary ID changed we need to:
- remove all of the IDs from the keyring, saving their certifications
- add them all in again, updating certs of IDs which have changed
- else
- remove changed IDs and add in with new certs
-
- if the master key changed, we need to remove the primary ID certification, so we can add
- the new one when it is generated, and they don't conflict
-
- Keys
- remove deleted keys
- if a key is modified, re-sign it
- do we need to remove and add in?
-
- Todo
- identify more things which need to be preserved - e.g. trust levels?
- user attributes
- */
-
- if (saveParcel.deletedKeys != null) {
- for (PGPSecretKey dKey : saveParcel.deletedKeys) {
- mKR = PGPSecretKeyRing.removeSecretKey(mKR, dKey);
- }
- }
-
- masterKey = mKR.getSecretKey();
- PGPPublicKey masterPublicKey = masterKey.getPublicKey();
-
- int usageId = saveParcel.keysUsages.get(0);
- boolean canSign;
- String mainUserId = saveParcel.userIDs.get(0);
-
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(saveParcel.oldPassphrase.toCharArray());
- PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor);
-
- updateProgress(R.string.progress_certifying_master_key, 20, 100);
-
- boolean anyIDChanged = false;
- for (String delID : saveParcel.deletedIDs) {
- anyIDChanged = true;
- masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, delID);
- }
-
- int userIDIndex = 0;
-
- 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 (saveParcel.keysExpiryDates.get(0) != null) {
- GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
- creationDate.setTime(masterPublicKey.getCreationTime());
- GregorianCalendar expiryDate = saveParcel.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 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,
- // this happens anyway
- }
-
- if (saveParcel.primaryIDChanged ||
- !saveParcel.originalIDs.get(0).equals(saveParcel.userIDs.get(0))) {
- anyIDChanged = true;
- ArrayList<Pair<String, PGPSignature>> sigList = new ArrayList<Pair<String, PGPSignature>>();
- for (String userId : saveParcel.userIDs) {
- String origID = saveParcel.originalIDs.get(userIDIndex);
- if (origID.equals(userId) && !saveParcel.newIDs[userIDIndex] &&
- !userId.equals(saveParcel.originalPrimaryID) && userIDIndex != 0) {
- Iterator<PGPSignature> origSigs = masterPublicKey.getSignaturesForID(origID);
- // TODO: make sure this iterator only has signatures we are interested in
- while (origSigs.hasNext()) {
- PGPSignature origSig = origSigs.next();
- sigList.add(new Pair<String, PGPSignature>(origID, origSig));
- }
- } else {
- 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);
- if (userIDIndex == 0) {
- sGen.setHashedSubpackets(hashedPacketsGen.generate());
- sGen.setUnhashedSubpackets(unhashedPacketsGen.generate());
- }
- PGPSignature certification = sGen.generateCertification(userId, masterPublicKey);
- sigList.add(new Pair<String, PGPSignature>(userId, certification));
- }
- if (!saveParcel.newIDs[userIDIndex]) {
- masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, origID);
- }
- userIDIndex++;
- }
- for (Pair<String, PGPSignature> toAdd : sigList) {
- masterPublicKey =
- PGPPublicKey.addCertification(masterPublicKey, toAdd.first, toAdd.second);
- }
- } else {
- for (String userId : saveParcel.userIDs) {
- String origID = saveParcel.originalIDs.get(userIDIndex);
- if (!origID.equals(userId) || saveParcel.newIDs[userIDIndex]) {
- anyIDChanged = true;
- 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);
- if (userIDIndex == 0) {
- sGen.setHashedSubpackets(hashedPacketsGen.generate());
- sGen.setUnhashedSubpackets(unhashedPacketsGen.generate());
- }
- PGPSignature certification = sGen.generateCertification(userId, masterPublicKey);
- if (!saveParcel.newIDs[userIDIndex]) {
- masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, origID);
- }
- masterPublicKey =
- PGPPublicKey.addCertification(masterPublicKey, userId, certification);
- }
- userIDIndex++;
- }
- }
-
- ArrayList<Pair<String, PGPSignature>> sigList = new ArrayList<Pair<String, PGPSignature>>();
- if (saveParcel.moddedKeys[0]) {
- userIDIndex = 0;
- for (String userId : saveParcel.userIDs) {
- String origID = saveParcel.originalIDs.get(userIDIndex);
- if (!(origID.equals(saveParcel.originalPrimaryID) && !saveParcel.primaryIDChanged)) {
- Iterator<PGPSignature> sigs = masterPublicKey.getSignaturesForID(userId);
- // TODO: make sure this iterator only has signatures we are interested in
- while (sigs.hasNext()) {
- PGPSignature sig = sigs.next();
- sigList.add(new Pair<String, PGPSignature>(userId, sig));
- }
- }
- masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, userId);
- userIDIndex++;
- }
- anyIDChanged = true;
- }
-
- //update the keyring with the new ID information
- if (anyIDChanged) {
- pKR = PGPPublicKeyRing.insertPublicKey(pKR, masterPublicKey);
- mKR = PGPSecretKeyRing.replacePublicKeys(mKR, pKR);
- }
-
- PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey);
-
- 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 encryptor based on old passphrase, as some keys may be unchanged
- PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- saveParcel.oldPassphrase.toCharArray());
-
- //this generates one more signature than necessary...
- PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION,
- masterKeyPair, mainUserId, sha1Calc, hashedPacketsGen.generate(),
- unhashedPacketsGen.generate(), certificationSignerBuilder, keyEncryptor);
-
- for (int i = 1; i < saveParcel.keys.size(); ++i) {
- updateProgress(40 + 50 * i / saveParcel.keys.size(), 100);
- if (saveParcel.moddedKeys[i]) {
- PGPSecretKey subKey = saveParcel.keys.get(i);
- PGPPublicKey subPublicKey = subKey.getPublicKey();
-
- PBESecretKeyDecryptor keyDecryptor2;
- if (saveParcel.newKeys[i]) {
- keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- "".toCharArray());
- } else {
- keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- saveParcel.oldPassphrase.toCharArray());
- }
- PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2);
- PGPKeyPair subKeyPair = new PGPKeyPair(subPublicKey, subPrivateKey);
-
- hashedPacketsGen = new PGPSignatureSubpacketGenerator();
- unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
-
- usageId = saveParcel.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 (saveParcel.keysExpiryDates.get(i) != null) {
- GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
- creationDate.setTime(subPublicKey.getCreationTime());
- GregorianCalendar expiryDate = saveParcel.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 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,
- // this happens anyway
- }
-
- keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate());
- // certifications will be discarded if the key is changed, because I think, for a start,
- // they will be invalid. Binding certs are regenerated anyway, and other certs which
- // need to be kept are on IDs and attributes
- // TODO: don't let revoked keys be edited, other than removed - changing one would
- // result in the revocation being wrong?
- }
- }
-
- PGPSecretKeyRing updatedSecretKeyRing = keyGen.generateSecretKeyRing();
- //finally, update the keyrings
- Iterator<PGPSecretKey> itr = updatedSecretKeyRing.getSecretKeys();
- while (itr.hasNext()) {
- PGPSecretKey theNextKey = itr.next();
- if ((theNextKey.isMasterKey() && saveParcel.moddedKeys[0]) || !theNextKey.isMasterKey()) {
- mKR = PGPSecretKeyRing.insertSecretKey(mKR, theNextKey);
- pKR = PGPPublicKeyRing.insertPublicKey(pKR, theNextKey.getPublicKey());
- }
- }
-
- //replace lost IDs
- if (saveParcel.moddedKeys[0]) {
- masterPublicKey = mKR.getPublicKey();
- for (Pair<String, PGPSignature> toAdd : sigList) {
- masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, toAdd.first, toAdd.second);
- }
- pKR = PGPPublicKeyRing.insertPublicKey(pKR, masterPublicKey);
- mKR = PGPSecretKeyRing.replacePublicKeys(mKR, pKR);
- }
-
- // Build key encryptor based on new passphrase
- PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- saveParcel.newPassphrase.toCharArray());
-
- //update the passphrase
- mKR = PGPSecretKeyRing.copyWithNewPassword(mKR, keyDecryptor, keyEncryptorNew);
-
- /* additional handy debug info
-
- Log.d(Constants.TAG, " ------- in private key -------");
-
- for(String uid : new IterableIterator<String>(secretKeyRing.getPublicKey().getUserIDs())) {
- for(PGPSignature sig : new IterableIterator<PGPSignature>(
- secretKeyRing.getPublicKey().getSignaturesForID(uid))) {
- Log.d(Constants.TAG, "sig: " +
- PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid);
- }
-
- }
-
- Log.d(Constants.TAG, " ------- in public key -------");
-
- for(String uid : new IterableIterator<String>(publicKeyRing.getPublicKey().getUserIDs())) {
- for(PGPSignature sig : new IterableIterator<PGPSignature>(
- publicKeyRing.getPublicKey().getSignaturesForID(uid))) {
- Log.d(Constants.TAG, "sig: " +
- PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid);
- }
- }
-
- */
-
- return new Pair<PGPSecretKeyRing, PGPPublicKeyRing>(mKR, pKR);
-
- }
-
- /**
- * 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_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 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.
- *
- * 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;
- }
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
deleted file mode 100644
index a864a165d..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 android.content.Context;
-
-import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.bcpg.BCPGOutputStream;
-import org.spongycastle.openpgp.PGPCompressedDataGenerator;
-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.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.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.util.InputData;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.SignatureException;
-import java.util.Date;
-
-/**
- * This class uses a Builder pattern!
- */
-public class PgpSignEncrypt {
- private Context mContext;
- private InputData mData;
- private OutputStream mOutStream;
-
- private ProgressDialogUpdater mProgress;
- private boolean mEnableAsciiArmorOutput;
- private int mCompressionId;
- private long[] mEncryptionKeyIds;
- private String mSymmetricPassphrase;
- private int mSymmetricEncryptionAlgorithm;
- private long mSignatureKeyId;
- private int mSignatureHashAlgorithm;
- private boolean mSignatureForceV3;
- private String mSignaturePassphrase;
-
- private PgpSignEncrypt(Builder builder) {
- // private Constructor can only be called from Builder
- this.mContext = builder.mContext;
- this.mData = builder.mData;
- this.mOutStream = builder.mOutStream;
-
- this.mProgress = builder.mProgress;
- this.mEnableAsciiArmorOutput = builder.mEnableAsciiArmorOutput;
- this.mCompressionId = builder.mCompressionId;
- this.mEncryptionKeyIds = builder.mEncryptionKeyIds;
- this.mSymmetricPassphrase = builder.mSymmetricPassphrase;
- this.mSymmetricEncryptionAlgorithm = builder.mSymmetricEncryptionAlgorithm;
- this.mSignatureKeyId = builder.mSignatureKeyId;
- this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
- this.mSignatureForceV3 = builder.mSignatureForceV3;
- this.mSignaturePassphrase = builder.mSignaturePassphrase;
- }
-
- public static class Builder {
- // mandatory parameter
- private Context mContext;
- private InputData mData;
- private OutputStream mOutStream;
-
- // optional
- private ProgressDialogUpdater mProgress = null;
- private boolean mEnableAsciiArmorOutput = false;
- private int mCompressionId = Id.choice.compression.none;
- private long[] mEncryptionKeyIds = null;
- private String mSymmetricPassphrase = null;
- private int mSymmetricEncryptionAlgorithm = 0;
- private long mSignatureKeyId = Id.key.none;
- private int mSignatureHashAlgorithm = 0;
- private boolean mSignatureForceV3 = false;
- private String mSignaturePassphrase = null;
-
- public Builder(Context context, InputData data, OutputStream outStream) {
- this.mContext = context;
- this.mData = data;
- this.mOutStream = outStream;
- }
-
- public Builder progress(ProgressDialogUpdater progress) {
- this.mProgress = progress;
- return this;
- }
-
- public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
- this.mEnableAsciiArmorOutput = enableAsciiArmorOutput;
- return this;
- }
-
- public Builder compressionId(int compressionId) {
- this.mCompressionId = compressionId;
- return this;
- }
-
- public Builder encryptionKeyIds(long[] encryptionKeyIds) {
- this.mEncryptionKeyIds = encryptionKeyIds;
- return this;
- }
-
- public Builder symmetricPassphrase(String symmetricPassphrase) {
- this.mSymmetricPassphrase = symmetricPassphrase;
- return this;
- }
-
- public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
- this.mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
- return this;
- }
-
- public Builder signatureKeyId(long signatureKeyId) {
- this.mSignatureKeyId = signatureKeyId;
- return this;
- }
-
- public Builder signatureHashAlgorithm(int signatureHashAlgorithm) {
- this.mSignatureHashAlgorithm = signatureHashAlgorithm;
- return this;
- }
-
- public Builder signatureForceV3(boolean signatureForceV3) {
- this.mSignatureForceV3 = signatureForceV3;
- return this;
- }
-
- public Builder signaturePassphrase(String signaturePassphrase) {
- this.mSignaturePassphrase = signaturePassphrase;
- return this;
- }
-
- public PgpSignEncrypt build() {
- return new PgpSignEncrypt(this);
- }
- }
-
- 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);
- }
- }
-
- /**
- * Signs and/or encrypts data based on parameters of class
- *
- * @throws IOException
- * @throws PgpGeneralException
- * @throws PGPException
- * @throws NoSuchProviderException
- * @throws NoSuchAlgorithmException
- * @throws SignatureException
- */
- public void execute()
- throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
- NoSuchAlgorithmException, SignatureException {
-
- boolean enableSignature = mSignatureKeyId != Id.key.none;
- boolean enableEncryption = ((mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0)
- || mSymmetricPassphrase != null);
- boolean enableCompression = (enableEncryption && mCompressionId != Id.choice.compression.none);
-
- Log.d(Constants.TAG, "enableSignature:" + enableSignature
- + "\nenableEncryption:" + enableEncryption
- + "\nenableCompression:" + enableCompression
- + "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput);
-
- int signatureType;
- if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
- // for sign-only ascii text
- signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
- } else {
- signatureType = PGPSignature.BINARY_DOCUMENT;
- }
-
- ArmoredOutputStream armorOut = null;
- OutputStream out;
- if (mEnableAsciiArmorOutput) {
- armorOut = new ArmoredOutputStream(mOutStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
- out = armorOut;
- } else {
- out = mOutStream;
- }
-
- /* Get keys for signature generation for later usage */
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
- if (enableSignature) {
- signingKeyRing = ProviderHelper.getPGPSecretKeyRingWithKeyId(mContext, mSignatureKeyId);
- signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId);
- if (signingKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
- }
-
- if (mSignaturePassphrase == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_no_signature_passphrase));
- }
-
- 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) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_could_not_extract_private_key));
- }
- }
- updateProgress(R.string.progress_preparing_streams, 5, 100);
-
- /* Initialize PGPEncryptedDataGenerator for later usage */
- PGPEncryptedDataGenerator cPk = null;
- if (enableEncryption) {
- // has Integrity packet enabled!
- JcePGPDataEncryptorBuilder encryptorBuilder =
- new JcePGPDataEncryptorBuilder(mSymmetricEncryptionAlgorithm)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
- .setWithIntegrityPacket(true);
-
- cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
-
- if (mSymmetricPassphrase != null) {
- // Symmetric encryption
- Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
-
- JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
- new JcePBEKeyEncryptionMethodGenerator(mSymmetricPassphrase.toCharArray());
- cPk.addMethod(symmetricEncryptionGenerator);
- } else {
- // Asymmetric encryption
- for (long id : mEncryptionKeyIds) {
- PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
- if (key != null) {
- JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
- new JcePublicKeyKeyEncryptionMethodGenerator(key);
- cPk.addMethod(pubKeyEncryptionGenerator);
- }
- }
- }
- }
-
- /* Initialize signature generator object for later usage */
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
- 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);
-
- if (mSignatureForceV3) {
- signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
- signatureV3Generator.init(signatureType, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- signatureGenerator.init(signatureType, signaturePrivateKey);
-
- String userId = PgpKeyHelper.getMainUserId(signingKeyRing.getSecretKey());
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
- }
-
- PGPCompressedDataGenerator compressGen = null;
- OutputStream pOut;
- OutputStream encryptionOut = null;
- BCPGOutputStream bcpgOut;
- if (enableEncryption) {
- /* actual encryption */
-
- encryptionOut = cPk.open(out, new byte[1 << 16]);
-
- if (enableCompression) {
- compressGen = new PGPCompressedDataGenerator(mCompressionId);
- bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
- } else {
- bcpgOut = new BCPGOutputStream(encryptionOut);
- }
-
- if (enableSignature) {
- if (mSignatureForceV3) {
- signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
- } else {
- signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
- }
- }
-
- PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
- // file name not needed, so empty string
- pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
- new byte[1 << 16]);
- updateProgress(R.string.progress_encrypting, 20, 100);
-
- long progress = 0;
- int n;
- byte[] buffer = new byte[1 << 16];
- InputStream in = mData.getInputStream();
- while ((n = in.read(buffer)) > 0) {
- pOut.write(buffer, 0, n);
-
- // update signature buffer if signature is requested
- if (enableSignature) {
- if (mSignatureForceV3) {
- signatureV3Generator.update(buffer, 0, n);
- } else {
- signatureGenerator.update(buffer, 0, n);
- }
- }
-
- progress += n;
- if (mData.getSize() != 0) {
- updateProgress((int) (20 + (95 - 20) * progress / mData.getSize()), 100);
- }
- }
-
- literalGen.close();
- } else if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
- /* sign-only of ascii text */
-
- updateProgress(R.string.progress_signing, 40, 100);
-
- // write directly on armor output stream
- armorOut.beginClearText(mSignatureHashAlgorithm);
-
- InputStream in = mData.getInputStream();
- final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
-
- final byte[] newline = "\r\n".getBytes("UTF-8");
-
- if (mSignatureForceV3) {
- processLine(reader.readLine(), armorOut, signatureV3Generator);
- } else {
- processLine(reader.readLine(), armorOut, signatureGenerator);
- }
-
- while (true) {
- String line = reader.readLine();
-
- if (line == null) {
- armorOut.write(newline);
- break;
- }
-
- armorOut.write(newline);
-
- // update signature buffer with input line
- if (mSignatureForceV3) {
- signatureV3Generator.update(newline);
- processLine(line, armorOut, signatureV3Generator);
- } else {
- signatureGenerator.update(newline);
- processLine(line, armorOut, signatureGenerator);
- }
- }
-
- armorOut.endClearText();
-
- pOut = new BCPGOutputStream(armorOut);
- } else {
- // TODO: implement sign-only for files!
- pOut = null;
- Log.e(Constants.TAG, "not supported!");
- }
-
- if (enableSignature) {
- updateProgress(R.string.progress_generating_signature, 95, 100);
- if (mSignatureForceV3) {
- signatureV3Generator.generate().encode(pOut);
- } else {
- signatureGenerator.generate().encode(pOut);
- }
- }
-
- // closing outputs
- // NOTE: closing needs to be done in the correct order!
- // TODO: closing bcpgOut and pOut???
- if (enableEncryption) {
- if (enableCompression) {
- compressGen.close();
- }
-
- encryptionOut.close();
- }
- if (mEnableAsciiArmorOutput) {
- armorOut.close();
- }
-
- out.close();
- mOutStream.close();
-
- updateProgress(R.string.progress_done, 100, 100);
- }
-
- // TODO: merge this into execute method!
- // TODO: allow binary input for this class
- public void generateSignature()
- throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
- SignatureException {
-
- OutputStream out;
- if (mEnableAsciiArmorOutput) {
- // Ascii Armor (Radix-64)
- ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
- out = armorOut;
- } else {
- out = mOutStream;
- }
-
- if (mSignatureKeyId == 0) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
- }
-
- PGPSecretKeyRing signingKeyRing =
- ProviderHelper.getPGPSecretKeyRingWithKeyId(mContext, mSignatureKeyId);
- PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId);
- if (signingKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
- }
-
- if (mSignaturePassphrase == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
- }
-
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
- PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
- if (signaturePrivateKey == null) {
- throw new PgpGeneralException(
- mContext.getString(R.string.error_could_not_extract_private_key));
- }
- updateProgress(R.string.progress_preparing_streams, 0, 100);
-
- updateProgress(R.string.progress_preparing_signature, 30, 100);
-
- int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
-// if (binary) {
-// type = PGPSignature.BINARY_DOCUMENT;
-// }
-
- // 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);
-
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
- if (mSignatureForceV3) {
- signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
- signatureV3Generator.init(type, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- signatureGenerator.init(type, signaturePrivateKey);
-
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- String userId = PgpKeyHelper.getMainUserId(signingKeyRing.getSecretKey());
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
-
- updateProgress(R.string.progress_signing, 40, 100);
-
- InputStream inStream = mData.getInputStream();
-// if (binary) {
-// byte[] buffer = new byte[1 << 16];
-// int n = 0;
-// while ((n = inStream.read(buffer)) > 0) {
-// if (signatureForceV3) {
-// signatureV3Generator.update(buffer, 0, n);
-// } else {
-// signatureGenerator.update(buffer, 0, n);
-// }
-// }
-// } else {
- final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
- final byte[] newline = "\r\n".getBytes("UTF-8");
-
- String line;
- while ((line = reader.readLine()) != null) {
- if (mSignatureForceV3) {
- processLine(line, null, signatureV3Generator);
- signatureV3Generator.update(newline);
- } else {
- processLine(line, null, signatureGenerator);
- signatureGenerator.update(newline);
- }
- }
-// }
-
- BCPGOutputStream bOut = new BCPGOutputStream(out);
- if (mSignatureForceV3) {
- signatureV3Generator.generate().encode(bOut);
- } else {
- signatureGenerator.generate().encode(bOut);
- }
- out.close();
- mOutStream.close();
-
- updateProgress(R.string.progress_done, 100, 100);
- }
-
-
- private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
- final PGPSignatureGenerator pSignatureGenerator)
- throws IOException, SignatureException {
-
- if (pLine == null) {
- return;
- }
-
- final char[] chars = pLine.toCharArray();
- int len = chars.length;
-
- while (len > 0) {
- if (!Character.isWhitespace(chars[len - 1])) {
- break;
- }
- len--;
- }
-
- final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
-
- if (pArmoredOutput != null) {
- pArmoredOutput.write(data);
- }
- pSignatureGenerator.update(data);
- }
-
- private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
- final PGPV3SignatureGenerator pSignatureGenerator)
- throws IOException, SignatureException {
-
- if (pLine == null) {
- return;
- }
-
- final char[] chars = pLine.toCharArray();
- int len = chars.length;
-
- while (len > 0) {
- if (!Character.isWhitespace(chars[len - 1])) {
- break;
- }
- len--;
- }
-
- final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
-
- if (pArmoredOutput != null) {
- pArmoredOutput.write(data);
- }
- pSignatureGenerator.update(data);
- }
-
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java
deleted file mode 100644
index 5bb1665b6..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 org.spongycastle.asn1.DERObjectIdentifier;
-import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
-import org.spongycastle.asn1.x509.BasicConstraints;
-import org.spongycastle.asn1.x509.GeneralName;
-import org.spongycastle.asn1.x509.GeneralNames;
-import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
-import org.spongycastle.asn1.x509.X509Extensions;
-import org.spongycastle.asn1.x509.X509Name;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.x509.X509V3CertificateGenerator;
-import org.spongycastle.x509.extension.AuthorityKeyIdentifierStructure;
-import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.util.Log;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.SignatureException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.text.DateFormat;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.Vector;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-public class PgpToX509 {
- public static final String DN_COMMON_PART_O = "OpenPGP to X.509 Bridge";
- public static final String DN_COMMON_PART_OU = "OpenPGP Keychain cert";
-
- /**
- * Creates a self-signed certificate from a public and private key. The (critical) key-usage
- * extension is set up with: digital signature, non-repudiation, key-encipherment, key-agreement
- * and certificate-signing. The (non-critical) Netscape extension is set up with: SSL client and
- * S/MIME. A URI subjectAltName may also be set up.
- *
- * @param pubKey public key
- * @param privKey private key
- * @param subject subject (and issuer) DN for this certificate, RFC 2253 format preferred.
- * @param startDate date from which the certificate will be valid (defaults to current date and time
- * if null)
- * @param endDate date until which the certificate will be valid (defaults to current date and time
- * if null) *
- * @param subjAltNameURI URI to be placed in subjectAltName
- * @return self-signed certificate
- * @throws InvalidKeyException
- * @throws SignatureException
- * @throws NoSuchAlgorithmException
- * @throws IllegalStateException
- * @throws NoSuchProviderException
- * @throws CertificateException
- * @throws Exception
- * @author Bruno Harbulot
- */
- public static X509Certificate createSelfSignedCert(
- PublicKey pubKey, PrivateKey privKey, X509Name subject, Date startDate, Date endDate,
- String subjAltNameURI)
- throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException,
- SignatureException, CertificateException, NoSuchProviderException {
-
- X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
-
- certGenerator.reset();
- /*
- * Sets up the subject distinguished name. Since it's a self-signed certificate, issuer and
- * subject are the same.
- */
- certGenerator.setIssuerDN(subject);
- certGenerator.setSubjectDN(subject);
-
- /*
- * Sets up the validity dates.
- */
- if (startDate == null) {
- startDate = new Date(System.currentTimeMillis());
- }
- certGenerator.setNotBefore(startDate);
- if (endDate == null) {
- endDate = new Date(startDate.getTime() + (365L * 24L * 60L * 60L * 1000L));
- Log.d(Constants.TAG, "end date is=" + DateFormat.getDateInstance().format(endDate));
- }
-
- certGenerator.setNotAfter(endDate);
-
- /*
- * The serial-number of this certificate is 1. It makes sense because it's self-signed.
- */
- certGenerator.setSerialNumber(BigInteger.ONE);
- /*
- * Sets the public-key to embed in this certificate.
- */
- certGenerator.setPublicKey(pubKey);
- /*
- * Sets the signature algorithm.
- */
- String pubKeyAlgorithm = pubKey.getAlgorithm();
- if (pubKeyAlgorithm.equals("DSA")) {
- certGenerator.setSignatureAlgorithm("SHA1WithDSA");
- } else if (pubKeyAlgorithm.equals("RSA")) {
- certGenerator.setSignatureAlgorithm("SHA1WithRSAEncryption");
- } else {
- RuntimeException re = new RuntimeException("Algorithm not recognised: "
- + pubKeyAlgorithm);
- Log.e(Constants.TAG, re.getMessage(), re);
- throw re;
- }
-
- /*
- * Adds the Basic Constraint (CA: true) extension.
- */
- certGenerator.addExtension(X509Extensions.BasicConstraints, true,
- new BasicConstraints(true));
-
- /*
- * Adds the subject key identifier extension.
- */
- SubjectKeyIdentifier subjectKeyIdentifier = new SubjectKeyIdentifierStructure(pubKey);
- certGenerator
- .addExtension(X509Extensions.SubjectKeyIdentifier, false, subjectKeyIdentifier);
-
- /*
- * Adds the authority key identifier extension.
- */
- AuthorityKeyIdentifier authorityKeyIdentifier = new AuthorityKeyIdentifierStructure(pubKey);
- certGenerator.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
- authorityKeyIdentifier);
-
- /*
- * Adds the subject alternative-name extension.
- */
- if (subjAltNameURI != null) {
- GeneralNames subjectAltNames = new GeneralNames(new GeneralName(
- GeneralName.uniformResourceIdentifier, subjAltNameURI));
- certGenerator.addExtension(X509Extensions.SubjectAlternativeName, false,
- subjectAltNames);
- }
-
- /*
- * Creates and sign this certificate with the private key corresponding to the public key of
- * the certificate (hence the name "self-signed certificate").
- */
- X509Certificate cert = certGenerator.generate(privKey);
-
- /*
- * Checks that this certificate has indeed been correctly signed.
- */
- cert.verify(pubKey);
-
- return cert;
- }
-
- /**
- * Creates a self-signed certificate from a PGP Secret Key.
- *
- * @param pgpSecKey PGP Secret Key (from which one can extract the public and private
- * keys and other attributes).
- * @param pgpPrivKey PGP Private Key corresponding to the Secret Key (password callbacks
- * should be done before calling this method)
- * @param subjAltNameURI optional URI to embed in the subject alternative-name
- * @return self-signed certificate
- * @throws PGPException
- * @throws NoSuchProviderException
- * @throws InvalidKeyException
- * @throws NoSuchAlgorithmException
- * @throws SignatureException
- * @throws CertificateException
- * @author Bruno Harbulot
- */
- public static X509Certificate createSelfSignedCert(
- PGPSecretKey pgpSecKey, PGPPrivateKey pgpPrivKey, String subjAltNameURI)
- throws PGPException, NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException,
- SignatureException, CertificateException {
- // get public key from secret key
- PGPPublicKey pgpPubKey = pgpSecKey.getPublicKey();
-
- // LOGGER.info("Key ID: " + Long.toHexString(pgpPubKey.getKeyID() & 0xffffffffL));
-
- /*
- * The X.509 Name to be the subject DN is prepared. The CN is extracted from the Secret Key
- * user ID.
- */
- Vector<DERObjectIdentifier> x509NameOids = new Vector<DERObjectIdentifier>();
- Vector<String> x509NameValues = new Vector<String>();
-
- x509NameOids.add(X509Name.O);
- x509NameValues.add(DN_COMMON_PART_O);
-
- x509NameOids.add(X509Name.OU);
- x509NameValues.add(DN_COMMON_PART_OU);
-
- for (@SuppressWarnings("unchecked")
- Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserIDs(); it.hasNext(); ) {
- Object attrib = it.next();
- x509NameOids.add(X509Name.CN);
- x509NameValues.add("CryptoCall");
- // x509NameValues.add(attrib.toString());
- }
-
- /*
- * Currently unused.
- */
- Log.d(Constants.TAG, "User attributes: ");
- for (@SuppressWarnings("unchecked")
- Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserAttributes(); it.hasNext(); ) {
- Object attrib = it.next();
- Log.d(Constants.TAG, " - " + attrib + " -- " + attrib.getClass());
- }
-
- X509Name x509name = new X509Name(x509NameOids, x509NameValues);
-
- Log.d(Constants.TAG, "Subject DN: " + x509name);
-
- /*
- * To check the signature from the certificate on the recipient side, the creation time
- * needs to be embedded in the certificate. It seems natural to make this creation time be
- * the "not-before" date of the X.509 certificate. Unlimited PGP keys have a validity of 0
- * second. In this case, the "not-after" date will be the same as the not-before date. This
- * is something that needs to be checked by the service receiving this certificate.
- */
- Date creationTime = pgpPubKey.getCreationTime();
- Log.d(Constants.TAG,
- "pgp pub key creation time=" + DateFormat.getDateInstance().format(creationTime));
- Log.d(Constants.TAG, "pgp valid seconds=" + pgpPubKey.getValidSeconds());
- Date validTo = null;
- if (pgpPubKey.getValidSeconds() > 0) {
- validTo = new Date(creationTime.getTime() + 1000L * pgpPubKey.getValidSeconds());
- }
-
- X509Certificate selfSignedCert = createSelfSignedCert(
- pgpPubKey.getKey(Constants.BOUNCY_CASTLE_PROVIDER_NAME), pgpPrivKey.getKey(),
- x509name, creationTime, validTo, subjAltNameURI);
-
- return selfSignedCert;
- }
-
- /**
- * This is a password callback handler that will fill in a password automatically. Useful to
- * configure passwords in advance, but should be used with caution depending on how much you
- * allow passwords to be stored within your application.
- *
- * @author Bruno Harbulot.
- */
- public static final class PredefinedPasswordCallbackHandler implements CallbackHandler {
-
- private char[] mPassword;
- private String mPrompt;
-
- public PredefinedPasswordCallbackHandler(String password) {
- this(password == null ? null : password.toCharArray(), null);
- }
-
- public PredefinedPasswordCallbackHandler(char[] password) {
- this(password, null);
- }
-
- public PredefinedPasswordCallbackHandler(String password, String prompt) {
- this(password == null ? null : password.toCharArray(), prompt);
- }
-
- public PredefinedPasswordCallbackHandler(char[] password, String prompt) {
- this.mPassword = password;
- this.mPrompt = prompt;
- }
-
- public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
- for (Callback callback : callbacks) {
- if (callback instanceof PasswordCallback) {
- PasswordCallback pwCallback = (PasswordCallback) callback;
- if ((this.mPrompt == null) || (this.mPrompt.equals(pwCallback.getPrompt()))) {
- pwCallback.setPassword(this.mPassword);
- }
- } else {
- throw new UnsupportedCallbackException(callback, "Unrecognised callback.");
- }
- }
- }
-
- protected final Object clone() throws CloneNotSupportedException {
- throw new CloneNotSupportedException();
- }
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java
deleted file mode 100644
index 23c4bbbd9..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java
+++ /dev/null
@@ -1,26 +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.exception;
-
-public class NoAsymmetricEncryptionException extends Exception {
- static final long serialVersionUID = 0xf812773343L;
-
- public NoAsymmetricEncryptionException() {
- super();
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java
deleted file mode 100644
index 418445367..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java
+++ /dev/null
@@ -1,29 +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.exception;
-
-public class PgpGeneralException extends Exception {
- static final long serialVersionUID = 0xf812773342L;
-
- public PgpGeneralException(String message) {
- super(message);
- }
- public PgpGeneralException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java
deleted file mode 100644
index caa7842db..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java
+++ /dev/null
@@ -1,35 +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.exception;
-
-import android.content.Context;
-
-public class PgpGeneralMsgIdException extends Exception {
- static final long serialVersionUID = 0xf812773343L;
-
- private final int mMessageId;
-
- public PgpGeneralMsgIdException(int messageId) {
- super("msg[" + messageId + "]");
- mMessageId = messageId;
- }
-
- public PgpGeneralException getContextualized(Context context) {
- return new PgpGeneralException(context.getString(mMessageId), this);
- }
-}