mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
Fix symmetric decryption
This commit is contained in:
parent
fadc08480f
commit
ebb7f55921
@ -18,16 +18,38 @@
|
|||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.spongycastle.bcpg.ArmoredInputStream;
|
import org.spongycastle.bcpg.ArmoredInputStream;
|
||||||
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
||||||
import org.spongycastle.openpgp.*;
|
import org.spongycastle.openpgp.PGPCompressedData;
|
||||||
|
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||||
|
import org.spongycastle.openpgp.PGPEncryptedDataList;
|
||||||
|
import org.spongycastle.openpgp.PGPException;
|
||||||
|
import org.spongycastle.openpgp.PGPLiteralData;
|
||||||
|
import org.spongycastle.openpgp.PGPObjectFactory;
|
||||||
|
import org.spongycastle.openpgp.PGPOnePassSignature;
|
||||||
|
import org.spongycastle.openpgp.PGPOnePassSignatureList;
|
||||||
|
import org.spongycastle.openpgp.PGPPBEEncryptedData;
|
||||||
|
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
|
import org.spongycastle.openpgp.PGPSignatureList;
|
||||||
|
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||||
import org.spongycastle.openpgp.PGPUtil;
|
import org.spongycastle.openpgp.PGPUtil;
|
||||||
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
|
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
|
||||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
|
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
|
||||||
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
||||||
import org.spongycastle.openpgp.operator.jcajce.*;
|
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.JcePBESecretKeyDecryptorBuilder;
|
||||||
|
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
@ -37,7 +59,12 @@ import org.sufficientlysecure.keychain.util.InputData;
|
|||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
|
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
@ -50,7 +77,7 @@ public class PgpDecryptVerify {
|
|||||||
private OutputStream mOutStream;
|
private OutputStream mOutStream;
|
||||||
|
|
||||||
private ProgressDialogUpdater mProgressDialogUpdater;
|
private ProgressDialogUpdater mProgressDialogUpdater;
|
||||||
private boolean mAssumeSymmetric;
|
private boolean mAllowSymmetricDecryption;
|
||||||
private String mPassphrase;
|
private String mPassphrase;
|
||||||
private long mEnforcedKeyId;
|
private long mEnforcedKeyId;
|
||||||
|
|
||||||
@ -61,7 +88,7 @@ public class PgpDecryptVerify {
|
|||||||
this.mOutStream = builder.mOutStream;
|
this.mOutStream = builder.mOutStream;
|
||||||
|
|
||||||
this.mProgressDialogUpdater = builder.mProgressDialogUpdater;
|
this.mProgressDialogUpdater = builder.mProgressDialogUpdater;
|
||||||
this.mAssumeSymmetric = builder.mAssumeSymmetric;
|
this.mAllowSymmetricDecryption = builder.mAllowSymmetricDecryption;
|
||||||
this.mPassphrase = builder.mPassphrase;
|
this.mPassphrase = builder.mPassphrase;
|
||||||
this.mEnforcedKeyId = builder.mEnforcedKeyId;
|
this.mEnforcedKeyId = builder.mEnforcedKeyId;
|
||||||
}
|
}
|
||||||
@ -74,7 +101,7 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
// optional
|
// optional
|
||||||
private ProgressDialogUpdater mProgressDialogUpdater = null;
|
private ProgressDialogUpdater mProgressDialogUpdater = null;
|
||||||
private boolean mAssumeSymmetric = false;
|
private boolean mAllowSymmetricDecryption = false;
|
||||||
private String mPassphrase = null;
|
private String mPassphrase = null;
|
||||||
private long mEnforcedKeyId = 0;
|
private long mEnforcedKeyId = 0;
|
||||||
|
|
||||||
@ -89,8 +116,8 @@ public class PgpDecryptVerify {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder assumeSymmetric(boolean assumeSymmetric) {
|
public Builder allowSymmetricDecryption(boolean allowSymmetricDecryption) {
|
||||||
this.mAssumeSymmetric = assumeSymmetric;
|
this.mAllowSymmetricDecryption = allowSymmetricDecryption;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,35 +155,6 @@ public class PgpDecryptVerify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
|
|
||||||
throws PgpGeneralException, IOException {
|
|
||||||
InputStream in = PGPUtil.getDecoderStream(inputStream);
|
|
||||||
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
|
||||||
PGPEncryptedDataList enc;
|
|
||||||
Object o = pgpF.nextObject();
|
|
||||||
|
|
||||||
// the first object might be a PGP marker packet.
|
|
||||||
if (o instanceof PGPEncryptedDataList) {
|
|
||||||
enc = (PGPEncryptedDataList) o;
|
|
||||||
} else {
|
|
||||||
enc = (PGPEncryptedDataList) pgpF.nextObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc == null) {
|
|
||||||
throw new PgpGeneralException(context.getString(R.string.error_invalid_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<?> it = enc.getEncryptedDataObjects();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
Object obj = it.next();
|
|
||||||
if (obj instanceof PGPPBEEncryptedData) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts and/or verifies data based on parameters of class
|
* Decrypts and/or verifies data based on parameters of class
|
||||||
*
|
*
|
||||||
@ -221,41 +219,11 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
currentProgress += 5;
|
currentProgress += 5;
|
||||||
|
|
||||||
// TODO: currently we always only look at the first known key or symmetric encryption,
|
PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
|
||||||
// there might be more...
|
PGPPBEEncryptedData encryptedDataSymmetric = null;
|
||||||
if (mAssumeSymmetric) {
|
|
||||||
PGPPBEEncryptedData pbe = null;
|
|
||||||
Iterator<?> it = enc.getEncryptedDataObjects();
|
|
||||||
// find secret key
|
|
||||||
while (it.hasNext()) {
|
|
||||||
Object obj = it.next();
|
|
||||||
if (obj instanceof PGPPBEEncryptedData) {
|
|
||||||
pbe = (PGPPBEEncryptedData) obj;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pbe == null) {
|
|
||||||
throw new PgpGeneralException(
|
|
||||||
mContext.getString(R.string.error_no_symmetric_encryption_packet));
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
|
|
||||||
|
|
||||||
PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder()
|
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
|
|
||||||
PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
|
|
||||||
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
|
||||||
mPassphrase.toCharArray());
|
|
||||||
|
|
||||||
clear = pbe.getDataStream(decryptorFactory);
|
|
||||||
|
|
||||||
encryptedData = pbe;
|
|
||||||
currentProgress += 5;
|
|
||||||
} else {
|
|
||||||
PGPPublicKeyEncryptedData pbe = null;
|
|
||||||
PGPSecretKey secretKey = null;
|
PGPSecretKey secretKey = null;
|
||||||
Iterator<?> it = enc.getEncryptedDataObjects();
|
Iterator<?> it = enc.getEncryptedDataObjects();
|
||||||
|
boolean symmetricPacketFound = false;
|
||||||
// find secret key
|
// find secret key
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Object obj = it.next();
|
Object obj = it.next();
|
||||||
@ -283,7 +251,7 @@ public class PgpDecryptVerify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pbe = encData;
|
encryptedDataAsymmetric = encData;
|
||||||
|
|
||||||
// if no passphrase was explicitly set try to get it from the cache service
|
// if no passphrase was explicitly set try to get it from the cache service
|
||||||
if (mPassphrase == null) {
|
if (mPassphrase == null) {
|
||||||
@ -300,13 +268,42 @@ public class PgpDecryptVerify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// break out of while, only get first object here
|
||||||
|
// TODO???: There could be more pgp objects, which are not decrypted!
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (obj instanceof PGPPBEEncryptedData) {
|
} else if (mAllowSymmetricDecryption && obj instanceof PGPPBEEncryptedData) {
|
||||||
|
symmetricPacketFound = true;
|
||||||
|
|
||||||
|
encryptedDataSymmetric = (PGPPBEEncryptedData) obj;
|
||||||
|
|
||||||
|
// if no passphrase is given, return here
|
||||||
|
// indicating that a passphrase is missing!
|
||||||
|
if (mPassphrase == null) {
|
||||||
|
returnData.setStatus(PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED);
|
||||||
|
return returnData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// break out of while, only get first object here
|
||||||
|
// TODO???: There could be more pgp objects, which are not decrypted!
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (symmetricPacketFound) {
|
||||||
|
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
|
||||||
|
|
||||||
|
PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder()
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
|
||||||
|
PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
|
||||||
|
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||||
|
mPassphrase.toCharArray());
|
||||||
|
|
||||||
|
clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
|
||||||
|
|
||||||
|
encryptedData = encryptedDataSymmetric;
|
||||||
|
currentProgress += 5;
|
||||||
|
} else {
|
||||||
if (secretKey == null) {
|
if (secretKey == null) {
|
||||||
throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
|
throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
|
||||||
}
|
}
|
||||||
@ -332,9 +329,9 @@ public class PgpDecryptVerify {
|
|||||||
PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder()
|
PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder()
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey);
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey);
|
||||||
|
|
||||||
clear = pbe.getDataStream(decryptorFactory);
|
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
|
||||||
|
|
||||||
encryptedData = pbe;
|
encryptedData = encryptedDataAsymmetric;
|
||||||
currentProgress += 5;
|
currentProgress += 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,9 +290,8 @@ public class OpenPgpService extends RemoteService {
|
|||||||
InputData inputData = new InputData(is, inputLength);
|
InputData inputData = new InputData(is, inputLength);
|
||||||
|
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
|
||||||
builder.assumeSymmetric(false) // no support for symmetric encryption
|
builder.allowSymmetricDecryption(false) // no support for symmetric encryption
|
||||||
// allow only the private key for this app for decryption
|
.enforcedKeyId(accSettings.getKeyId()) // allow only the private key for this app for decryption
|
||||||
.enforcedKeyId(accSettings.getKeyId())
|
|
||||||
.passphrase(passphrase);
|
.passphrase(passphrase);
|
||||||
|
|
||||||
// TODO: currently does not support binary signed-only content
|
// TODO: currently does not support binary signed-only content
|
||||||
|
@ -98,7 +98,6 @@ public class KeychainIntentService extends IntentService
|
|||||||
|
|
||||||
// decrypt/verify
|
// decrypt/verify
|
||||||
public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes";
|
public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes";
|
||||||
public static final String DECRYPT_ASSUME_SYMMETRIC = "assume_symmetric";
|
|
||||||
public static final String DECRYPT_PASSPHRASE = "passphrase";
|
public static final String DECRYPT_PASSPHRASE = "passphrase";
|
||||||
|
|
||||||
// save keyring
|
// save keyring
|
||||||
@ -344,7 +343,6 @@ public class KeychainIntentService extends IntentService
|
|||||||
int target = data.getInt(TARGET);
|
int target = data.getInt(TARGET);
|
||||||
|
|
||||||
byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES);
|
byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES);
|
||||||
boolean assumeSymmetricEncryption = data.getBoolean(DECRYPT_ASSUME_SYMMETRIC);
|
|
||||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||||
|
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
@ -424,7 +422,7 @@ public class KeychainIntentService extends IntentService
|
|||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
|
||||||
builder.progressDialogUpdater(this);
|
builder.progressDialogUpdater(this);
|
||||||
|
|
||||||
builder.assumeSymmetric(assumeSymmetricEncryption)
|
builder.allowSymmetricDecryption(true)
|
||||||
.passphrase(passphrase);
|
.passphrase(passphrase);
|
||||||
|
|
||||||
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||||
|
@ -35,6 +35,7 @@ import com.devspark.appmsg.AppMsg;
|
|||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.Id;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.helper.FileHelper;
|
import org.sufficientlysecure.keychain.helper.FileHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
||||||
@ -202,6 +203,8 @@ public class DecryptFileFragment extends DecryptFragment {
|
|||||||
|
|
||||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||||
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||||
|
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||||
|
showPassphraseDialog(Id.key.symmetric);
|
||||||
} else {
|
} else {
|
||||||
if (mDeleteAfter.isChecked()) {
|
if (mDeleteAfter.isChecked()) {
|
||||||
// Create and show dialog to delete original file
|
// Create and show dialog to delete original file
|
||||||
|
@ -33,6 +33,7 @@ import com.devspark.appmsg.AppMsg;
|
|||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.Id;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
||||||
@ -149,6 +150,8 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
|
|
||||||
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||||
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||||
|
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
|
||||||
|
showPassphraseDialog(Id.key.symmetric);
|
||||||
} else {
|
} else {
|
||||||
AppMsg.makeText(getActivity(), R.string.decryption_successful,
|
AppMsg.makeText(getActivity(), R.string.decryption_successful,
|
||||||
AppMsg.STYLE_INFO).show();
|
AppMsg.STYLE_INFO).show();
|
||||||
|
Loading…
Reference in New Issue
Block a user