diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations')
16 files changed, 434 insertions, 149 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 206212387..ae9a2c180 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java @@ -252,7 +252,7 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> { ring.encode(arOutStream); } catch (PgpGeneralException e) { - log.add(LogType.MSG_BACKUP_ERROR_KEY, 2); + log.add(LogType.MSG_UPLOAD_ERROR_IO, 2); } finally { if (arOutStream != null) { arOutStream.close(); @@ -273,7 +273,7 @@ public class BackupOperation extends BaseOperation<BackupKeyringParcel> { ring.encode(arOutStream); } catch (PgpGeneralException e) { - log.add(LogType.MSG_BACKUP_ERROR_KEY, 2); + log.add(LogType.MSG_UPLOAD_ERROR_IO, 2); } finally { if (arOutStream != null) { arOutStream.close(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java new file mode 100644 index 000000000..f6e157c74 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com> + * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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.operations; + + +import java.util.Random; + +import android.content.Context; +import android.support.annotation.NonNull; + +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.S2K; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; +import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.operations.results.BenchmarkResult; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.BenchmarkInputParcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; +import org.sufficientlysecure.keychain.util.ProgressScaler; + + +public class BenchmarkOperation extends BaseOperation<BenchmarkInputParcel> { + + public BenchmarkOperation(Context context, ProviderHelper providerHelper, Progressable + progressable) { + super(context, providerHelper, progressable); + } + + @NonNull + @Override + public BenchmarkResult execute(BenchmarkInputParcel consolidateInputParcel, + CryptoInputParcel cryptoInputParcel) { + OperationLog log = new OperationLog(); + log.add(LogType.MSG_BENCH, 0); + + // random data + byte[] buf = new byte[1024*1024*5]; + new Random().nextBytes(buf); + + Passphrase passphrase = new Passphrase("a"); + + int numRepeats = 5; + long totalTime = 0; + + // encrypt + SignEncryptResult encryptResult; + int i = 0; + do { + 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.setBytes(buf); + encryptResult = op.execute(input, new CryptoInputParcel()); + log.add(encryptResult, 1); + log.add(LogType.MSG_BENCH_ENC_TIME, 2, + String.format("%.2f", encryptResult.getResults().get(0).mOperationTime / 1000.0)); + totalTime += encryptResult.getResults().get(0).mOperationTime; + } while (++i < numRepeats); + + long encryptionTime = totalTime / numRepeats; + totalTime = 0; + + // decrypt + i = 0; + do { + DecryptVerifyResult decryptResult; + PgpDecryptVerifyOperation op = + new PgpDecryptVerifyOperation(mContext, mProviderHelper, + new ProgressScaler(mProgressable, 50 +i*(50/numRepeats), 50 +(i+1)*(50/numRepeats), 100)); + PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(encryptResult.getResultBytes()); + input.setAllowSymmetricDecryption(true); + decryptResult = op.execute(input, new CryptoInputParcel(passphrase)); + log.add(decryptResult, 1); + log.add(LogType.MSG_BENCH_DEC_TIME, 2, String.format("%.2f", decryptResult.mOperationTime / 1000.0)); + totalTime += decryptResult.mOperationTime; + } while (++i < numRepeats); + + long decryptionTime = totalTime / numRepeats; + totalTime = 0; + + int iterationsFor100ms; + try { + PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(); + PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder( + digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( + "".toCharArray()); + + byte[] iv = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + int iterations = 0; + while (iterations < 255 && totalTime < 100) { + iterations += 1; + + S2K s2k = new S2K(HashAlgorithmTags.SHA1, iv, iterations); + totalTime = System.currentTimeMillis(); + decryptorFactory.makeKeyFromPassPhrase(SymmetricKeyAlgorithmTags.AES_128, s2k); + totalTime = System.currentTimeMillis() -totalTime; + + if ((iterations % 10) == 0) { + log.add(LogType.MSG_BENCH_S2K_FOR_IT, 1, Integer.toString(iterations), Long.toString(totalTime)); + } + + } + iterationsFor100ms = iterations; + + } catch (PGPException e) { + Log.e(Constants.TAG, "internal error during benchmark", e); + log.add(LogType.MSG_INTERNAL_ERROR, 0); + return new BenchmarkResult(BenchmarkResult.RESULT_ERROR, log); + } + + log.add(LogType.MSG_BENCH_S2K_100MS_ITS, 1, Integer.toString(iterationsFor100ms)); + log.add(LogType.MSG_BENCH_ENC_TIME_AVG, 1, String.format("%.2f", encryptionTime/1000.0)); + log.add(LogType.MSG_BENCH_DEC_TIME_AVG, 1, String.format("%.2f", decryptionTime/1000.0)); + + log.add(LogType.MSG_BENCH_SUCCESS, 0); + return new BenchmarkResult(BenchmarkResult.RESULT_OK, log); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java index e1daac874..7d11fa1f1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java @@ -208,7 +208,7 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> { // these variables are used inside the following loop, but they need to be created only once UploadOperation uploadOperation = null; if (parcel.keyServerUri != null) { - uploadOperation = new UploadOperation(mContext, mProviderHelper, mProgressable); + uploadOperation = new UploadOperation(mContext, mProviderHelper, mProgressable, mCancelled); } // Write all certified keys into the database diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index cf8928768..3b2c484be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -26,7 +26,6 @@ import android.support.annotation.NonNull; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; -import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; @@ -73,7 +72,7 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> { * @return the result of the operation */ @NonNull - public InputPendingResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) { + public EditKeyResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) { OperationLog log = new OperationLog(); log.add(LogType.MSG_ED, 0); @@ -100,7 +99,8 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> { modifyResult = keyOperations.modifySecretKeyRing(secRing, cryptoInput, saveParcel); if (modifyResult.isPending()) { - return modifyResult; + log.add(modifyResult, 1); + return new EditKeyResult(log, modifyResult); } } catch (NotFoundException e) { @@ -148,19 +148,16 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> { new UploadKeyringParcel(saveParcel.getUploadKeyserver(), keyringBytes); UploadResult uploadResult = - new UploadOperation(mContext, mProviderHelper, mProgressable) + new UploadOperation(mContext, mProviderHelper, mProgressable, mCancelled) .execute(exportKeyringParcel, cryptoInput); + log.add(uploadResult, 2); + if (uploadResult.isPending()) { - return uploadResult; + return new EditKeyResult(log, uploadResult); } else if (!uploadResult.success() && saveParcel.isUploadAtomic()) { // if atomic, update fail implies edit operation should also fail and not save - log.add(uploadResult, 2); - return new EditKeyResult(log, RequiredInputParcel.createRetryUploadOperation(), - cryptoInput); - } else { - // upload succeeded or not atomic so we continue - log.add(uploadResult, 2); + return new EditKeyResult(log, RequiredInputParcel.createRetryUploadOperation(), cryptoInput); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java index 89575338f..19a05790f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java @@ -28,7 +28,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; -import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -82,6 +82,8 @@ import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; */ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { + public static final int MAX_THREADS = 10; + public ImportOperation(Context context, ProviderHelper providerHelper, Progressable progressable) { super(context, providerHelper, progressable); @@ -133,7 +135,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { @NonNull private ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num, String keyServerUri, Progressable progressable, - Proxy proxy) { + @NonNull Proxy proxy) { if (progressable != null) { progressable.setProgress(R.string.progress_importing, 0, 100); } @@ -188,7 +190,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { // Make sure we have the keyserver instance cached if (keyServer == null) { log.add(LogType.MSG_IMPORT_KEYSERVER, 1, keyServerUri); - keyServer = new HkpKeyserver(keyServerUri); + keyServer = new HkpKeyserver(keyServerUri, proxy); } try { @@ -197,11 +199,10 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { if (entry.mExpectedFingerprint != null) { log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, "0x" + entry.mExpectedFingerprint.substring(24)); - data = keyServer.get("0x" + entry.mExpectedFingerprint, proxy) - .getBytes(); + data = keyServer.get("0x" + entry.mExpectedFingerprint).getBytes(); } else { log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, entry.mKeyIdHex); - data = keyServer.get(entry.mKeyIdHex, proxy).getBytes(); + data = keyServer.get(entry.mKeyIdHex).getBytes(); } key = UncachedKeyRing.decodeFromData(data); if (key != null) { @@ -219,12 +220,12 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { if (entry.mKeybaseName != null) { // Make sure we have this cached if (keybaseServer == null) { - keybaseServer = new KeybaseKeyserver(); + keybaseServer = new KeybaseKeyserver(proxy); } try { log.add(LogType.MSG_IMPORT_FETCH_KEYBASE, 2, entry.mKeybaseName); - byte[] data = keybaseServer.get(entry.mKeybaseName, proxy).getBytes(); + byte[] data = keybaseServer.get(entry.mKeybaseName).getBytes(); UncachedKeyRing keybaseKey = UncachedKeyRing.decodeFromData(data); // If there already is a key, merge the two @@ -261,12 +262,6 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { continue; } - // Another check if we have been cancelled - if (checkCancelled()) { - cancelled = true; - break; - } - SaveKeyringResult result; // synchronizing prevents https://github.com/open-keychain/open-keychain/issues/1221 // and https://github.com/open-keychain/open-keychain/issues/1480 @@ -365,13 +360,15 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { } } - // Final log entry, it's easier to do this individually - if ((newKeys > 0 || updatedKeys > 0) && badKeys > 0) { - log.add(LogType.MSG_IMPORT_PARTIAL, 1); - } else if (newKeys > 0 || updatedKeys > 0) { - log.add(LogType.MSG_IMPORT_SUCCESS, 1); - } else { - log.add(LogType.MSG_IMPORT_ERROR, 1); + if (!cancelled) { + // Final log entry, it's easier to do this individually + if ((newKeys > 0 || updatedKeys > 0) && badKeys > 0) { + log.add(LogType.MSG_IMPORT_PARTIAL, 1); + } else if (newKeys > 0 || updatedKeys > 0) { + log.add(LogType.MSG_IMPORT_SUCCESS, 1); + } else { + log.add(LogType.MSG_IMPORT_ERROR, 1); + } } return new ImportKeyResult(resultType, log, newKeys, updatedKeys, badKeys, secret, @@ -400,8 +397,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { return new ImportKeyResult(null, RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput); } - proxy = Preferences.getPreferences(mContext).getProxyPrefs().parcelableProxy - .getProxy(); + proxy = Preferences.getPreferences(mContext).getProxyPrefs().getProxy(); } else { proxy = cryptoInput.getParcelableProxy().getProxy(); } @@ -414,62 +410,61 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { } @NonNull - private ImportKeyResult multiThreadedKeyImport(Iterator<ParcelableKeyRing> keyListIterator, + private ImportKeyResult multiThreadedKeyImport(@NonNull Iterator<ParcelableKeyRing> keyListIterator, int totKeys, final String keyServer, final Proxy proxy) { Log.d(Constants.TAG, "Multi-threaded key import starting"); - if (keyListIterator != null) { - KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable); - - final ProgressScaler ignoreProgressable = new ProgressScaler(); + KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable); - final int maxThreads = 200; - ExecutorService importExecutor = new ThreadPoolExecutor(0, maxThreads, - 30L, TimeUnit.SECONDS, - new SynchronousQueue<Runnable>()); + final ProgressScaler ignoreProgressable = new ProgressScaler(); - ExecutorCompletionService<ImportKeyResult> importCompletionService = - new ExecutorCompletionService<>(importExecutor); + ExecutorService importExecutor = new ThreadPoolExecutor(0, MAX_THREADS, 30L, TimeUnit.SECONDS, + new LinkedBlockingQueue<Runnable>()); - while (keyListIterator.hasNext()) { // submit all key rings to be imported + ExecutorCompletionService<ImportKeyResult> importCompletionService = + new ExecutorCompletionService<>(importExecutor); - final ParcelableKeyRing pkRing = keyListIterator.next(); + while (keyListIterator.hasNext()) { // submit all key rings to be imported - Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult> - () { + final ParcelableKeyRing pkRing = keyListIterator.next(); - @Override - public ImportKeyResult call() { + Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult> + () { - ArrayList<ParcelableKeyRing> list = new ArrayList<>(); - list.add(pkRing); + @Override + public ImportKeyResult call() { - return serialKeyRingImport(list.iterator(), 1, keyServer, - ignoreProgressable, proxy); + if (checkCancelled()) { + return null; } - }; - importCompletionService.submit(importOperationCallable); - } + ArrayList<ParcelableKeyRing> list = new ArrayList<>(); + list.add(pkRing); - while (!accumulator.isImportFinished()) { // accumulate the results of each import - try { - accumulator.accumulateKeyImport(importCompletionService.take().get()); - } catch (InterruptedException | ExecutionException e) { - Log.e(Constants.TAG, "A key could not be imported during multi-threaded " + - "import", e); - // do nothing? - if (e instanceof ExecutionException) { - // Since serialKeyRingImport does not throw any exceptions, this is what - // would have happened if - // we were importing the key on this thread - throw new RuntimeException(); - } + return serialKeyRingImport(list.iterator(), 1, keyServer, ignoreProgressable, proxy); + } + }; + + importCompletionService.submit(importOperationCallable); + } + + while (!accumulator.isImportFinished()) { // accumulate the results of each import + try { + accumulator.accumulateKeyImport(importCompletionService.take().get()); + } catch (InterruptedException | ExecutionException e) { + Log.e(Constants.TAG, "A key could not be imported during multi-threaded " + + "import", e); + // do nothing? + if (e instanceof ExecutionException) { + // Since serialKeyRingImport does not throw any exceptions, this is what + // would have happened if + // we were importing the key on this thread + throw new RuntimeException(); } } - return accumulator.getConsolidatedResult(); } - return new ImportKeyResult(ImportKeyResult.RESULT_FAIL_NOTHING, new OperationLog()); + return accumulator.getConsolidatedResult(); + } /** @@ -486,6 +481,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { private int mUpdatedKeys = 0; private int mSecret = 0; private int mResultType = 0; + private boolean mHasCancelledResult; /** * Accumulates keyring imports and updates the progressable whenever a new key is imported. @@ -503,14 +499,25 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { } } - public synchronized void accumulateKeyImport(ImportKeyResult result) { + public void accumulateKeyImport(ImportKeyResult result) { mImportedKeys++; + if (result == null) { + return; + } + if (mProgressable != null) { mProgressable.setProgress(mImportedKeys, mTotalKeys); } - mImportLog.addAll(result.getLog().toList());//accumulates log + boolean notCancelledOrFirstCancelled = !result.cancelled() || !mHasCancelledResult; + if (notCancelledOrFirstCancelled) { + mImportLog.addAll(result.getLog().toList()); //accumulates log + if (result.cancelled()) { + mHasCancelledResult = true; + } + } + mBadKeys += result.mBadKeys; mNewKeys += result.mNewKeys; mUpdatedKeys += result.mUpdatedKeys; @@ -533,7 +540,9 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> { // adding required information to mResultType // special case,no keys requested for import - if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0) { + if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0 + && (mResultType & ImportKeyResult.RESULT_CANCELLED) + != ImportKeyResult.RESULT_CANCELLED) { mResultType = ImportKeyResult.RESULT_FAIL_NOTHING; } else { if (mNewKeys > 0) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java index a09cf4f27..bb8d6ad73 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java @@ -110,10 +110,9 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> { if (decryptResult.isPending()) { return new InputDataResult(log, decryptResult); } - log.addByMerge(decryptResult, 2); + log.addByMerge(decryptResult, 1); - if (!decryptResult.success()) { - log.add(LogType.MSG_DATA_ERROR_OPENPGP, 1); + if ( ! decryptResult.success()) { return new InputDataResult(InputDataResult.RESULT_ERROR, log); } @@ -165,6 +164,7 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> { parser.setContentDecoding(true); parser.setRecurse(); parser.setContentHandler(new AbstractContentHandler() { + private boolean mFoundHeaderWithFields = false; private Uri uncheckedSignedDataUri; String mFilename; @@ -221,11 +221,19 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> { } @Override + public void endHeader() throws MimeException { + if ( ! mFoundHeaderWithFields) { + parser.stop(); + } + } + + @Override public void field(Field field) throws MimeException { field = DefaultFieldParser.getParser().parse(field, DecodeMonitor.SILENT); if (field instanceof ContentDispositionField) { mFilename = ((ContentDispositionField) field).getFilename(); } + mFoundHeaderWithFields = true; } private void bodySignature(BodyDescriptor bd, InputStream is) throws MimeException, IOException { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java index 975cf541a..3e787560a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java @@ -19,12 +19,13 @@ package org.sufficientlysecure.keychain.operations; + import android.content.Context; import android.net.Uri; import android.support.annotation.NonNull; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.operations.results.InputPendingResult; +import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.RevokeResult; import org.sufficientlysecure.keychain.pgp.Progressable; @@ -79,9 +80,8 @@ public class RevokeOperation extends BaseOperation<RevokeKeyringParcel> { saveKeyringParcel.mRevokeSubKeys.add(masterKeyId); - InputPendingResult revokeAndUploadResult = new EditKeyOperation(mContext, - mProviderHelper, mProgressable, mCancelled) - .execute(saveKeyringParcel, cryptoInputParcel); + EditKeyResult revokeAndUploadResult = new EditKeyOperation(mContext, + mProviderHelper, mProgressable, mCancelled).execute(saveKeyringParcel, cryptoInputParcel); if (revokeAndUploadResult.isPending()) { return revokeAndUploadResult; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java index bac9a7975..e5f11eaa6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java @@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import android.content.Context; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import org.spongycastle.bcpg.ArmoredOutputStream; import org.sufficientlysecure.keychain.Constants; @@ -47,26 +48,17 @@ 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.Log; +import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.Preferences.ProxyPrefs; import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; /** - * An operation class which implements high level export operations. - * This class receives a source and/or destination of keys as input and performs - * all steps for this export. - * - * @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries() - * For the export operation, the input consists of a set of key ids and - * either the name of a file or an output uri to write to. + * An operation class which implements the upload of a single key to a key server. */ public class UploadOperation extends BaseOperation<UploadKeyringParcel> { - public UploadOperation(Context context, ProviderHelper providerHelper, Progressable - progressable) { - super(context, providerHelper, progressable); - } - public UploadOperation(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean cancelled) { super(context, providerHelper, progressable, cancelled); @@ -74,57 +66,99 @@ public class UploadOperation extends BaseOperation<UploadKeyringParcel> { @NonNull public UploadResult execute(UploadKeyringParcel uploadInput, CryptoInputParcel cryptoInput) { + OperationLog log = new OperationLog(); + + log.add(LogType.MSG_UPLOAD, 0); + updateProgress(R.string.progress_uploading, 0, 1); + Proxy proxy; - if (cryptoInput.getParcelableProxy() == null) { - // explicit proxy not set - if (!OrbotHelper.isOrbotInRequiredState(mContext)) { - return new UploadResult(null, RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput); + { + boolean proxyIsTor = false; + + // Proxy priorities: + // 1. explicit proxy + // 2. orbot proxy state + // 3. proxy from preferences + ParcelableProxy parcelableProxy = cryptoInput.getParcelableProxy(); + if (parcelableProxy != null) { + proxy = parcelableProxy.getProxy(); + } else { + if ( ! OrbotHelper.isOrbotInRequiredState(mContext)) { + return new UploadResult(log, RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput); + } + ProxyPrefs proxyPrefs = Preferences.getPreferences(mContext).getProxyPrefs(); + if (proxyPrefs.torEnabled) { + proxyIsTor = true; + } + proxy = proxyPrefs.getProxy(); } - proxy = Preferences.getPreferences(mContext).getProxyPrefs().parcelableProxy.getProxy(); - } else { - proxy = cryptoInput.getParcelableProxy().getProxy(); + + if (proxyIsTor) { + log.add(LogType.MSG_UPLOAD_PROXY_TOR, 1); + } else if (proxy == Proxy.NO_PROXY) { + log.add(LogType.MSG_UPLOAD_PROXY_DIRECT, 1); + } else { + log.add(LogType.MSG_UPLOAD_PROXY, 1, proxy.toString()); + } + + } + + HkpKeyserver hkpKeyserver; + { + hkpKeyserver = new HkpKeyserver(uploadInput.mKeyserver, proxy); + log.add(LogType.MSG_UPLOAD_SERVER, 1, hkpKeyserver.toString()); + } + + CanonicalizedPublicKeyRing keyring = getPublicKeyringFromInput(log, uploadInput); + if (keyring == null) { + return new UploadResult(UploadResult.RESULT_ERROR, log); + } + + return uploadKeyRingToServer(log, hkpKeyserver, keyring); + } + + @Nullable + private CanonicalizedPublicKeyRing getPublicKeyringFromInput(OperationLog log, UploadKeyringParcel uploadInput) { + + boolean hasMasterKeyId = uploadInput.mMasterKeyId != null; + boolean hasKeyringBytes = uploadInput.mUncachedKeyringBytes != null; + if (hasMasterKeyId == hasKeyringBytes) { + throw new IllegalArgumentException("either keyid xor bytes must be non-null for this method call!"); } - HkpKeyserver hkpKeyserver = new HkpKeyserver(uploadInput.mKeyserver); try { - CanonicalizedPublicKeyRing keyring; - if (uploadInput.mMasterKeyId != null) { - keyring = mProviderHelper.getCanonicalizedPublicKeyRing( - uploadInput.mMasterKeyId); - } else if (uploadInput.mUncachedKeyringBytes != null) { - CanonicalizedKeyRing canonicalizedRing = - UncachedKeyRing.decodeFromData(uploadInput.mUncachedKeyringBytes) - .canonicalize(new OperationLog(), 0, true); - if ( ! CanonicalizedPublicKeyRing.class.isInstance(canonicalizedRing)) { - throw new AssertionError("keyring bytes must contain public key ring!"); - } - keyring = (CanonicalizedPublicKeyRing) canonicalizedRing; - } else { - throw new AssertionError("key id or bytes must be non-null!"); + + if (hasMasterKeyId) { + log.add(LogType.MSG_UPLOAD_KEY, 0, KeyFormattingUtils.convertKeyIdToHex(uploadInput.mMasterKeyId)); + return mProviderHelper.getCanonicalizedPublicKeyRing(uploadInput.mMasterKeyId); } - return uploadKeyRingToServer(hkpKeyserver, keyring, proxy); + + CanonicalizedKeyRing canonicalizedRing = + UncachedKeyRing.decodeFromData(uploadInput.mUncachedKeyringBytes) + .canonicalize(new OperationLog(), 0, true); + if ( ! CanonicalizedPublicKeyRing.class.isInstance(canonicalizedRing)) { + throw new IllegalArgumentException("keyring bytes must contain public key ring!"); + } + log.add(LogType.MSG_UPLOAD_KEY, 0, KeyFormattingUtils.convertKeyIdToHex(canonicalizedRing.getMasterKeyId())); + return (CanonicalizedPublicKeyRing) canonicalizedRing; + } catch (ProviderHelper.NotFoundException e) { + log.add(LogType.MSG_UPLOAD_ERROR_NOT_FOUND, 1); + return null; + } catch (IOException | PgpGeneralException e) { + log.add(LogType.MSG_UPLOAD_ERROR_IO, 1); Log.e(Constants.TAG, "error uploading key", e); - return new UploadResult(UploadResult.RESULT_ERROR, new OperationLog()); - } catch (IOException e) { - e.printStackTrace(); - return new UploadResult(UploadResult.RESULT_ERROR, new OperationLog()); - } catch (PgpGeneralException e) { - e.printStackTrace(); - return new UploadResult(UploadResult.RESULT_ERROR, new OperationLog()); + return null; } - } - UploadResult uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring, Proxy proxy) { + } - mProgressable.setProgress(R.string.progress_uploading, 0, 1); + @NonNull + private UploadResult uploadKeyRingToServer( + OperationLog log, HkpKeyserver server, CanonicalizedPublicKeyRing keyring) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ArmoredOutputStream aos = null; - OperationLog log = new OperationLog(); - log.add(LogType.MSG_BACKUP_UPLOAD_PUBLIC, 0, KeyFormattingUtils.convertKeyIdToHex( - keyring.getPublicKey().getKeyId() - )); try { aos = new ArmoredOutputStream(bos); @@ -132,22 +166,23 @@ public class UploadOperation extends BaseOperation<UploadKeyringParcel> { aos.close(); String armoredKey = bos.toString("UTF-8"); - server.add(armoredKey, proxy); + server.add(armoredKey); + + updateProgress(R.string.progress_uploading, 1, 1); - log.add(LogType.MSG_BACKUP_UPLOAD_SUCCESS, 1); + log.add(LogType.MSG_UPLOAD_SUCCESS, 1); return new UploadResult(UploadResult.RESULT_OK, log); } catch (IOException e) { Log.e(Constants.TAG, "IOException", e); - log.add(LogType.MSG_BACKUP_ERROR_KEY, 1); + log.add(LogType.MSG_UPLOAD_ERROR_IO, 1); return new UploadResult(UploadResult.RESULT_ERROR, log); } catch (AddKeyException e) { Log.e(Constants.TAG, "AddKeyException", e); - log.add(LogType.MSG_BACKUP_ERROR_UPLOAD, 1); + log.add(LogType.MSG_UPLOAD_ERROR_UPLOAD, 1); return new UploadResult(UploadResult.RESULT_ERROR, log); } finally { - mProgressable.setProgress(R.string.progress_uploading, 1, 1); try { if (aos != null) { aos.close(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/BenchmarkResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/BenchmarkResult.java new file mode 100644 index 000000000..473ae9886 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/BenchmarkResult.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 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.operations.results; + +import android.os.Parcel; + + +public class BenchmarkResult extends OperationResult { + + public BenchmarkResult(int result, OperationLog log) { + super(result, log); + } + + /** Construct from a parcel - trivial because we have no extra data. */ + public BenchmarkResult(Parcel source) { + super(source); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } + + public static Creator<BenchmarkResult> CREATOR = new Creator<BenchmarkResult>() { + public BenchmarkResult createFromParcel(final Parcel source) { + return new BenchmarkResult(source); + } + + public BenchmarkResult[] newArray(final int size) { + return new BenchmarkResult[size]; + } + }; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java index 95cf179af..f19ba5250 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java @@ -39,6 +39,8 @@ public class DecryptVerifyResult extends InputPendingResult { byte[] mOutputBytes; + public long mOperationTime; + public DecryptVerifyResult(int result, OperationLog log) { super(result, log); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java index 6098d59d5..fa383a7b5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java @@ -38,6 +38,11 @@ public class EditKeyResult extends InputPendingResult { mMasterKeyId = null; } + public EditKeyResult(OperationLog log, InputPendingResult result) { + super(log, result); + mMasterKeyId = null; + } + public EditKeyResult(Parcel source) { super(source); mMasterKeyId = source.readInt() != 0 ? source.readLong() : null; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java index 0a8c1f653..ed6674ef7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; +import android.support.annotation.NonNull; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -32,13 +33,13 @@ public class InputPendingResult extends OperationResult { // in case operation needs to add to/changes the cryptoInputParcel sent to it public final CryptoInputParcel mCryptoInputParcel; - public InputPendingResult(int result, OperationLog log) { + public InputPendingResult(int result, @NonNull OperationLog log) { super(result, log); mRequiredInput = null; mCryptoInputParcel = null; } - public InputPendingResult(OperationLog log, InputPendingResult result) { + public InputPendingResult(@NonNull OperationLog log, @NonNull InputPendingResult result) { super(RESULT_PENDING, log); if (!result.isPending()) { throw new AssertionError("sub result must be pending!"); @@ -47,7 +48,7 @@ public class InputPendingResult extends OperationResult { mCryptoInputParcel = result.mCryptoInputParcel; } - public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput, + public InputPendingResult(@NonNull OperationLog log, RequiredInputParcel requiredInput, CryptoInputParcel cryptoInputParcel) { super(RESULT_PENDING, log); mRequiredInput = requiredInput; 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 0b8c3e6c7..9877f2318 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 @@ -635,6 +635,8 @@ public abstract class OperationResult implements Parcelable { MSG_EK_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_ek_error_not_found), // decryptverify + MSG_DC_ASKIP_BAD_FLAGS (LogLevel.DEBUG, R.string.msg_dc_askip_bad_flags), + MSG_DC_ASKIP_UNAVAILABLE (LogLevel.DEBUG, R.string.msg_dc_askip_unavailable), MSG_DC_ASKIP_NO_KEY (LogLevel.DEBUG, R.string.msg_dc_askip_no_key), MSG_DC_ASKIP_NOT_ALLOWED (LogLevel.DEBUG, R.string.msg_dc_askip_not_allowed), MSG_DC_ASYM (LogLevel.DEBUG, R.string.msg_dc_asym), @@ -766,17 +768,24 @@ public abstract class OperationResult implements Parcelable { MSG_IMPORT_SUCCESS (LogLevel.OK, R.string.msg_import_success), MSG_BACKUP(LogLevel.START, R.plurals.msg_backup), - MSG_BACKUP_UPLOAD_PUBLIC(LogLevel.START, R.string.msg_backup_upload_public), MSG_BACKUP_PUBLIC(LogLevel.DEBUG, R.string.msg_backup_public), MSG_BACKUP_SECRET(LogLevel.DEBUG, R.string.msg_backup_secret), MSG_BACKUP_ALL(LogLevel.START, R.string.msg_backup_all), MSG_BACKUP_ERROR_URI_OPEN(LogLevel.ERROR, R.string.msg_backup_error_uri_open), MSG_BACKUP_ERROR_DB(LogLevel.ERROR, R.string.msg_backup_error_db), MSG_BACKUP_ERROR_IO(LogLevel.ERROR, R.string.msg_backup_error_io), - MSG_BACKUP_ERROR_KEY(LogLevel.ERROR, R.string.msg_backup_error_key), - MSG_BACKUP_ERROR_UPLOAD(LogLevel.ERROR, R.string.msg_backup_error_upload), MSG_BACKUP_SUCCESS(LogLevel.OK, R.string.msg_backup_success), - MSG_BACKUP_UPLOAD_SUCCESS(LogLevel.OK, R.string.msg_backup_upload_success), + + MSG_UPLOAD(LogLevel.START, R.string.msg_upload), + MSG_UPLOAD_KEY(LogLevel.INFO, R.string.msg_upload_key), + MSG_UPLOAD_PROXY_DIRECT(LogLevel.DEBUG, R.string.msg_upload_proxy_direct), + MSG_UPLOAD_PROXY_TOR(LogLevel.DEBUG, R.string.msg_upload_proxy_tor), + MSG_UPLOAD_PROXY(LogLevel.DEBUG, R.string.msg_upload_proxy), + MSG_UPLOAD_SERVER(LogLevel.DEBUG, R.string.msg_upload_server), + MSG_UPLOAD_SUCCESS(LogLevel.OK, R.string.msg_upload_success), + MSG_UPLOAD_ERROR_NOT_FOUND(LogLevel.ERROR, R.string.msg_upload_error_not_found), + MSG_UPLOAD_ERROR_IO(LogLevel.ERROR, R.string.msg_upload_error_key), + MSG_UPLOAD_ERROR_UPLOAD(LogLevel.ERROR, R.string.msg_upload_error_upload), MSG_CRT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_crt_upload_success), @@ -827,7 +836,6 @@ public abstract class OperationResult implements Parcelable { MSG_DATA (LogLevel.START, R.string.msg_data), MSG_DATA_OPENPGP (LogLevel.DEBUG, R.string.msg_data_openpgp), MSG_DATA_ERROR_IO (LogLevel.ERROR, R.string.msg_data_error_io), - MSG_DATA_ERROR_OPENPGP (LogLevel.ERROR, R.string.msg_data_error_openpgp), MSG_DATA_DETACHED (LogLevel.INFO, R.string.msg_data_detached), MSG_DATA_DETACHED_CLEAR (LogLevel.WARN, R.string.msg_data_detached_clear), MSG_DATA_DETACHED_SIG (LogLevel.DEBUG, R.string.msg_data_detached_sig), @@ -867,6 +875,16 @@ public abstract class OperationResult implements Parcelable { MSG_LV_FETCH_ERROR_IO (LogLevel.ERROR, R.string.msg_lv_fetch_error_io), MSG_LV_FETCH_ERROR_FORMAT(LogLevel.ERROR, R.string.msg_lv_fetch_error_format), MSG_LV_FETCH_ERROR_NOTHING (LogLevel.ERROR, R.string.msg_lv_fetch_error_nothing), + + MSG_BENCH (LogLevel.START, R.string.msg_bench), + MSG_BENCH_ENC_TIME (LogLevel.DEBUG, R.string.msg_bench_enc_time), + MSG_BENCH_ENC_TIME_AVG (LogLevel.INFO, R.string.msg_bench_enc_time_avg), + MSG_BENCH_DEC_TIME (LogLevel.DEBUG, R.string.msg_bench_dec_time), + MSG_BENCH_DEC_TIME_AVG (LogLevel.INFO, R.string.msg_bench_enc_time_avg), + MSG_BENCH_S2K_FOR_IT (LogLevel.DEBUG, R.string.msg_bench_s2k_for_it), + MSG_BENCH_S2K_100MS_ITS (LogLevel.INFO, R.string.msg_bench_s2k_100ms_its), + MSG_BENCH_SUCCESS (LogLevel.OK, R.string.msg_bench_success), + ; public final int mMsgId; 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 2b33b8ace..12b091e32 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 @@ -26,6 +26,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; public class PgpSignEncryptResult extends InputPendingResult { byte[] mDetachedSignature; + public long mOperationTime; public void setDetachedSignature(byte[] detachedSignature) { mDetachedSignature = detachedSignature; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java index 0e0c5d598..60f47be3c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java @@ -56,6 +56,10 @@ public class SignEncryptResult extends InputPendingResult { return mResultBytes; } + public ArrayList<PgpSignEncryptResult> getResults() { + return mResults; + } + public int describeContents() { return 0; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/UploadResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/UploadResult.java index a88072de3..ea2b373a9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/UploadResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/UploadResult.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; +import android.support.annotation.NonNull; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -38,7 +39,7 @@ public class UploadResult extends InputPendingResult { } - public UploadResult(OperationLog log, RequiredInputParcel requiredInputParcel, + public UploadResult(@NonNull OperationLog log, RequiredInputParcel requiredInputParcel, CryptoInputParcel cryptoInputParcel) { super(log, requiredInputParcel, cryptoInputParcel); // we won't use these values |