diff options
author | Andrea Torlaschi <runnerway@gmail.com> | 2016-03-08 18:47:46 +0100 |
---|---|---|
committer | Andrea Torlaschi <runnerway@gmail.com> | 2016-05-10 23:38:11 +0200 |
commit | c942d8b2ff062abce236ebff6fba268ab5247038 (patch) | |
tree | 0387f7e2126911bdf3d9f13bd727386b17af0ab2 /OpenKeychain/src/main/java/org/sufficientlysecure | |
parent | c8a0eb3a083c92b654610f34655fed80312a8ef1 (diff) | |
download | open-keychain-c942d8b2ff062abce236ebff6fba268ab5247038.tar.gz open-keychain-c942d8b2ff062abce236ebff6fba268ab5247038.tar.bz2 open-keychain-c942d8b2ff062abce236ebff6fba268ab5247038.zip |
PgpSignEncryptOperation refactoring
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure')
12 files changed, 496 insertions, 349 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java index 7c2f9d6b2..0ea7e7e59 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java @@ -47,6 +47,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; import org.sufficientlysecure.keychain.pgp.Progressable; @@ -151,10 +152,11 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> { PgpSignEncryptOperation pseOp = new PgpSignEncryptOperation(mContext, mProviderHelper, mProgressable, mCancelled); - PgpSignEncryptInputParcel inputParcel = new PgpSignEncryptInputParcel(); - inputParcel.setSymmetricPassphrase(cryptoInput.getPassphrase()); - inputParcel.setEnableAsciiArmorOutput(true); - inputParcel.setAddBackupHeader(true); + PgpSignEncryptData data = new PgpSignEncryptData(); + data.setSymmetricPassphrase(cryptoInput.getPassphrase()); + data.setEnableAsciiArmorOutput(true); + data.setAddBackupHeader(true); + PgpSignEncryptInputParcel inputParcel = new PgpSignEncryptInputParcel(data); InputStream inStream = mContext.getContentResolver().openInputStream(plainUri); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java index 52deffeab..a179fa66a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java @@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -83,9 +84,10 @@ public class BenchmarkOperation extends BaseOperation<BenchmarkInputParcel> { SignEncryptOperation op = new SignEncryptOperation(mContext, mProviderHelper, new ProgressScaler(mProgressable, i*(50/numRepeats), (i+1)*(50/numRepeats), 100), mCancelled); - SignEncryptParcel input = new SignEncryptParcel(); - input.setSymmetricPassphrase(passphrase); - input.setSymmetricEncryptionAlgorithm(OpenKeychainSymmetricKeyAlgorithmTags.AES_128); + PgpSignEncryptData data = new PgpSignEncryptData(); + data.setSymmetricPassphrase(passphrase); + data.setSymmetricEncryptionAlgorithm(OpenKeychainSymmetricKeyAlgorithmTags.AES_128); + SignEncryptParcel input = new SignEncryptParcel(data); input.setBytes(buf); encryptResult = op.execute(input, new CryptoInputParcel()); log.add(encryptResult, 1); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java index 5bca372cb..dedc03553 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java @@ -18,15 +18,6 @@ package org.sufficientlysecure.keychain.operations; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicBoolean; - import android.content.Context; import android.net.Uri; import android.support.annotation.NonNull; @@ -36,6 +27,8 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; @@ -45,16 +38,18 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType; -import org.sufficientlysecure.keychain.util.FileHelper; -import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + /** * This is a high-level operation, which encapsulates one or more sign/encrypt * operations, using URIs or byte arrays as input and output. - * + * <p/> * This operation is fail-fast: If any sign/encrypt sub-operation fails or returns * a pending result, it will terminate. */ @@ -75,20 +70,20 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> { ArrayDeque<Uri> inputUris = new ArrayDeque<>(input.getInputUris()); ArrayDeque<Uri> outputUris = new ArrayDeque<>(input.getOutputUris()); byte[] inputBytes = input.getBytes(); - byte[] outputBytes = null; int total = inputBytes != null ? 1 : inputUris.size(), count = 0; ArrayList<PgpSignEncryptResult> results = new ArrayList<>(); SecurityTokenSignOperationsBuilder pendingInputBuilder = null; + PgpSignEncryptData data = input.getData(); // if signing subkey has not explicitly been set, get first usable subkey capable of signing - if (input.getSignatureMasterKeyId() != Constants.key.none - && input.getSignatureSubKeyId() == null) { + if (data.getSignatureMasterKeyId() != Constants.key.none + && data.getSignatureSubKeyId() == null) { try { long signKeyId = mProviderHelper.getCachedPublicKeyRing( - input.getSignatureMasterKeyId()).getSecretSignId(); - input.setSignatureSubKeyId(signKeyId); + data.getSignatureMasterKeyId()).getSecretSignId(); + data.setSignatureSubKeyId(signKeyId); } catch (PgpKeyNotFoundException e) { Log.e(Constants.TAG, "Key not found", e); return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); @@ -96,61 +91,22 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> { } do { - if (checkCancelled()) { log.add(LogType.MSG_OPERATION_CANCELLED, 0); return new SignEncryptResult(SignEncryptResult.RESULT_CANCELLED, log, results); } - InputData inputData; - { - if (inputBytes != null) { - log.add(LogType.MSG_SE_INPUT_BYTES, 1); - InputStream is = new ByteArrayInputStream(inputBytes); - inputData = new InputData(is, inputBytes.length); - inputBytes = null; - } else { - if (inputUris.isEmpty()) { - log.add(LogType.MSG_SE_ERROR_NO_INPUT, 1); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); - } - - log.add(LogType.MSG_SE_INPUT_URI, 1); - Uri uri = inputUris.removeFirst(); - try { - InputStream is = FileHelper.openInputStreamSafe(mContext.getContentResolver(), uri); - long fileSize = FileHelper.getFileSize(mContext, uri, 0); - String filename = FileHelper.getFilename(mContext, uri); - inputData = new InputData(is, fileSize, filename); - } catch (FileNotFoundException e) { - log.add(LogType.MSG_SE_ERROR_INPUT_URI_NOT_FOUND, 1); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); - } - } - } - - OutputStream outStream; - { - if (!outputUris.isEmpty()) { - try { - Uri outputUri = outputUris.removeFirst(); - outStream = mContext.getContentResolver().openOutputStream(outputUri); - } catch (FileNotFoundException e) { - log.add(LogType.MSG_SE_ERROR_OUTPUT_URI_NOT_FOUND, 1); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); - } - } else { - if (outputBytes != null) { - log.add(LogType.MSG_SE_ERROR_TOO_MANY_INPUTS, 1); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); - } - outStream = new ByteArrayOutputStream(); - } - } - PgpSignEncryptOperation op = new PgpSignEncryptOperation(mContext, mProviderHelper, new ProgressScaler(mProgressable, 100 * count / total, 100 * ++count / total, 100), mCancelled); - PgpSignEncryptResult result = op.execute(input, cryptoInput, inputData, outStream); + PgpSignEncryptInputParcel inputParcel = new PgpSignEncryptInputParcel(input.getData()); + if (inputBytes != null) { + inputParcel.setInputBytes(inputBytes); + } else { + inputParcel.setInputUri(inputUris.removeFirst()); + } + inputParcel.setOutputUri(outputUris.pollFirst()); + + PgpSignEncryptResult result = op.execute(inputParcel, cryptoInput); results.add(result); log.add(result, 2); @@ -162,17 +118,12 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> { } if (pendingInputBuilder == null) { pendingInputBuilder = new SecurityTokenSignOperationsBuilder(requiredInput.mSignatureTime, - input.getSignatureMasterKeyId(), input.getSignatureSubKeyId()); + data.getSignatureMasterKeyId(), data.getSignatureSubKeyId()); } pendingInputBuilder.addAll(requiredInput); } else if (!result.success()) { return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); } - - if (outStream instanceof ByteArrayOutputStream) { - outputBytes = ((ByteArrayOutputStream) outStream).toByteArray(); - } - } while (!inputUris.isEmpty()); if (pendingInputBuilder != null && !pendingInputBuilder.isEmpty()) { @@ -184,8 +135,8 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> { } log.add(LogType.MSG_SE_SUCCESS, 1); - return new SignEncryptResult(SignEncryptResult.RESULT_OK, log, results, outputBytes); - + return new SignEncryptResult(SignEncryptResult.RESULT_OK, log, results, + results.get(results.size() - 1).getOutputBytes()); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index d3d962808..be736d785 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -710,15 +710,15 @@ public abstract class OperationResult implements Parcelable { // signencrypt MSG_SE (LogLevel.START, R.string.msg_se), - MSG_SE_INPUT_BYTES (LogLevel.INFO, R.string.msg_se_input_bytes), - MSG_SE_INPUT_URI (LogLevel.INFO, R.string.msg_se_input_uri), MSG_SE_ERROR_NO_INPUT (LogLevel.DEBUG, R.string.msg_se_error_no_input), - MSG_SE_ERROR_INPUT_URI_NOT_FOUND (LogLevel.ERROR, R.string.msg_se_error_input_uri_not_found), - MSG_SE_ERROR_OUTPUT_URI_NOT_FOUND (LogLevel.ERROR, R.string.msg_se_error_output_uri_not_found), MSG_SE_ERROR_TOO_MANY_INPUTS (LogLevel.ERROR, R.string.msg_se_error_too_many_inputs), MSG_SE_SUCCESS (LogLevel.OK, R.string.msg_se_success), // pgpsignencrypt + MSG_PSE_INPUT_BYTES (LogLevel.INFO, R.string.msg_se_input_bytes), + MSG_PSE_INPUT_URI (LogLevel.INFO, R.string.msg_se_input_uri), + MSG_PSE_ERROR_INPUT_URI_NOT_FOUND (LogLevel.ERROR, R.string.msg_se_error_input_uri_not_found), + MSG_PSE_ERROR_OUTPUT_URI_NOT_FOUND (LogLevel.ERROR, R.string.msg_se_error_output_uri_not_found), MSG_PSE_ASYMMETRIC (LogLevel.INFO, R.string.msg_pse_asymmetric), MSG_PSE_COMPRESSING (LogLevel.DEBUG, R.string.msg_pse_compressing), MSG_PSE_ENCRYPTING (LogLevel.DEBUG, R.string.msg_pse_encrypting), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java index c4f66b950..2b9f149ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java @@ -25,6 +25,8 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; public class PgpSignEncryptResult extends InputPendingResult { + byte[] mOutputBytes; + byte[] mDetachedSignature; public long mOperationTime; // this is the micalg parameter used in PGP/MIME, see RFC3156: @@ -53,6 +55,14 @@ public class PgpSignEncryptResult extends InputPendingResult { mDetachedSignature = source.readInt() != 0 ? source.createByteArray() : null; } + public void setOutputBytes(byte[] outputBytes) { + mOutputBytes = outputBytes; + } + + public byte[] getOutputBytes() { + return mOutputBytes; + } + public int describeContents() { return 0; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptData.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptData.java new file mode 100644 index 000000000..c4e569d24 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptData.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com> + * + * 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.bouncycastle.bcpg.CompressionAlgorithmTags; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Passphrase; + + +public class PgpSignEncryptData implements Parcelable { + + protected String mVersionHeader = null; + protected boolean mEnableAsciiArmorOutput = false; + protected int mCompressionAlgorithm = CompressionAlgorithmTags.UNCOMPRESSED; + protected long[] mEncryptionMasterKeyIds = null; + protected Passphrase mSymmetricPassphrase = null; + protected int mSymmetricEncryptionAlgorithm = PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT; + protected long mSignatureMasterKeyId = Constants.key.none; + protected Long mSignatureSubKeyId = null; + protected int mSignatureHashAlgorithm = PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT; + protected long mAdditionalEncryptId = Constants.key.none; + protected String mCharset; + protected boolean mCleartextSignature; + protected boolean mDetachedSignature = false; + protected boolean mHiddenRecipients = false; + protected boolean mIntegrityProtected = true; + protected boolean mAddBackupHeader = false; + + public PgpSignEncryptData(){ + } + + PgpSignEncryptData(Parcel source) { + ClassLoader loader = getClass().getClassLoader(); + + mVersionHeader = source.readString(); + mEnableAsciiArmorOutput = source.readInt() == 1; + mCompressionAlgorithm = source.readInt(); + mEncryptionMasterKeyIds = source.createLongArray(); + mSymmetricPassphrase = source.readParcelable(loader); + mSymmetricEncryptionAlgorithm = source.readInt(); + mSignatureMasterKeyId = source.readLong(); + mSignatureSubKeyId = source.readInt() == 1 ? source.readLong() : null; + mSignatureHashAlgorithm = source.readInt(); + mAdditionalEncryptId = source.readLong(); + mCharset = source.readString(); + mCleartextSignature = source.readInt() == 1; + mDetachedSignature = source.readInt() == 1; + mHiddenRecipients = source.readInt() == 1; + mIntegrityProtected = source.readInt() == 1; + mAddBackupHeader = source.readInt() == 1; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mVersionHeader); + dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0); + dest.writeInt(mCompressionAlgorithm); + dest.writeLongArray(mEncryptionMasterKeyIds); + dest.writeParcelable(mSymmetricPassphrase, 0); + dest.writeInt(mSymmetricEncryptionAlgorithm); + dest.writeLong(mSignatureMasterKeyId); + if (mSignatureSubKeyId != null) { + dest.writeInt(1); + dest.writeLong(mSignatureSubKeyId); + } else { + dest.writeInt(0); + } + dest.writeInt(mSignatureHashAlgorithm); + dest.writeLong(mAdditionalEncryptId); + dest.writeString(mCharset); + dest.writeInt(mCleartextSignature ? 1 : 0); + dest.writeInt(mDetachedSignature ? 1 : 0); + dest.writeInt(mHiddenRecipients ? 1 : 0); + dest.writeInt(mIntegrityProtected ? 1 : 0); + dest.writeInt(mAddBackupHeader ? 1 : 0); + } + + public String getCharset() { + return mCharset; + } + + public void setCharset(String mCharset) { + this.mCharset = mCharset; + } + + public long getAdditionalEncryptId() { + return mAdditionalEncryptId; + } + + public PgpSignEncryptData setAdditionalEncryptId(long additionalEncryptId) { + mAdditionalEncryptId = additionalEncryptId; + return this; + } + + public int getSignatureHashAlgorithm() { + return mSignatureHashAlgorithm; + } + + public PgpSignEncryptData setSignatureHashAlgorithm(int signatureHashAlgorithm) { + mSignatureHashAlgorithm = signatureHashAlgorithm; + return this; + } + + public Long getSignatureSubKeyId() { + return mSignatureSubKeyId; + } + + public PgpSignEncryptData setSignatureSubKeyId(long signatureSubKeyId) { + mSignatureSubKeyId = signatureSubKeyId; + return this; + } + + public long getSignatureMasterKeyId() { + return mSignatureMasterKeyId; + } + + public PgpSignEncryptData setSignatureMasterKeyId(long signatureMasterKeyId) { + mSignatureMasterKeyId = signatureMasterKeyId; + return this; + } + + public int getSymmetricEncryptionAlgorithm() { + return mSymmetricEncryptionAlgorithm; + } + + public PgpSignEncryptData setSymmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) { + mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm; + return this; + } + + public Passphrase getSymmetricPassphrase() { + return mSymmetricPassphrase; + } + + public PgpSignEncryptData setSymmetricPassphrase(Passphrase symmetricPassphrase) { + mSymmetricPassphrase = symmetricPassphrase; + return this; + } + + public long[] getEncryptionMasterKeyIds() { + return mEncryptionMasterKeyIds; + } + + public PgpSignEncryptData setEncryptionMasterKeyIds(long[] encryptionMasterKeyIds) { + mEncryptionMasterKeyIds = encryptionMasterKeyIds; + return this; + } + + public int getCompressionAlgorithm() { + return mCompressionAlgorithm; + } + + public PgpSignEncryptData setCompressionAlgorithm(int compressionAlgorithm) { + mCompressionAlgorithm = compressionAlgorithm; + return this; + } + + public boolean isEnableAsciiArmorOutput() { + return mEnableAsciiArmorOutput; + } + + public String getVersionHeader() { + return mVersionHeader; + } + + public PgpSignEncryptData setVersionHeader(String versionHeader) { + mVersionHeader = versionHeader; + return this; + } + + public PgpSignEncryptData setEnableAsciiArmorOutput(boolean enableAsciiArmorOutput) { + mEnableAsciiArmorOutput = enableAsciiArmorOutput; + return this; + } + + public PgpSignEncryptData setCleartextSignature(boolean cleartextSignature) { + this.mCleartextSignature = cleartextSignature; + return this; + } + + public boolean isCleartextSignature() { + return mCleartextSignature; + } + + public PgpSignEncryptData setDetachedSignature(boolean detachedSignature) { + this.mDetachedSignature = detachedSignature; + return this; + } + + public boolean isDetachedSignature() { + return mDetachedSignature; + } + + public PgpSignEncryptData setHiddenRecipients(boolean hiddenRecipients) { + this.mHiddenRecipients = hiddenRecipients; + return this; + } + + public boolean isIntegrityProtected() { + return mIntegrityProtected; + } + + /** + * Only use for testing! Never disable integrity protection! + */ + public PgpSignEncryptData setIntegrityProtected(boolean integrityProtected) { + this.mIntegrityProtected = integrityProtected; + return this; + } + + public PgpSignEncryptData setAddBackupHeader(boolean addBackupHeader) { + this.mAddBackupHeader = addBackupHeader; + return this; + } + + public boolean isAddBackupHeader() { + return mAddBackupHeader; + } + + public boolean isHiddenRecipients() { + return mHiddenRecipients; + } + + public static final Creator<PgpSignEncryptData> CREATOR = new Creator<PgpSignEncryptData>() { + public PgpSignEncryptData createFromParcel(final Parcel source) { + return new PgpSignEncryptData(source); + } + + public PgpSignEncryptData[] newArray(final int size) { + return new PgpSignEncryptData[size]; + } + }; + +} + diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java index 8eae92e63..8e0c7ab40 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java @@ -18,58 +18,29 @@ package org.sufficientlysecure.keychain.pgp; -import org.bouncycastle.bcpg.CompressionAlgorithmTags; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Passphrase; - +import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; public class PgpSignEncryptInputParcel implements Parcelable { - protected String mVersionHeader = null; - protected boolean mEnableAsciiArmorOutput = false; - protected int mCompressionAlgorithm = CompressionAlgorithmTags.UNCOMPRESSED; - protected long[] mEncryptionMasterKeyIds = null; - protected Passphrase mSymmetricPassphrase = null; - protected int mSymmetricEncryptionAlgorithm = PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT; - protected long mSignatureMasterKeyId = Constants.key.none; - protected Long mSignatureSubKeyId = null; - protected int mSignatureHashAlgorithm = PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT; - protected long mAdditionalEncryptId = Constants.key.none; - protected String mCharset; - protected boolean mCleartextSignature; - protected boolean mDetachedSignature = false; - protected boolean mHiddenRecipients = false; - protected boolean mIntegrityProtected = true; - protected boolean mAddBackupHeader = false; + private PgpSignEncryptData data; - public PgpSignEncryptInputParcel() { + private Uri mInputUri; + private Uri mOutputUri; + private byte[] mInputBytes; + public PgpSignEncryptInputParcel(PgpSignEncryptData data) { + this.data = data; } PgpSignEncryptInputParcel(Parcel source) { + mInputUri = source.readParcelable(getClass().getClassLoader()); + mOutputUri = source.readParcelable(getClass().getClassLoader()); + mInputBytes = source.createByteArray(); - ClassLoader loader = getClass().getClassLoader(); - - // we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable - mVersionHeader = source.readString(); - mEnableAsciiArmorOutput = source.readInt() == 1; - mCompressionAlgorithm = source.readInt(); - mEncryptionMasterKeyIds = source.createLongArray(); - mSymmetricPassphrase = source.readParcelable(loader); - mSymmetricEncryptionAlgorithm = source.readInt(); - mSignatureMasterKeyId = source.readLong(); - mSignatureSubKeyId = source.readInt() == 1 ? source.readLong() : null; - mSignatureHashAlgorithm = source.readInt(); - mAdditionalEncryptId = source.readLong(); - mCharset = source.readString(); - mCleartextSignature = source.readInt() == 1; - mDetachedSignature = source.readInt() == 1; - mHiddenRecipients = source.readInt() == 1; - mIntegrityProtected = source.readInt() == 1; - mAddBackupHeader = source.readInt() == 1; + data = source.readParcelable(getClass().getClassLoader()); } @Override @@ -79,173 +50,45 @@ public class PgpSignEncryptInputParcel implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mVersionHeader); - dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0); - dest.writeInt(mCompressionAlgorithm); - dest.writeLongArray(mEncryptionMasterKeyIds); - dest.writeParcelable(mSymmetricPassphrase, 0); - dest.writeInt(mSymmetricEncryptionAlgorithm); - dest.writeLong(mSignatureMasterKeyId); - if (mSignatureSubKeyId != null) { - dest.writeInt(1); - dest.writeLong(mSignatureSubKeyId); - } else { - dest.writeInt(0); - } - dest.writeInt(mSignatureHashAlgorithm); - dest.writeLong(mAdditionalEncryptId); - dest.writeString(mCharset); - dest.writeInt(mCleartextSignature ? 1 : 0); - dest.writeInt(mDetachedSignature ? 1 : 0); - dest.writeInt(mHiddenRecipients ? 1 : 0); - dest.writeInt(mIntegrityProtected ? 1 : 0); - dest.writeInt(mAddBackupHeader ? 1 : 0); - } - - public String getCharset() { - return mCharset; - } - - public void setCharset(String mCharset) { - this.mCharset = mCharset; - } - - public long getAdditionalEncryptId() { - return mAdditionalEncryptId; - } - - public PgpSignEncryptInputParcel setAdditionalEncryptId(long additionalEncryptId) { - mAdditionalEncryptId = additionalEncryptId; - return this; - } - - public int getSignatureHashAlgorithm() { - return mSignatureHashAlgorithm; - } - - public PgpSignEncryptInputParcel setSignatureHashAlgorithm(int signatureHashAlgorithm) { - mSignatureHashAlgorithm = signatureHashAlgorithm; - return this; - } - - public Long getSignatureSubKeyId() { - return mSignatureSubKeyId; - } - - public PgpSignEncryptInputParcel setSignatureSubKeyId(long signatureSubKeyId) { - mSignatureSubKeyId = signatureSubKeyId; - return this; - } - - public long getSignatureMasterKeyId() { - return mSignatureMasterKeyId; - } - - public PgpSignEncryptInputParcel setSignatureMasterKeyId(long signatureMasterKeyId) { - mSignatureMasterKeyId = signatureMasterKeyId; - return this; - } + dest.writeParcelable(mInputUri, 0); + dest.writeParcelable(mOutputUri, 0); + dest.writeByteArray(mInputBytes); - public int getSymmetricEncryptionAlgorithm() { - return mSymmetricEncryptionAlgorithm; + data.writeToParcel(dest, 0); } - public PgpSignEncryptInputParcel setSymmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) { - mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm; - return this; + public void setInputBytes(byte[] inputBytes) { + this.mInputBytes = inputBytes; } - public Passphrase getSymmetricPassphrase() { - return mSymmetricPassphrase; + byte[] getInputBytes() { + return mInputBytes; } - public PgpSignEncryptInputParcel setSymmetricPassphrase(Passphrase symmetricPassphrase) { - mSymmetricPassphrase = symmetricPassphrase; + public PgpSignEncryptInputParcel setInputUri(Uri uri) { + mInputUri = uri; return this; } - public long[] getEncryptionMasterKeyIds() { - return mEncryptionMasterKeyIds; + Uri getInputUri() { + return mInputUri; } - public PgpSignEncryptInputParcel setEncryptionMasterKeyIds(long[] encryptionMasterKeyIds) { - mEncryptionMasterKeyIds = encryptionMasterKeyIds; + public PgpSignEncryptInputParcel setOutputUri(Uri uri) { + mOutputUri = uri; return this; } - public int getCompressionAlgorithm() { - return mCompressionAlgorithm; - } - - public PgpSignEncryptInputParcel setCompressionAlgorithm(int compressionAlgorithm) { - mCompressionAlgorithm = compressionAlgorithm; - return this; - } - - public boolean isEnableAsciiArmorOutput() { - return mEnableAsciiArmorOutput; - } - - public String getVersionHeader() { - return mVersionHeader; - } - - public PgpSignEncryptInputParcel setVersionHeader(String versionHeader) { - mVersionHeader = versionHeader; - return this; - } - - public PgpSignEncryptInputParcel setEnableAsciiArmorOutput(boolean enableAsciiArmorOutput) { - mEnableAsciiArmorOutput = enableAsciiArmorOutput; - return this; - } - - public PgpSignEncryptInputParcel setCleartextSignature(boolean cleartextSignature) { - this.mCleartextSignature = cleartextSignature; - return this; - } - - public boolean isCleartextSignature() { - return mCleartextSignature; - } - - public PgpSignEncryptInputParcel setDetachedSignature(boolean detachedSignature) { - this.mDetachedSignature = detachedSignature; - return this; - } - - public boolean isDetachedSignature() { - return mDetachedSignature; - } - - public PgpSignEncryptInputParcel setHiddenRecipients(boolean hiddenRecipients) { - this.mHiddenRecipients = hiddenRecipients; - return this; - } - - public boolean isIntegrityProtected() { - return mIntegrityProtected; - } - - /** - * Only use for testing! Never disable integrity protection! - */ - public PgpSignEncryptInputParcel setIntegrityProtected(boolean integrityProtected) { - this.mIntegrityProtected = integrityProtected; - return this; - } - - public PgpSignEncryptInputParcel setAddBackupHeader(boolean addBackupHeader) { - this.mAddBackupHeader = addBackupHeader; - return this; + Uri getOutputUri() { + return mOutputUri; } - public boolean isAddBackupHeader() { - return mAddBackupHeader; + public void setData(PgpSignEncryptData data) { + this.data = data; } - public boolean isHiddenRecipients() { - return mHiddenRecipients; + public PgpSignEncryptData getData() { + return data; } public static final Creator<PgpSignEncryptInputParcel> CREATOR = new Creator<PgpSignEncryptInputParcel>() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index 0bb6419eb..7a1d99927 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.pgp; import android.content.Context; +import android.net.Uri; import android.os.Parcelable; import android.support.annotation.NonNull; @@ -39,16 +40,19 @@ import org.bouncycastle.openpgp.operator.jcajce.PGPUtil; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.BaseOperation; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; 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.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; @@ -57,7 +61,9 @@ import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -83,7 +89,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * @see org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult * @see org.sufficientlysecure.keychain.operations.SignEncryptOperation */ -public class PgpSignEncryptOperation extends BaseOperation { +public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputParcel> { private static byte[] NEW_LINE; @@ -105,16 +111,65 @@ public class PgpSignEncryptOperation extends BaseOperation { @NonNull @Override - // TODO this is horrible, refactor ASAP!! - public OperationResult execute(Parcelable input, CryptoInputParcel cryptoInput) { - return null; + public PgpSignEncryptResult execute(PgpSignEncryptInputParcel input, CryptoInputParcel cryptoInput) { + OperationLog log = new OperationLog(); + + InputData inputData; + { + if (input.getInputBytes() != null) { + log.add(LogType.MSG_PSE_INPUT_BYTES, 1); + InputStream is = new ByteArrayInputStream(input.getInputBytes()); + inputData = new InputData(is, input.getInputBytes().length); + } else { + log.add(LogType.MSG_PSE_INPUT_URI, 1); + Uri uri = input.getInputUri(); + try { + InputStream is = FileHelper.openInputStreamSafe(mContext.getContentResolver(), uri); + long fileSize = FileHelper.getFileSize(mContext, uri, 0); + String filename = FileHelper.getFilename(mContext, uri); + inputData = new InputData(is, fileSize, filename); + } catch (FileNotFoundException e) { + log.add(LogType.MSG_PSE_ERROR_INPUT_URI_NOT_FOUND, 1); + return new PgpSignEncryptResult(SignEncryptResult.RESULT_ERROR, log); + } + } + } + + OutputStream outStream; + { + if (input.getOutputUri() != null) { + try { + Uri outputUri = input.getOutputUri(); + outStream = mContext.getContentResolver().openOutputStream(outputUri); + } catch (FileNotFoundException e) { + log.add(LogType.MSG_PSE_ERROR_OUTPUT_URI_NOT_FOUND, 1); + return new PgpSignEncryptResult(SignEncryptResult.RESULT_ERROR, log); + } + } else { + outStream = new ByteArrayOutputStream(); + } + } + + PgpSignEncryptResult result = executeInternal(input, cryptoInput, inputData, outStream); + if (outStream instanceof ByteArrayOutputStream) { + byte[] outputData = ((ByteArrayOutputStream) outStream).toByteArray(); + result.setOutputBytes(outputData); + } + + return result; + } + + @NonNull + public PgpSignEncryptResult execute(PgpSignEncryptInputParcel input, CryptoInputParcel cryptoInput, + InputData inputData, OutputStream outputStream) { + return executeInternal(input, cryptoInput, inputData, outputStream); } /** * Signs and/or encrypts data based on parameters of class */ - public PgpSignEncryptResult execute(PgpSignEncryptInputParcel input, CryptoInputParcel cryptoInput, - InputData inputData, OutputStream outputStream) { + private PgpSignEncryptResult executeInternal(PgpSignEncryptInputParcel input, CryptoInputParcel cryptoInput, + InputData inputData, OutputStream outputStream) { int indent = 0; OperationLog log = new OperationLog(); @@ -122,36 +177,37 @@ public class PgpSignEncryptOperation extends BaseOperation { log.add(LogType.MSG_PSE, indent); indent += 1; - boolean enableSignature = input.getSignatureMasterKeyId() != Constants.key.none; - boolean enableEncryption = ((input.getEncryptionMasterKeyIds() != null && input.getEncryptionMasterKeyIds().length > 0) - || input.getSymmetricPassphrase() != null); - boolean enableCompression = (input.getCompressionAlgorithm() != CompressionAlgorithmTags.UNCOMPRESSED); + PgpSignEncryptData data = input.getData(); + boolean enableSignature = data.getSignatureMasterKeyId() != Constants.key.none; + boolean enableEncryption = ((data.getEncryptionMasterKeyIds() != null && data.getEncryptionMasterKeyIds().length > 0) + || data.getSymmetricPassphrase() != null); + boolean enableCompression = (data.getCompressionAlgorithm() != CompressionAlgorithmTags.UNCOMPRESSED); Log.d(Constants.TAG, "enableSignature:" + enableSignature + "\nenableEncryption:" + enableEncryption + "\nenableCompression:" + enableCompression - + "\nenableAsciiArmorOutput:" + input.isEnableAsciiArmorOutput() - + "\nisHiddenRecipients:" + input.isHiddenRecipients()); + + "\nenableAsciiArmorOutput:" + data.isEnableAsciiArmorOutput() + + "\nisHiddenRecipients:" + data.isHiddenRecipients()); // add additional key id to encryption ids (mostly to do self-encryption) - if (enableEncryption && input.getAdditionalEncryptId() != Constants.key.none) { - input.setEncryptionMasterKeyIds(Arrays.copyOf(input.getEncryptionMasterKeyIds(), input.getEncryptionMasterKeyIds().length + 1)); - input.getEncryptionMasterKeyIds()[input.getEncryptionMasterKeyIds().length - 1] = input.getAdditionalEncryptId(); + if (enableEncryption && data.getAdditionalEncryptId() != Constants.key.none) { + data.setEncryptionMasterKeyIds(Arrays.copyOf(data.getEncryptionMasterKeyIds(), data.getEncryptionMasterKeyIds().length + 1)); + data.getEncryptionMasterKeyIds()[data.getEncryptionMasterKeyIds().length - 1] = data.getAdditionalEncryptId(); } ArmoredOutputStream armorOut = null; OutputStream out; - if (input.isEnableAsciiArmorOutput()) { + if (data.isEnableAsciiArmorOutput()) { armorOut = new ArmoredOutputStream(new BufferedOutputStream(outputStream, 1 << 16)); - if (input.getVersionHeader() != null) { - armorOut.setHeader("Version", input.getVersionHeader()); + if (data.getVersionHeader() != null) { + armorOut.setHeader("Version", data.getVersionHeader()); } // if we have a charset, put it in the header - if (input.getCharset() != null) { - armorOut.setHeader("Charset", input.getCharset()); + if (data.getCharset() != null) { + armorOut.setHeader("Charset", data.getCharset()); } // add proprietary header to indicate that this is a key backup - if (input.isAddBackupHeader()) { + if (data.isAddBackupHeader()) { armorOut.setHeader("BackupVersion", "2"); } out = armorOut; @@ -166,12 +222,12 @@ public class PgpSignEncryptOperation extends BaseOperation { updateProgress(R.string.progress_extracting_signature_key, 0, 100); try { - long signingMasterKeyId = input.getSignatureMasterKeyId(); - long signingSubKeyId = input.getSignatureSubKeyId(); + long signingMasterKeyId = data.getSignatureMasterKeyId(); + long signingSubKeyId = data.getSignatureSubKeyId(); CanonicalizedSecretKeyRing signingKeyRing = mProviderHelper.getCanonicalizedSecretKeyRing(signingMasterKeyId); - signingKey = signingKeyRing.getSecretKey(input.getSignatureSubKeyId()); + signingKey = signingKeyRing.getSecretKey(data.getSignatureSubKeyId()); // Make sure key is not expired or revoked @@ -240,9 +296,9 @@ public class PgpSignEncryptOperation extends BaseOperation { } // Use requested hash algo - int requestedAlgorithm = input.getSignatureHashAlgorithm(); + int requestedAlgorithm = data.getSignatureHashAlgorithm(); if (requestedAlgorithm == PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) { - input.setSignatureHashAlgorithm(PgpSecurityConstants.DEFAULT_HASH_ALGORITHM); + data.setSignatureHashAlgorithm(PgpSecurityConstants.DEFAULT_HASH_ALGORITHM); } } updateProgress(R.string.progress_preparing_streams, 2, 100); @@ -252,36 +308,36 @@ public class PgpSignEncryptOperation extends BaseOperation { if (enableEncryption) { // Use requested encryption algo - int algo = input.getSymmetricEncryptionAlgorithm(); + int algo = data.getSymmetricEncryptionAlgorithm(); if (algo == PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) { algo = PgpSecurityConstants.DEFAULT_SYMMETRIC_ALGORITHM; } JcePGPDataEncryptorBuilder encryptorBuilder = new JcePGPDataEncryptorBuilder(algo) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME) - .setWithIntegrityPacket(input.isIntegrityProtected()); + .setWithIntegrityPacket(data.isIntegrityProtected()); cPk = new PGPEncryptedDataGenerator(encryptorBuilder); - if (input.getSymmetricPassphrase() != null) { + if (data.getSymmetricPassphrase() != null) { // Symmetric encryption log.add(LogType.MSG_PSE_SYMMETRIC, indent); JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = - new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().getCharArray()); + new JcePBEKeyEncryptionMethodGenerator(data.getSymmetricPassphrase().getCharArray()); cPk.addMethod(symmetricEncryptionGenerator); } else { log.add(LogType.MSG_PSE_ASYMMETRIC, indent); // Asymmetric encryption - for (long id : input.getEncryptionMasterKeyIds()) { + for (long id : data.getEncryptionMasterKeyIds()) { try { CanonicalizedPublicKeyRing keyRing = mProviderHelper.getCanonicalizedPublicKeyRing( KeyRings.buildUnifiedKeyRingUri(id)); Set<Long> encryptSubKeyIds = keyRing.getEncryptIds(); for (Long subKeyId : encryptSubKeyIds) { CanonicalizedPublicKey key = keyRing.getPublicKey(subKeyId); - cPk.addMethod(key.getPubKeyEncryptionGenerator(input.isHiddenRecipients())); + cPk.addMethod(key.getPubKeyEncryptionGenerator(data.isHiddenRecipients())); log.add(LogType.MSG_PSE_KEY_OK, indent + 1, KeyFormattingUtils.convertKeyIdToHex(subKeyId)); } @@ -310,9 +366,9 @@ public class PgpSignEncryptOperation extends BaseOperation { updateProgress(R.string.progress_preparing_signature, 4, 100); try { - boolean cleartext = input.isCleartextSignature() && input.isEnableAsciiArmorOutput() && !enableEncryption; + boolean cleartext = data.isCleartextSignature() && data.isEnableAsciiArmorOutput() && !enableEncryption; signatureGenerator = signingKey.getDataSignatureGenerator( - input.getSignatureHashAlgorithm(), cleartext, + data.getSignatureHashAlgorithm(), cleartext, cryptoInput.getCryptoData(), cryptoInput.getSignatureTime()); } catch (PgpGeneralException e) { log.add(LogType.MSG_PSE_ERROR_NFC, indent); @@ -351,7 +407,7 @@ public class PgpSignEncryptOperation extends BaseOperation { log.add(LogType.MSG_PSE_COMPRESSING, indent); // Use preferred compression algo - int algo = input.getCompressionAlgorithm(); + int algo = data.getCompressionAlgorithm(); if (algo == PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT) { algo = PgpSecurityConstants.DEFAULT_COMPRESSION_ALGORITHM; } @@ -367,7 +423,7 @@ public class PgpSignEncryptOperation extends BaseOperation { PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator(); char literalDataFormatTag; - if (input.isCleartextSignature()) { + if (data.isCleartextSignature()) { literalDataFormatTag = PGPLiteralData.UTF8; } else { literalDataFormatTag = PGPLiteralData.BINARY; @@ -397,14 +453,14 @@ public class PgpSignEncryptOperation extends BaseOperation { literalGen.close(); indent -= 1; - } else if (enableSignature && input.isCleartextSignature() && input.isEnableAsciiArmorOutput()) { + } else if (enableSignature && data.isCleartextSignature() && data.isEnableAsciiArmorOutput()) { /* cleartext signature: sign-only of ascii text */ updateProgress(R.string.progress_signing, 8, 100); log.add(LogType.MSG_PSE_SIGNING_CLEARTEXT, indent); // write -----BEGIN PGP SIGNED MESSAGE----- - armorOut.beginClearText(input.getSignatureHashAlgorithm()); + armorOut.beginClearText(data.getSignatureHashAlgorithm()); InputStream in = new BufferedInputStream(inputData.getInputStream()); final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); @@ -432,7 +488,7 @@ public class PgpSignEncryptOperation extends BaseOperation { armorOut.endClearText(); pOut = new BCPGOutputStream(armorOut); - } else if (enableSignature && input.isDetachedSignature()) { + } else if (enableSignature && data.isDetachedSignature()) { /* detached signature */ updateProgress(R.string.progress_signing, 8, 100); @@ -443,10 +499,10 @@ public class PgpSignEncryptOperation extends BaseOperation { // handle output stream separately for detached signatures detachedByteOut = new ByteArrayOutputStream(); OutputStream detachedOut = detachedByteOut; - if (input.isEnableAsciiArmorOutput()) { + if (data.isEnableAsciiArmorOutput()) { detachedArmorOut = new ArmoredOutputStream(new BufferedOutputStream(detachedOut, 1 << 16)); - if (input.getVersionHeader() != null) { - detachedArmorOut.setHeader("Version", input.getVersionHeader()); + if (data.getVersionHeader() != null) { + detachedArmorOut.setHeader("Version", data.getVersionHeader()); } detachedOut = detachedArmorOut; @@ -469,7 +525,7 @@ public class PgpSignEncryptOperation extends BaseOperation { } pOut = null; - } else if (enableSignature && !input.isCleartextSignature() && !input.isDetachedSignature()) { + } else if (enableSignature && !data.isCleartextSignature() && !data.isDetachedSignature()) { /* sign-only binary (files/data stream) */ updateProgress(R.string.progress_signing, 8, 100); @@ -479,7 +535,7 @@ public class PgpSignEncryptOperation extends BaseOperation { if (enableCompression) { // Use preferred compression algo - int algo = input.getCompressionAlgorithm(); + int algo = data.getCompressionAlgorithm(); if (algo == PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.USE_DEFAULT) { algo = PgpSecurityConstants.DEFAULT_COMPRESSION_ALGORITHM; } @@ -534,7 +590,7 @@ public class PgpSignEncryptOperation extends BaseOperation { } } - opTime = System.currentTimeMillis() -startTime; + opTime = System.currentTimeMillis() - startTime; Log.d(Constants.TAG, "sign/encrypt time taken: " + String.format("%.2f", opTime / 1000.0) + "s"); @@ -591,7 +647,7 @@ public class PgpSignEncryptOperation extends BaseOperation { } result.setDetachedSignature(detachedByteOut.toByteArray()); try { - String digestName = PGPUtil.getDigestName(input.getSignatureHashAlgorithm()); + String digestName = PGPUtil.getDigestName(data.getSignatureHashAlgorithm()); // construct micalg parameter according to https://tools.ietf.org/html/rfc3156#section-5 result.setMicAlgDigestName("pgp-" + digestName.toLowerCase()); } catch (PGPException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java index 8f80a4802..2acd4243a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java @@ -20,41 +20,43 @@ package org.sufficientlysecure.keychain.pgp; import android.net.Uri; import android.os.Parcel; +import android.os.Parcelable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -/** This parcel stores the input of one or more PgpSignEncrypt operations. +/** + * This parcel stores the input of one or more PgpSignEncrypt operations. * All operations will use the same general paramters, differing only in * input and output. Each input/output set depends on the paramters: - * + * <p/> * - Each input uri is individually encrypted/signed * - If a byte array is supplied, it is treated as an input before uris are processed * - The number of output uris must match the number of input uris, plus one more - * if there is a byte array present. + * if there is a byte array present. * - Once the output uris are empty, there must be exactly one input (uri xor bytes) - * left, which will be returned in a byte array as part of the result parcel. - * + * left, which will be returned in a byte array as part of the result parcel. */ -public class SignEncryptParcel extends PgpSignEncryptInputParcel { +public class SignEncryptParcel implements Parcelable { + + private PgpSignEncryptData data; public ArrayList<Uri> mInputUris = new ArrayList<>(); public ArrayList<Uri> mOutputUris = new ArrayList<>(); public byte[] mBytes; - public SignEncryptParcel() { - super(); + public SignEncryptParcel(PgpSignEncryptData data) { + this.data = data; } public SignEncryptParcel(Parcel src) { - super(src); - mInputUris = src.createTypedArrayList(Uri.CREATOR); mOutputUris = src.createTypedArrayList(Uri.CREATOR); mBytes = src.createByteArray(); + data = src.readParcelable(getClass().getClassLoader()); } public boolean isIncomplete() { @@ -85,17 +87,25 @@ public class SignEncryptParcel extends PgpSignEncryptInputParcel { mOutputUris.addAll(outputUris); } + public void setData(PgpSignEncryptData data) { + this.data = data; + } + + public PgpSignEncryptData getData() { + return data; + } + @Override public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeTypedList(mInputUris); dest.writeTypedList(mOutputUris); dest.writeByteArray(mBytes); + + dest.writeParcelable(data, 0); } public static final Creator<SignEncryptParcel> CREATOR = new Creator<SignEncryptParcel>() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 88cd066a2..e20ab67e8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -62,6 +62,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing.UserId; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel; import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; @@ -199,13 +200,14 @@ public class OpenPgpService extends Service { boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); // sign-only - PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel() - .setEnableAsciiArmorOutput(asciiArmor) + PgpSignEncryptData pgpData = new PgpSignEncryptData(); + pgpData.setEnableAsciiArmorOutput(asciiArmor) .setCleartextSignature(cleartextSign) .setDetachedSignature(!cleartextSign) .setVersionHeader(null) .setSignatureHashAlgorithm(PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT); + Intent signKeyIdIntent = getSignKeyMasterId(data); // NOTE: Fallback to return account settings (Old API) if (signKeyIdIntent.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR) @@ -217,18 +219,21 @@ public class OpenPgpService extends Service { if (signKeyId == Constants.key.none) { throw new Exception("No signing key given"); } else { - pseInput.setSignatureMasterKeyId(signKeyId); + pgpData.setSignatureMasterKeyId(signKeyId); // get first usable subkey capable of signing try { long signSubKeyId = mProviderHelper.getCachedPublicKeyRing( - pseInput.getSignatureMasterKeyId()).getSecretSignId(); - pseInput.setSignatureSubKeyId(signSubKeyId); + pgpData.getSignatureMasterKeyId()).getSecretSignId(); + pgpData.setSignatureSubKeyId(signSubKeyId); } catch (PgpKeyNotFoundException e) { throw new Exception("signing subkey not found!", e); } } + + PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel(pgpData); + // Get Input- and OutputStream from ParcelFileDescriptor if (!cleartextSign) { // output stream only needed for cleartext signatures, @@ -335,8 +340,8 @@ public class OpenPgpService extends Service { long inputLength = inputStream.available(); InputData inputData = new InputData(inputStream, inputLength, originalFilename); - PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel(); - pseInput.setEnableAsciiArmorOutput(asciiArmor) + PgpSignEncryptData pgpData = new PgpSignEncryptData(); + pgpData.setEnableAsciiArmorOutput(asciiArmor) .setVersionHeader(null) .setCompressionAlgorithm(compressionId) .setSymmetricEncryptionAlgorithm(PgpSecurityConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_DEFAULT) @@ -354,20 +359,20 @@ public class OpenPgpService extends Service { if (signKeyId == Constants.key.none) { throw new Exception("No signing key given"); } else { - pseInput.setSignatureMasterKeyId(signKeyId); + pgpData.setSignatureMasterKeyId(signKeyId); // get first usable subkey capable of signing try { long signSubKeyId = mProviderHelper.getCachedPublicKeyRing( - pseInput.getSignatureMasterKeyId()).getSecretSignId(); - pseInput.setSignatureSubKeyId(signSubKeyId); + pgpData.getSignatureMasterKeyId()).getSecretSignId(); + pgpData.setSignatureSubKeyId(signSubKeyId); } catch (PgpKeyNotFoundException e) { throw new Exception("signing subkey not found!", e); } } // sign and encrypt - pseInput.setSignatureHashAlgorithm(PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) + pgpData.setSignatureHashAlgorithm(PgpSecurityConstants.OpenKeychainHashAlgorithmTags.USE_DEFAULT) .setAdditionalEncryptId(signKeyId); // add sign key for encryption } @@ -382,9 +387,11 @@ public class OpenPgpService extends Service { if (accSettings == null || (accSettings.getKeyId() == Constants.key.none)) { return mApiPermissionHelper.getCreateAccountIntent(data, accName); } - pseInput.setAdditionalEncryptId(accSettings.getKeyId()); + pgpData.setAdditionalEncryptId(accSettings.getKeyId()); } + PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel(pgpData); + CryptoInputParcel inputParcel = CryptoInputParcelCacheService.getCryptoInputParcel(this, data); if (inputParcel == null) { inputParcel = new CryptoInputParcel(new Date()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index d5c540856..80bac18e3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -63,6 +63,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -620,9 +621,7 @@ public class EncryptFilesFragment } // fill values for this action - SignEncryptParcel data = new SignEncryptParcel(); - - data.addInputUris(mFilesAdapter.getAsArrayList()); + PgpSignEncryptData data = new PgpSignEncryptData(); if (mUseCompression) { data.setCompressionAlgorithm( @@ -673,7 +672,11 @@ public class EncryptFilesFragment data.setSymmetricPassphrase(passphrase); } - return data; + + SignEncryptParcel parcel = new SignEncryptParcel(data); + parcel.addInputUris(mFilesAdapter.getAsArrayList()); + + return parcel; } private Intent createSendIntent() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 10d88253d..f805c70c3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment; @@ -230,9 +231,8 @@ public class EncryptTextFragment } // fill values for this action - SignEncryptParcel data = new SignEncryptParcel(); + PgpSignEncryptData data = new PgpSignEncryptData(); - data.setBytes(mMessage.getBytes()); data.setCleartextSignature(true); if (mUseCompression) { @@ -283,7 +283,11 @@ public class EncryptTextFragment } data.setSymmetricPassphrase(passphrase); } - return data; + + SignEncryptParcel parcel = new SignEncryptParcel(data); + parcel.setBytes(mMessage.getBytes()); + + return parcel; } private void copyToClipboard(SignEncryptResult result) { |