aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src/main/java')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationIncoming.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperation.java)480
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java584
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java49
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java40
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java4
5 files changed, 672 insertions, 485 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationIncoming.java
index 50db814e3..c57691f8d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperation.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationIncoming.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * 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");
@@ -17,37 +17,16 @@
package org.sufficientlysecure.keychain.pgp;
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-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;
-import java.util.Iterator;
+import android.content.Context;
+import android.os.Bundle;
import org.spongycastle.bcpg.ArmoredInputStream;
-import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.bcpg.BCPGInputStream;
-import org.spongycastle.bcpg.BCPGOutputStream;
-
-import org.spongycastle.bcpg.SignaturePacket;
-
-import org.spongycastle.bcpg.SignatureSubpacket;
import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.openpgp.PGPCompressedData;
-import org.spongycastle.openpgp.PGPCompressedDataGenerator;
import org.spongycastle.openpgp.PGPEncryptedData;
-import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
import org.spongycastle.openpgp.PGPEncryptedDataList;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPLiteralData;
-import org.spongycastle.openpgp.PGPLiteralDataGenerator;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPOnePassSignature;
import org.spongycastle.openpgp.PGPOnePassSignatureList;
@@ -57,29 +36,20 @@ 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.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureList;
-import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.PGPUtil;
-import org.spongycastle.openpgp.PGPV3SignatureGenerator;
import org.spongycastle.openpgp.operator.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.JcaPGPContentSignerBuilder;
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.JcePBEKeyEncryptionMethodGenerator;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
-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;
@@ -88,17 +58,26 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
-import android.content.Context;
-import android.os.Bundle;
+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.Iterator;
-public class PgpOperation {
+/**
+ * TODO: make builder pattern like in PgpOperationOutgoing
+ */
+public class PgpOperationIncoming {
private Context mContext;
private ProgressDialogUpdater mProgress;
private InputData mData;
private OutputStream mOutStream;
- public PgpOperation(Context context, ProgressDialogUpdater progress, InputData data,
- OutputStream outStream) {
+ public PgpOperationIncoming(Context context, ProgressDialogUpdater progress, InputData data,
+ OutputStream outStream) {
super();
this.mContext = context;
this.mProgress = progress;
@@ -118,361 +97,6 @@ public class PgpOperation {
}
}
- public void signAndEncrypt(boolean enableAsciiArmorOutput, int compressionId, long[] encryptionKeyIds,
- String encryptionPassphrase, int symmetricEncryptionAlgorithm,
- long signatureKeyId, int signatureHashAlgorithm,
- boolean signatureForceV3, String signaturePassphrase)
- throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
- NoSuchAlgorithmException, SignatureException {
-
- if (encryptionKeyIds == null) {
- encryptionKeyIds = new long[0];
- }
-
- boolean enableSignature = signatureKeyId != Id.key.none;
- boolean enableCompression = compressionId == Id.choice.compression.none;
- boolean enableEncryption = encryptionKeyIds.length != 0 || encryptionPassphrase != null;
-
- int signatureType;
- // TODO: disable when encrypting???
- if (enableAsciiArmorOutput && enableSignature && !enableEncryption) {
- signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
- } else {
- signatureType = PGPSignature.BINARY_DOCUMENT;
- }
-
- ArmoredOutputStream armorOut = null;
- OutputStream out;
- OutputStream encryptionOut = null;
- if (enableAsciiArmorOutput) {
- armorOut = new ArmoredOutputStream(mOutStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
- out = armorOut;
- } else {
- out = mOutStream;
- }
-
-
- PGPSecretKey signingKey = null;
- PGPSecretKeyRing signingKeyRing = null;
- PGPPrivateKey signaturePrivateKey = null;
- if (enableSignature) {
- signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
- signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
- if (signingKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
- }
-
- if (signaturePassphrase == 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(signaturePassphrase.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);
-
- // encrypt and compress input file content
- if (enableEncryption) {
- // has Integrity packet enabled!
- JcePGPDataEncryptorBuilder encryptorBuilder =
- new JcePGPDataEncryptorBuilder(symmetricEncryptionAlgorithm)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
- .setWithIntegrityPacket(true);
-
- PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
-
- if (encryptionKeyIds.length == 0) {
- // Symmetric encryption
- Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
-
- JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
- new JcePBEKeyEncryptionMethodGenerator(encryptionPassphrase.toCharArray());
- cPk.addMethod(symmetricEncryptionGenerator);
- } else {
- // Asymmetric encryption
- for (long id : encryptionKeyIds) {
- PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
- if (key != null) {
-
- JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
- new JcePublicKeyKeyEncryptionMethodGenerator(key);
- cPk.addMethod(pubKeyEncryptionGenerator);
- }
- }
- }
- encryptionOut = cPk.open(out, new byte[1 << 16]);
- }
-
- 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(), signatureHashAlgorithm)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- if (signatureForceV3) {
- signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
- signatureV3Generator.init(signatureType, signaturePrivateKey);
- } else {
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- signatureGenerator.init(signatureType, signaturePrivateKey);
-
- String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- spGen.setSignerUserID(false, userId);
- signatureGenerator.setHashedSubpackets(spGen.generate());
- }
- }
-
- PGPCompressedDataGenerator compressGen = null;
- OutputStream pOut;
- if (enableEncryption) {
- BCPGOutputStream bcpgOut;
- if (enableCompression) {
- compressGen = new PGPCompressedDataGenerator(compressionId);
- bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
- } else {
- bcpgOut = new BCPGOutputStream(encryptionOut);
- }
-
- if (enableSignature) {
- if (signatureForceV3) {
- 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 (signatureForceV3) {
- 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 (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
- /* sign-only of ascii text */
-
- updateProgress(R.string.progress_signing, 40, 100);
-
- // write directly on armor output stream
- armorOut.beginClearText(signatureHashAlgorithm);
-
- InputStream in = mData.getInputStream();
- final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
-
- final byte[] newline = "\r\n".getBytes("UTF-8");
-
- if (signatureForceV3) {
- 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);
- if (signatureForceV3) {
- 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 (signatureForceV3) {
- signatureV3Generator.generate().encode(pOut);
- } else {
- signatureGenerator.generate().encode(pOut);
- }
- }
-
- // closing outputs...
- if (enableEncryption) {
- encryptionOut.close();
-
- if (enableCompression) {
- compressGen.close();
- }
- }
- if (enableAsciiArmorOutput) {
- armorOut.close();
- }
-
- updateProgress(R.string.progress_done, 100, 100);
- }
-
- public void signText(long signatureKeyId, String signaturePassphrase,
- int signatureHashAlgorithm, boolean forceV3Signature)
- throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
- SignatureException {
-
- try {
- signAndEncrypt(true, 0, null, null, 0, signatureKeyId, signatureHashAlgorithm, forceV3Signature, signaturePassphrase);
- } catch (NoSuchProviderException e) {
- e.printStackTrace();
- }
- }
-
- // TODO: merge this into signAndEncrypt method!
- public void generateSignature(boolean armored, boolean binary, long signatureKeyId,
- String signaturePassPhrase, int hashAlgorithm, boolean forceV3Signature)
- throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
- SignatureException {
-
- OutputStream out;
- if (armored) {
- // Ascii Armor (Radix-64)
- ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
- armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
- out = armorOut;
- } else {
- out = mOutStream;
- }
-
- if (signatureKeyId == 0) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
- }
-
- PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
- PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
- if (signingKey == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
- }
-
- if (signaturePassPhrase == null) {
- throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
- }
-
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassPhrase.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(), hashAlgorithm)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
-
- PGPSignatureGenerator signatureGenerator = null;
- PGPV3SignatureGenerator signatureV3Generator = null;
- if (forceV3Signature) {
- 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(PgpKeyHelper.getMasterKey(signingKeyRing));
- 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 (forceV3Signature) {
- 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 (forceV3Signature) {
- processLine(line, null, signatureV3Generator);
- signatureV3Generator.update(newline);
- } else {
- processLine(line, null, signatureGenerator);
- signatureGenerator.update(newline);
- }
- }
- }
-
- BCPGOutputStream bOut = new BCPGOutputStream(out);
- if (forceV3Signature) {
- signatureV3Generator.generate().encode(bOut);
- } else {
- signatureGenerator.generate().encode(bOut);
- }
- out.close();
- mOutStream.close();
-
- updateProgress(R.string.progress_done, 100, 100);
- }
-
public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
throws PgpGeneralException, IOException {
InputStream in = PGPUtil.getDecoderStream(inputStream);
@@ -528,8 +152,8 @@ public class PgpOperation {
throw new PgpGeneralException(mContext.getString(R.string.error_invalid_data));
}
- InputStream clear = null;
- PGPEncryptedData encryptedData = null;
+ InputStream clear;
+ PGPEncryptedData encryptedData;
currentProgress += 5;
@@ -694,12 +318,13 @@ public class PgpOperation {
} else if (encryptedData.isIntegrityProtected()) {
endProgress = 95;
}
- int n = 0;
- int done = 0;
+
+ int n;
+// int progress = 0;
long startPos = mData.getStreamPosition();
while ((n = dataIn.read(buffer)) > 0) {
out.write(buffer, 0, n);
- done += n;
+// progress += n;
if (signature != null) {
try {
signature.update(buffer, 0, n);
@@ -709,9 +334,10 @@ public class PgpOperation {
signature = null;
}
}
+ // TODO: dead code?!
// unknown size, but try to at least have a moving, slowing down progress bar
- currentProgress = startProgress + (endProgress - startProgress) * done
- / (done + 100000);
+// currentProgress = startProgress + (endProgress - startProgress) * progress
+// / (progress + 100000);
if (mData.getSize() - startPos == 0) {
currentProgress = endProgress;
} else {
@@ -740,13 +366,15 @@ public class PgpOperation {
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, "No integrity check!");
+ Log.e(Constants.TAG, "Encrypted data was not integrity protected!");
}
updateProgress(R.string.progress_done, 100, 100);
@@ -953,56 +581,6 @@ public class PgpOperation {
return primkeyBinding_isok;
}
- 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);
- }
// taken from ClearSignedFileProcessor in BC
private static void processLine(PGPSignature sig, byte[] line) throws SignatureException,
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java
new file mode 100644
index 000000000..346638fa7
--- /dev/null
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpOperationOutgoing.java
@@ -0,0 +1,584 @@
+/*
+ * 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 PgpOperationOutgoing {
+ private Context context;
+ private InputData data;
+ private OutputStream outStream;
+
+ private ProgressDialogUpdater progress;
+ private boolean enableAsciiArmorOutput;
+ private int compressionId;
+ private long[] encryptionKeyIds;
+ private String encryptionPassphrase;
+ private int symmetricEncryptionAlgorithm;
+ private long signatureKeyId;
+ private int signatureHashAlgorithm;
+ private boolean signatureForceV3;
+ private String signaturePassphrase;
+
+ private PgpOperationOutgoing(Builder builder) {
+ // private Constructor can only be called from Builder
+ this.context = builder.context;
+ this.data = builder.data;
+ this.outStream = builder.outStream;
+
+ this.progress = builder.progress;
+ this.enableAsciiArmorOutput = builder.enableAsciiArmorOutput;
+ this.compressionId = builder.compressionId;
+ this.encryptionKeyIds = builder.encryptionKeyIds;
+ this.encryptionPassphrase = builder.encryptionPassphrase;
+ this.symmetricEncryptionAlgorithm = builder.symmetricEncryptionAlgorithm;
+ this.signatureKeyId = builder.signatureKeyId;
+ this.signatureHashAlgorithm = builder.signatureHashAlgorithm;
+ this.signatureForceV3 = builder.signatureForceV3;
+ this.signaturePassphrase = builder.signaturePassphrase;
+ }
+
+ public static class Builder {
+ // mandatory parameter
+ private Context context;
+ private InputData data;
+ private OutputStream outStream;
+
+ // optional
+ private ProgressDialogUpdater progress = null;
+ private boolean enableAsciiArmorOutput = false;
+ private int compressionId = Id.choice.compression.none;
+ private long[] encryptionKeyIds = new long[0];
+ private String encryptionPassphrase = null;
+ private int symmetricEncryptionAlgorithm = 0;
+ private long signatureKeyId = Id.key.none;
+ private int signatureHashAlgorithm = 0;
+ private boolean signatureForceV3 = false;
+ private String signaturePassphrase = null;
+
+ public Builder(Context context, InputData data, OutputStream outStream) {
+ this.context = context;
+ this.data = data;
+ this.outStream = outStream;
+ }
+
+ public Builder progress(ProgressDialogUpdater progress) {
+ this.progress = progress;
+ return this;
+ }
+
+ public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
+ this.enableAsciiArmorOutput = enableAsciiArmorOutput;
+ return this;
+ }
+
+ public Builder compressionId(int compressionId) {
+ this.compressionId = compressionId;
+ return this;
+ }
+
+ public Builder encryptionKeyIds(long[] encryptionKeyIds) {
+ this.encryptionKeyIds = encryptionKeyIds;
+ return this;
+ }
+
+ public Builder encryptionPassphrase(String encryptionPassphrase) {
+ this.encryptionPassphrase = encryptionPassphrase;
+ return this;
+ }
+
+ public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
+ this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
+ return this;
+ }
+
+ public Builder signatureKeyId(long signatureKeyId) {
+ this.signatureKeyId = signatureKeyId;
+ return this;
+ }
+
+ public Builder signatureHashAlgorithm(int signatureHashAlgorithm) {
+ this.signatureHashAlgorithm = signatureHashAlgorithm;
+ return this;
+ }
+
+ public Builder signatureForceV3(boolean signatureForceV3) {
+ this.signatureForceV3 = signatureForceV3;
+ return this;
+ }
+
+ public Builder signaturePassphrase(String signaturePassphrase) {
+ this.signaturePassphrase = signaturePassphrase;
+ return this;
+ }
+
+ public PgpOperationOutgoing build() {
+ return new PgpOperationOutgoing(this);
+ }
+ }
+
+ public void updateProgress(int message, int current, int total) {
+ if (progress != null) {
+ progress.setProgress(message, current, total);
+ }
+ }
+
+ public void updateProgress(int current, int total) {
+ if (progress != null) {
+ progress.setProgress(current, total);
+ }
+ }
+
+ public void signAndEncrypt()
+ throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
+ NoSuchAlgorithmException, SignatureException {
+
+ if (encryptionKeyIds == null) {
+ encryptionKeyIds = new long[0];
+ }
+
+ boolean enableSignature = signatureKeyId != Id.key.none;
+ boolean enableCompression = compressionId != Id.choice.compression.none;
+ boolean enableEncryption = encryptionKeyIds.length != 0 || encryptionPassphrase != null;
+
+ int signatureType;
+ if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
+ signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
+ } else {
+ signatureType = PGPSignature.BINARY_DOCUMENT;
+ }
+
+ ArmoredOutputStream armorOut = null;
+ OutputStream out;
+ OutputStream encryptionOut = null;
+ if (enableAsciiArmorOutput) {
+ armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
+ out = armorOut;
+ } else {
+ out = outStream;
+ }
+
+
+ PGPSecretKey signingKey = null;
+ PGPSecretKeyRing signingKeyRing = null;
+ PGPPrivateKey signaturePrivateKey = null;
+ if (enableSignature) {
+ signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
+ signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
+ if (signingKey == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_signature_failed));
+ }
+
+ if (signaturePassphrase == null) {
+ throw new PgpGeneralException(
+ context.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(signaturePassphrase.toCharArray());
+ signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
+ if (signaturePrivateKey == null) {
+ throw new PgpGeneralException(
+ context.getString(R.string.error_could_not_extract_private_key));
+ }
+ }
+ updateProgress(R.string.progress_preparing_streams, 5, 100);
+
+ // encrypt and compress input file content
+ if (enableEncryption) {
+ // has Integrity packet enabled!
+ JcePGPDataEncryptorBuilder encryptorBuilder =
+ new JcePGPDataEncryptorBuilder(symmetricEncryptionAlgorithm)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
+ .setWithIntegrityPacket(true);
+
+ PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
+
+ if (encryptionKeyIds.length == 0) {
+ // Symmetric encryption
+ Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
+
+ JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
+ new JcePBEKeyEncryptionMethodGenerator(encryptionPassphrase.toCharArray());
+ cPk.addMethod(symmetricEncryptionGenerator);
+ } else {
+ // Asymmetric encryption
+ for (long id : encryptionKeyIds) {
+ PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(context, id);
+ if (key != null) {
+
+ JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
+ new JcePublicKeyKeyEncryptionMethodGenerator(key);
+ cPk.addMethod(pubKeyEncryptionGenerator);
+ }
+ }
+ }
+ encryptionOut = cPk.open(out, new byte[1 << 16]);
+ }
+
+ 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(), signatureHashAlgorithm)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ if (signatureForceV3) {
+ signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
+ signatureV3Generator.init(signatureType, signaturePrivateKey);
+ } else {
+ signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ signatureGenerator.init(signatureType, signaturePrivateKey);
+
+ String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
+ }
+
+ PGPCompressedDataGenerator compressGen = null;
+ OutputStream pOut;
+ if (enableEncryption) {
+ BCPGOutputStream bcpgOut;
+ if (enableCompression) {
+ compressGen = new PGPCompressedDataGenerator(compressionId);
+ bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
+ } else {
+ bcpgOut = new BCPGOutputStream(encryptionOut);
+ }
+
+ if (enableSignature) {
+ if (signatureForceV3) {
+ 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 = data.getInputStream();
+ while ((n = in.read(buffer)) > 0) {
+ pOut.write(buffer, 0, n);
+
+ // update signature buffer if signature is requested
+ if (enableSignature) {
+ if (signatureForceV3) {
+ signatureV3Generator.update(buffer, 0, n);
+ } else {
+ signatureGenerator.update(buffer, 0, n);
+ }
+ }
+
+ progress += n;
+ if (data.getSize() != 0) {
+ updateProgress((int) (20 + (95 - 20) * progress / data.getSize()), 100);
+ }
+ }
+
+ literalGen.close();
+ } else if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
+ /* sign-only of ascii text */
+
+ updateProgress(R.string.progress_signing, 40, 100);
+
+ // write directly on armor output stream
+ armorOut.beginClearText(signatureHashAlgorithm);
+
+ InputStream in = data.getInputStream();
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+
+ final byte[] newline = "\r\n".getBytes("UTF-8");
+
+ if (signatureForceV3) {
+ 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);
+ if (signatureForceV3) {
+ 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 (signatureForceV3) {
+ signatureV3Generator.generate().encode(pOut);
+ } else {
+ signatureGenerator.generate().encode(pOut);
+ }
+ }
+
+ // closing outputs...
+ if (enableEncryption) {
+ encryptionOut.close();
+
+ if (enableCompression) {
+ compressGen.close();
+ }
+ }
+ if (enableAsciiArmorOutput) {
+ armorOut.close();
+ }
+
+ updateProgress(R.string.progress_done, 100, 100);
+ }
+
+ // TODO: merge this into signAndEncrypt method!
+ public void generateSignature()
+ throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
+ SignatureException {
+
+ OutputStream out;
+ if (enableAsciiArmorOutput) {
+ // Ascii Armor (Radix-64)
+ ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
+ armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
+ out = armorOut;
+ } else {
+ out = outStream;
+ }
+
+ if (signatureKeyId == 0) {
+ throw new PgpGeneralException(context.getString(R.string.error_no_signature_key));
+ }
+
+ PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
+ PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
+ if (signingKey == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_signature_failed));
+ }
+
+ if (signaturePassphrase == null) {
+ throw new PgpGeneralException(context.getString(R.string.error_no_signature_passphrase));
+ }
+
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
+ PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
+ if (signaturePrivateKey == null) {
+ throw new PgpGeneralException(
+ context.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(), signatureHashAlgorithm)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+
+ PGPSignatureGenerator signatureGenerator = null;
+ PGPV3SignatureGenerator signatureV3Generator = null;
+ if (signatureForceV3) {
+ 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(PgpKeyHelper.getMasterKey(signingKeyRing));
+ spGen.setSignerUserID(false, userId);
+ signatureGenerator.setHashedSubpackets(spGen.generate());
+ }
+
+ updateProgress(R.string.progress_signing, 40, 100);
+
+ InputStream inStream = data.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 (signatureForceV3) {
+ processLine(line, null, signatureV3Generator);
+ signatureV3Generator.update(newline);
+ } else {
+ processLine(line, null, signatureGenerator);
+ signatureGenerator.update(newline);
+ }
+ }
+// }
+
+ BCPGOutputStream bOut = new BCPGOutputStream(out);
+ if (signatureForceV3) {
+ signatureV3Generator.generate().encode(bOut);
+ } else {
+ signatureGenerator.generate().encode(bOut);
+ }
+ out.close();
+ outStream.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);
+ }
+
+ private static boolean isWhiteSpace(byte b) {
+ return b == '\r' || b == '\n' || b == '\t' || b == ' ';
+ }
+
+}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 1de9ab985..8d8f4e796 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -46,7 +46,8 @@ import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
-import org.sufficientlysecure.keychain.pgp.PgpOperation;
+import org.sufficientlysecure.keychain.pgp.PgpOperationIncoming;
+import org.sufficientlysecure.keychain.pgp.PgpOperationOutgoing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -316,27 +317,41 @@ public class KeychainIntentService extends IntentService implements ProgressDial
}
/* Operation */
- PgpOperation operation = new PgpOperation(this, this, inputData, outStream);
+ PgpOperationOutgoing.Builder builder =
+ new PgpOperationOutgoing.Builder(this, inputData, outStream);
+ builder.progress(this);
+
if (generateSignature) {
Log.d(Constants.TAG, "generating signature...");
- operation.generateSignature(useAsciiArmor, false, secretKeyId,
- PassphraseCacheService.getCachedPassphrase(this, secretKeyId),
- Preferences.getPreferences(this).getDefaultHashAlgorithm(), Preferences
- .getPreferences(this).getForceV3Signatures());
+ builder.enableAsciiArmorOutput(useAsciiArmor)
+ .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
+ .signatureKeyId(secretKeyId)
+ .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+
+ builder.build().generateSignature();
} else if (signOnly) {
Log.d(Constants.TAG, "sign only...");
- operation.signText(secretKeyId, PassphraseCacheService.getCachedPassphrase(
- this, secretKeyId), Preferences.getPreferences(this)
- .getDefaultHashAlgorithm(), Preferences.getPreferences(this)
- .getForceV3Signatures());
+ builder.enableAsciiArmorOutput(useAsciiArmor)
+ .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
+ .signatureKeyId(secretKeyId)
+ .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+
+ builder.build().signAndEncrypt();
} else {
Log.d(Constants.TAG, "encrypt...");
- operation.signAndEncrypt(useAsciiArmor, compressionId, encryptionKeyIds,
- encryptionPassphrase, Preferences.getPreferences(this)
- .getDefaultEncryptionAlgorithm(), secretKeyId, Preferences
- .getPreferences(this).getDefaultHashAlgorithm(), Preferences
- .getPreferences(this).getForceV3Signatures(),
- PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+ builder.enableAsciiArmorOutput(useAsciiArmor)
+ .compressionId(compressionId)
+ .symmetricEncryptionAlgorithm(Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
+ .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
+ .encryptionKeyIds(encryptionKeyIds)
+ .encryptionPassphrase(encryptionPassphrase)
+ .signatureKeyId(secretKeyId)
+ .signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
+ .signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+
+ builder.build().signAndEncrypt();
}
outStream.close();
@@ -466,7 +481,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// verifyText and decrypt returning additional resultData values for the
// verification of signatures
- PgpOperation operation = new PgpOperation(this, this, inputData, outStream);
+ PgpOperationIncoming operation = new PgpOperationIncoming(this, this, inputData, outStream);
if (signedOnly) {
resultData = operation.verifyText();
} else {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
index b13c8ac49..da42be2e2 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java
@@ -29,12 +29,11 @@ import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpConstants;
-import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.pgp.PgpOperation;
+import org.sufficientlysecure.keychain.pgp.PgpOperationOutgoing;
+import org.sufficientlysecure.keychain.pgp.PgpOperationIncoming;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
@@ -162,9 +161,14 @@ public class OpenPgpService extends RemoteService {
long inputLength = is.available();
InputData inputData = new InputData(is, inputLength);
- PgpOperation operation = new PgpOperation(getContext(), null, inputData, os);
- operation.signText(appSettings.getKeyId(), passphrase, appSettings.getHashAlgorithm(),
- Preferences.getPreferences(this).getForceV3Signatures());
+ // sign-only
+ PgpOperationOutgoing.Builder builder = new PgpOperationOutgoing.Builder(getContext(), inputData, os);
+ builder.enableAsciiArmorOutput(true)
+ .signatureHashAlgorithm(appSettings.getHashAlgorithm())
+ .signatureForceV3(false)
+ .signatureKeyId(appSettings.getKeyId())
+ .signaturePassphrase(passphrase);
+ builder.build().signAndEncrypt();
} finally {
is.close();
os.close();
@@ -223,7 +227,14 @@ public class OpenPgpService extends RemoteService {
long inputLength = is.available();
InputData inputData = new InputData(is, inputLength);
- PgpOperation operation = new PgpOperation(getContext(), null, inputData, os);
+ PgpOperationOutgoing.Builder builder = new PgpOperationOutgoing.Builder(getContext(), inputData, os);
+ builder.enableAsciiArmorOutput(asciiArmor)
+ .compressionId(appSettings.getCompression())
+ .symmetricEncryptionAlgorithm(appSettings.getEncryptionAlgorithm())
+ .signatureHashAlgorithm(appSettings.getHashAlgorithm())
+ .signatureForceV3(false)
+ .encryptionKeyIds(keyIds);
+
if (sign) {
String passphrase;
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
@@ -239,15 +250,14 @@ public class OpenPgpService extends RemoteService {
}
// sign and encrypt
- operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
- appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
- appSettings.getHashAlgorithm(), true, passphrase);
+ builder.signatureKeyId(appSettings.getKeyId())
+ .signaturePassphrase(passphrase);
} else {
// encrypt only
- operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
- appSettings.getEncryptionAlgorithm(), Id.key.none,
- appSettings.getHashAlgorithm(), true, null);
+ builder.signatureKeyId(Id.key.none);
}
+ // execute PGP operation!
+ builder.build().signAndEncrypt();
} finally {
is.close();
os.close();
@@ -344,7 +354,7 @@ public class OpenPgpService extends RemoteService {
// inputStream2.reset();
// }
// secretKeyId = Id.key.symmetric;
-// if (!PgpOperation.hasSymmetricEncryption(this, inputStream2)) {
+// if (!PgpOperationIncoming.hasSymmetricEncryption(this, inputStream2)) {
// throw new PgpGeneralException(
// getString(R.string.error_no_known_encryption_found));
// }
@@ -374,7 +384,7 @@ public class OpenPgpService extends RemoteService {
Bundle outputBundle;
- PgpOperation operation = new PgpOperation(getContext(), null, inputData, os);
+ PgpOperationIncoming operation = new PgpOperationIncoming(getContext(), null, inputData, os);
if (signedOnly) {
outputBundle = operation.verifyText();
} else {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index b8eed83c9..1f3280af3 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -34,7 +34,7 @@ import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.pgp.PgpOperation;
+import org.sufficientlysecure.keychain.pgp.PgpOperationIncoming;
import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -546,7 +546,7 @@ public class DecryptActivity extends DrawerActivity {
inStream.reset();
}
mSecretKeyId = Id.key.symmetric;
- if (!PgpOperation.hasSymmetricEncryption(this, inStream)) {
+ if (!PgpOperationIncoming.hasSymmetricEncryption(this, inStream)) {
throw new PgpGeneralException(
getString(R.string.error_no_known_encryption_found));
}