introduce CachingDataDecryptorFactory towards cached session keys
this commit introduces the CachingDataDecryptorFactory, which wraps a DataDecryptorFactory but supports caching of decrypted session keys. this change also gets rid of runtimeexception based control flow in PgpDecryptVerify.
This commit is contained in:
@@ -21,23 +21,18 @@ package org.sufficientlysecure.keychain.pgp;
|
||||
import org.spongycastle.bcpg.S2K;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.spongycastle.openpgp.PGPSignatureGenerator;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
||||
import org.spongycastle.openpgp.operator.jcajce.CachingDataDecryptorFactory;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPublicKeyDataDecryptorFactoryBuilder;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
@@ -51,7 +46,6 @@ import java.security.interfaces.RSAPrivateCrtKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@@ -270,19 +264,20 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
public PublicKeyDataDecryptorFactory getDecryptorFactory(CryptoInputParcel cryptoInput) {
|
||||
public CachingDataDecryptorFactory getCachingDecryptorFactory(CryptoInputParcel cryptoInput) {
|
||||
if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
|
||||
throw new PrivateKeyNotUnlockedException();
|
||||
}
|
||||
|
||||
if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
|
||||
return new NfcSyncPublicKeyDataDecryptorFactoryBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
cryptoInput.getCryptoData()
|
||||
);
|
||||
return new CachingDataDecryptorFactory(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME,
|
||||
cryptoInput.getCryptoData());
|
||||
} else {
|
||||
return new JcePublicKeyDataDecryptorFactoryBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey);
|
||||
return new CachingDataDecryptorFactory(
|
||||
new JcePublicKeyDataDecryptorFactoryBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey),
|
||||
cryptoInput.getCryptoData());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.webkit.MimeTypeMap;
|
||||
import org.openintents.openpgp.OpenPgpMetadata;
|
||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||
import org.spongycastle.bcpg.ArmoredInputStream;
|
||||
import org.spongycastle.bcpg.PublicKeyEncSessionPacket;
|
||||
import org.spongycastle.openpgp.PGPCompressedData;
|
||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||
import org.spongycastle.openpgp.PGPEncryptedDataList;
|
||||
@@ -40,11 +41,10 @@ import org.spongycastle.openpgp.PGPUtil;
|
||||
import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory;
|
||||
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
|
||||
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
|
||||
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
||||
import org.spongycastle.openpgp.operator.jcajce.CachingDataDecryptorFactory;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPublicKeyDataDecryptorFactoryBuilder;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.BaseOperation;
|
||||
@@ -541,24 +541,33 @@ public class PgpDecryptVerify extends BaseOperation {
|
||||
currentProgress += 2;
|
||||
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
|
||||
|
||||
try {
|
||||
PublicKeyDataDecryptorFactory decryptorFactory
|
||||
= secretEncryptionKey.getDecryptorFactory(cryptoInput);
|
||||
try {
|
||||
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
|
||||
} catch (PGPKeyValidationException | ArrayIndexOutOfBoundsException e) {
|
||||
log.add(LogType.MSG_DC_ERROR_CORRUPT_DATA, indent + 1);
|
||||
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
|
||||
}
|
||||
CachingDataDecryptorFactory decryptorFactory
|
||||
= secretEncryptionKey.getCachingDecryptorFactory(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)) {
|
||||
|
||||
symmetricEncryptionAlgo = encryptedDataAsymmetric.getSymmetricAlgorithm(decryptorFactory);
|
||||
} catch (NfcSyncPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) {
|
||||
log.add(LogType.MSG_DC_PENDING_NFC, indent + 1);
|
||||
return new DecryptVerifyResult(log, RequiredInputParcel.createNfcDecryptOperation(
|
||||
secretEncryptionKey.getRing().getMasterKeyId(),
|
||||
secretEncryptionKey.getKeyId(), e.encryptedSessionKey
|
||||
secretEncryptionKey.getKeyId(), encryptedDataAsymmetric.getSessionKey()[0]
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
|
||||
} catch (PGPKeyValidationException | ArrayIndexOutOfBoundsException e) {
|
||||
log.add(LogType.MSG_DC_ERROR_CORRUPT_DATA, indent + 1);
|
||||
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
symmetricEncryptionAlgo = encryptedDataAsymmetric.getSymmetricAlgorithm(decryptorFactory);
|
||||
|
||||
cryptoInput.addCryptoData(decryptorFactory.getCachedSessionKeys());
|
||||
|
||||
encryptedData = encryptedDataAsymmetric;
|
||||
} else {
|
||||
// there wasn't even any useful data
|
||||
@@ -821,6 +830,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
||||
// Return a positive result, with metadata and verification info
|
||||
DecryptVerifyResult result =
|
||||
new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
|
||||
result.setCachedCryptoInputParcel(cryptoInput);
|
||||
result.setDecryptMetadata(metadata);
|
||||
result.setSignatureResult(signatureResultBuilder.build());
|
||||
result.setCharset(charset);
|
||||
|
||||
Reference in New Issue
Block a user