aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java22
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java80
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java12
m---------extern/openpgp-api-lib0
6 files changed, 91 insertions, 43 deletions
diff --git a/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java
index 703af94f4..7679f8486 100644
--- a/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java
+++ b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java
@@ -6,15 +6,16 @@
package org.bouncycastle.openpgp.operator.jcajce;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
-import java.nio.ByteBuffer;
-import java.util.Map;
-
public class CachingDataDecryptorFactory implements PublicKeyDataDecryptorFactory
{
private final PublicKeyDataDecryptorFactory mWrappedDecryptor;
@@ -59,6 +60,10 @@ public class CachingDataDecryptorFactory implements PublicKeyDataDecryptorFactor
return mSessionKeyCache.get(bi);
}
+ if (mWrappedDecryptor == null) {
+ throw new IllegalStateException("tried to decrypt without wrapped decryptor, this is a bug!");
+ }
+
byte[] sessionData = mWrappedDecryptor.recoverSessionData(keyAlgorithm, secKeyData);
mSessionKeyCache.put(bi, sessionData);
return sessionData;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java
index c4525e5cd..31a3f91b6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpDecryptionResultBuilder.java
@@ -26,6 +26,8 @@ public class OpenPgpDecryptionResultBuilder {
// builder
private boolean mInsecure = false;
private boolean mEncrypted = false;
+ private byte[] sessionKey;
+ private byte[] decryptedSessionKey;
public void setInsecure(boolean insecure) {
this.mInsecure = insecure;
@@ -36,24 +38,26 @@ public class OpenPgpDecryptionResultBuilder {
}
public OpenPgpDecryptionResult build() {
- OpenPgpDecryptionResult result = new OpenPgpDecryptionResult();
-
if (mInsecure) {
Log.d(Constants.TAG, "RESULT_INSECURE");
- result.setResult(OpenPgpDecryptionResult.RESULT_INSECURE);
- return result;
+ return new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_INSECURE, sessionKey, decryptedSessionKey);
}
if (mEncrypted) {
Log.d(Constants.TAG, "RESULT_ENCRYPTED");
- result.setResult(OpenPgpDecryptionResult.RESULT_ENCRYPTED);
- } else {
- Log.d(Constants.TAG, "RESULT_NOT_ENCRYPTED");
- result.setResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED);
+ return new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_ENCRYPTED, sessionKey, decryptedSessionKey);
}
- return result;
+ Log.d(Constants.TAG, "RESULT_NOT_ENCRYPTED");
+ return new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED);
}
+ public void setSessionKey(byte[] sessionKey, byte[] decryptedSessionKey) {
+ if ((sessionKey == null) != (decryptedSessionKey == null)) {
+ throw new AssertionError("sessionKey must be null iff decryptedSessionKey is null!");
+ }
+ this.sessionKey = sessionKey;
+ this.decryptedSessionKey = decryptedSessionKey;
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
index 94606bff9..a27e4a8d5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
@@ -26,9 +26,12 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.security.SignatureException;
import java.util.Date;
import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
import android.content.Context;
import android.support.annotation.NonNull;
@@ -60,7 +63,6 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.key;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.BaseOperation;
-import org.sufficientlysecure.keychain.util.CharsetVerifier;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
@@ -73,6 +75,7 @@ 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.CharsetVerifier;
import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -197,6 +200,10 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
PGPEncryptedData encryptedData;
InputStream cleartextStream;
+ // the cached session key
+ byte[] sessionKey;
+ byte[] decryptedSessionKey;
+
int symmetricEncryptionAlgo = 0;
boolean skippedDisallowedKey = false;
@@ -304,6 +311,9 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
// if this worked out so far, the data is encrypted
decryptionResultBuilder.setEncrypted(true);
+ if (esResult.sessionKey != null && esResult.decryptedSessionKey != null) {
+ decryptionResultBuilder.setSessionKey(esResult.sessionKey, esResult.decryptedSessionKey);
+ }
if (esResult.insecureEncryptionKey) {
log.add(LogType.MSG_DC_INSECURE_SYMMETRIC_ENCRYPTION_ALGO, indent + 1);
@@ -545,10 +555,14 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
boolean asymmetricPacketFound = false;
boolean symmetricPacketFound = false;
boolean anyPacketFound = false;
+ boolean decryptedSessionKeyAvailable = false;
PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
PGPPBEEncryptedData encryptedDataSymmetric = null;
CanonicalizedSecretKey decryptionKey = null;
+ CachingDataDecryptorFactory cachedKeyDecryptorFactory = new CachingDataDecryptorFactory(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME, cryptoInput.getCryptoData());
+ ;
Passphrase passphrase = null;
@@ -569,6 +583,13 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_ASYM, indent,
KeyFormattingUtils.convertKeyIdToHex(subKeyId));
+ decryptedSessionKeyAvailable = cachedKeyDecryptorFactory.hasCachedSessionData(encData);
+ if (decryptedSessionKeyAvailable) {
+ asymmetricPacketFound = true;
+ encryptedDataAsymmetric = encData;
+ break;
+ }
+
CachedPublicKeyRing cachedPublicKeyRing;
try {
// get actual keyring object based on master key id
@@ -746,34 +767,38 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
currentProgress += 2;
updateProgress(R.string.progress_extracting_key, currentProgress, 100);
- try {
- log.add(LogType.MSG_DC_UNLOCKING, indent + 1);
- if (!decryptionKey.unlock(passphrase)) {
- log.add(LogType.MSG_DC_ERROR_BAD_PASSPHRASE, indent + 1);
+ CachingDataDecryptorFactory decryptorFactory;
+ if (decryptedSessionKeyAvailable) {
+ decryptorFactory = cachedKeyDecryptorFactory;
+ } else {
+ try {
+ log.add(LogType.MSG_DC_UNLOCKING, indent + 1);
+ if (!decryptionKey.unlock(passphrase)) {
+ log.add(LogType.MSG_DC_ERROR_BAD_PASSPHRASE, indent + 1);
+ return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log));
+ }
+ } catch (PgpGeneralException e) {
+ log.add(LogType.MSG_DC_ERROR_EXTRACT_KEY, indent + 1);
return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log));
}
- } catch (PgpGeneralException e) {
- log.add(LogType.MSG_DC_ERROR_EXTRACT_KEY, indent + 1);
- return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log));
- }
-
- currentProgress += 2;
- updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
- CachingDataDecryptorFactory decryptorFactory
- = decryptionKey.getCachingDecryptorFactory(cryptoInput);
+ currentProgress += 2;
+ updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
- // special case: if the decryptor does not have a session key cached for this encrypted
- // data, and can't actually decrypt on its own, return a pending intent
- if (!decryptorFactory.canDecrypt()
- && !decryptorFactory.hasCachedSessionData(encryptedDataAsymmetric)) {
+ decryptorFactory = decryptionKey.getCachingDecryptorFactory(cryptoInput);
- log.add(LogType.MSG_DC_PENDING_NFC, indent + 1);
- return result.with(new DecryptVerifyResult(log, RequiredInputParcel.createSecurityTokenDecryptOperation(
- decryptionKey.getRing().getMasterKeyId(),
- decryptionKey.getKeyId(), encryptedDataAsymmetric.getSessionKey()[0]
- ), cryptoInput));
+ // special case: if the decryptor does not have a session key cached for this encrypted
+ // data, and can't actually decrypt on its own, return a pending intent
+ if (!decryptorFactory.canDecrypt()
+ && !decryptorFactory.hasCachedSessionData(encryptedDataAsymmetric)) {
+ log.add(LogType.MSG_DC_PENDING_NFC, indent + 1);
+ return result.with(new DecryptVerifyResult(log,
+ RequiredInputParcel.createSecurityTokenDecryptOperation(
+ decryptionKey.getRing().getMasterKeyId(),
+ decryptionKey.getKeyId(), encryptedDataAsymmetric.getSessionKey()[0]
+ ), cryptoInput));
+ }
}
try {
@@ -786,8 +811,13 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
result.symmetricEncryptionAlgo = encryptedDataAsymmetric.getSymmetricAlgorithm(decryptorFactory);
result.encryptedData = encryptedDataAsymmetric;
- cryptoInput.addCryptoData(decryptorFactory.getCachedSessionKeys());
-
+ Map<ByteBuffer, byte[]> cachedSessionKeys = decryptorFactory.getCachedSessionKeys();
+ cryptoInput.addCryptoData(cachedSessionKeys);
+ if (cachedSessionKeys.size() >= 1) {
+ Entry<ByteBuffer, byte[]> entry = cachedSessionKeys.entrySet().iterator().next();
+ result.sessionKey = entry.getKey().array();
+ result.decryptedSessionKey = entry.getValue();
+ }
} else {
// there wasn't even any useful data
if (!anyPacketFound) {
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 02d9ba62d..e17310b65 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -35,6 +35,7 @@ import android.app.Service;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -453,6 +454,14 @@ public class OpenPgpService extends Service {
cryptoInput.mPassphrase =
new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE));
}
+ if (data.hasExtra(OpenPgpApi.EXTRA_DECRYPTION_RESULT_WRAPPER)) {
+ Bundle wrapperBundle = data.getBundleExtra(OpenPgpApi.EXTRA_DECRYPTION_RESULT_WRAPPER);
+ wrapperBundle.setClassLoader(getClassLoader());
+ OpenPgpDecryptionResult decryptionResult = wrapperBundle.getParcelable(OpenPgpApi.EXTRA_DECRYPTION_RESULT);
+ if (decryptionResult != null && decryptionResult.hasDecryptedSessionKey()) {
+ cryptoInput.addCryptoData(decryptionResult.sessionKey, decryptionResult.decryptedSessionKey);
+ }
+ }
byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
index 849418905..080c34c04 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
@@ -17,18 +17,18 @@
package org.sufficientlysecure.keychain.service.input;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import org.sufficientlysecure.keychain.util.ParcelableProxy;
-import org.sufficientlysecure.keychain.util.Passphrase;
-import java.net.Proxy;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
+import org.sufficientlysecure.keychain.util.Passphrase;
+
/**
* This is a base class for the input of crypto operations.
*/
diff --git a/extern/openpgp-api-lib b/extern/openpgp-api-lib
-Subproject 710a0d8fe8d89cb9a1f247007000a7f49a29c52
+Subproject f027645214ff41a54e15cc46058ce9f1867cad5