mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
rewrite PgpDecryptVerify input, introduce PgpDecryptVerifyInputParcel
This commit is contained in:
parent
36ecd60c1b
commit
0d8370be1d
@ -36,6 +36,23 @@ public class DecryptVerifyResult extends InputPendingResult {
|
|||||||
// https://tools.ietf.org/html/rfc4880#page56
|
// https://tools.ietf.org/html/rfc4880#page56
|
||||||
String mCharset;
|
String mCharset;
|
||||||
|
|
||||||
|
byte[] mOutputBytes;
|
||||||
|
|
||||||
|
public DecryptVerifyResult(int result, OperationLog log) {
|
||||||
|
super(result, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecryptVerifyResult(OperationLog log, RequiredInputParcel requiredInput) {
|
||||||
|
super(log, requiredInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecryptVerifyResult(Parcel source) {
|
||||||
|
super(source);
|
||||||
|
mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
|
||||||
|
mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isKeysDisallowed () {
|
public boolean isKeysDisallowed () {
|
||||||
return (mResult & RESULT_KEY_DISALLOWED) == RESULT_KEY_DISALLOWED;
|
return (mResult & RESULT_KEY_DISALLOWED) == RESULT_KEY_DISALLOWED;
|
||||||
}
|
}
|
||||||
@ -64,18 +81,12 @@ public class DecryptVerifyResult extends InputPendingResult {
|
|||||||
mCharset = charset;
|
mCharset = charset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecryptVerifyResult(int result, OperationLog log) {
|
public void setOutputBytes(byte[] outputBytes) {
|
||||||
super(result, log);
|
mOutputBytes = outputBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecryptVerifyResult(OperationLog log, RequiredInputParcel requiredInput) {
|
public byte[] getOutputBytes() {
|
||||||
super(log, requiredInput);
|
return mOutputBytes;
|
||||||
}
|
|
||||||
|
|
||||||
public DecryptVerifyResult(Parcel source) {
|
|
||||||
super(source);
|
|
||||||
mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
|
|
||||||
mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
|
@ -58,6 +58,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.Operat
|
|||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
@ -66,6 +67,7 @@ import org.sufficientlysecure.keychain.util.ProgressScaler;
|
|||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -73,147 +75,90 @@ import java.net.URLConnection;
|
|||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class uses a Builder pattern!
|
* This class uses a Builder pattern!
|
||||||
*/
|
*/
|
||||||
public class PgpDecryptVerify extends BaseOperation {
|
public class PgpDecryptVerify extends BaseOperation {
|
||||||
|
|
||||||
private InputData mData;
|
public PgpDecryptVerify(Context context, ProviderHelper providerHelper, Progressable progressable) {
|
||||||
private OutputStream mOutStream;
|
super(context, providerHelper, progressable);
|
||||||
|
|
||||||
private boolean mAllowSymmetricDecryption;
|
|
||||||
private Set<Long> mAllowedKeyIds;
|
|
||||||
private boolean mDecryptMetadataOnly;
|
|
||||||
private byte[] mDetachedSignature;
|
|
||||||
private String mRequiredSignerFingerprint;
|
|
||||||
private boolean mSignedLiteralData;
|
|
||||||
|
|
||||||
protected PgpDecryptVerify(Builder builder) {
|
|
||||||
super(builder.mContext, builder.mProviderHelper, builder.mProgressable);
|
|
||||||
|
|
||||||
// private Constructor can only be called from Builder
|
|
||||||
this.mData = builder.mData;
|
|
||||||
this.mOutStream = builder.mOutStream;
|
|
||||||
|
|
||||||
this.mAllowSymmetricDecryption = builder.mAllowSymmetricDecryption;
|
|
||||||
this.mAllowedKeyIds = builder.mAllowedKeyIds;
|
|
||||||
this.mDecryptMetadataOnly = builder.mDecryptMetadataOnly;
|
|
||||||
this.mDetachedSignature = builder.mDetachedSignature;
|
|
||||||
this.mSignedLiteralData = builder.mSignedLiteralData;
|
|
||||||
this.mRequiredSignerFingerprint = builder.mRequiredSignerFingerprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Builder {
|
|
||||||
// mandatory parameter
|
|
||||||
private Context mContext;
|
|
||||||
private ProviderHelper mProviderHelper;
|
|
||||||
private InputData mData;
|
|
||||||
|
|
||||||
// optional
|
|
||||||
private OutputStream mOutStream = null;
|
|
||||||
private Progressable mProgressable = null;
|
|
||||||
private boolean mAllowSymmetricDecryption = true;
|
|
||||||
private Set<Long> mAllowedKeyIds = null;
|
|
||||||
private boolean mDecryptMetadataOnly = false;
|
|
||||||
private byte[] mDetachedSignature = null;
|
|
||||||
private String mRequiredSignerFingerprint = null;
|
|
||||||
private boolean mSignedLiteralData = false;
|
|
||||||
|
|
||||||
public Builder(Context context, ProviderHelper providerHelper,
|
|
||||||
Progressable progressable,
|
|
||||||
InputData data, OutputStream outStream) {
|
|
||||||
mContext = context;
|
|
||||||
mProviderHelper = providerHelper;
|
|
||||||
mProgressable = progressable;
|
|
||||||
mData = data;
|
|
||||||
mOutStream = outStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is used when verifying signed literals to check that they are signed with
|
|
||||||
* the required key
|
|
||||||
*/
|
|
||||||
public Builder setRequiredSignerFingerprint(String fingerprint) {
|
|
||||||
mRequiredSignerFingerprint = fingerprint;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is to force a mode where the message is just the signature key id and
|
|
||||||
* then a literal data packet; used in Keybase.io proofs
|
|
||||||
*/
|
|
||||||
public Builder setSignedLiteralData(boolean signedLiteralData) {
|
|
||||||
mSignedLiteralData = signedLiteralData;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setAllowSymmetricDecryption(boolean allowSymmetricDecryption) {
|
|
||||||
mAllowSymmetricDecryption = allowSymmetricDecryption;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow these key ids alone for decryption.
|
|
||||||
* This means only ciphertexts encrypted for one of these private key can be decrypted.
|
|
||||||
*/
|
|
||||||
public Builder setAllowedKeyIds(Set<Long> allowedKeyIds) {
|
|
||||||
mAllowedKeyIds = allowedKeyIds;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If enabled, the actual decryption/verification of the content will not be executed.
|
|
||||||
* The metadata only will be decrypted and returned.
|
|
||||||
*/
|
|
||||||
public Builder setDecryptMetadataOnly(boolean decryptMetadataOnly) {
|
|
||||||
mDecryptMetadataOnly = decryptMetadataOnly;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If detachedSignature != null, it will be used exclusively to verify the signature
|
|
||||||
*/
|
|
||||||
public Builder setDetachedSignature(byte[] detachedSignature) {
|
|
||||||
mDetachedSignature = detachedSignature;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PgpDecryptVerify build() {
|
|
||||||
return new PgpDecryptVerify(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts and/or verifies data based on parameters of class
|
* Decrypts and/or verifies data based on parameters of class
|
||||||
*/
|
*/
|
||||||
public DecryptVerifyResult execute(CryptoInputParcel cryptoInput) {
|
public DecryptVerifyResult execute(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput) {
|
||||||
|
InputData inputData;
|
||||||
|
OutputStream outputStream;
|
||||||
|
|
||||||
|
if (input.getInputBytes() != null) {
|
||||||
|
byte[] inputBytes = input.getInputBytes();
|
||||||
|
inputData = new InputData(new ByteArrayInputStream(inputBytes), inputBytes.length);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = mContext.getContentResolver().openInputStream(input.getInputUri());
|
||||||
|
long inputSize = FileHelper.getFileSize(mContext, input.getInputUri(), 0);
|
||||||
|
inputData = new InputData(inputStream, inputSize);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.getOutputUri() == null) {
|
||||||
|
outputStream = new ByteArrayOutputStream();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
outputStream = mContext.getContentResolver().openOutputStream(input.getOutputUri());
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DecryptVerifyResult result = executeInternal(input, cryptoInput, inputData, outputStream);
|
||||||
|
if (outputStream instanceof ByteArrayOutputStream) {
|
||||||
|
byte[] outputData = ((ByteArrayOutputStream) outputStream).toByteArray();
|
||||||
|
result.setOutputBytes(outputData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecryptVerifyResult execute(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
|
||||||
|
InputData inputData, OutputStream outputStream) {
|
||||||
|
return executeInternal(input, cryptoInput, inputData, outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DecryptVerifyResult executeInternal(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
|
||||||
|
InputData inputData, OutputStream outputStream) {
|
||||||
try {
|
try {
|
||||||
if (mDetachedSignature != null) {
|
if (input.getDetachedSignature() != null) {
|
||||||
Log.d(Constants.TAG, "Detached signature present, verifying with this signature only");
|
Log.d(Constants.TAG, "Detached signature present, verifying with this signature only");
|
||||||
|
|
||||||
return verifyDetachedSignature(mData.getInputStream(), 0);
|
return verifyDetachedSignature(input, inputData, outputStream, 0);
|
||||||
} else {
|
} else {
|
||||||
// automatically works with PGP ascii armor and PGP binary
|
// automatically works with PGP ascii armor and PGP binary
|
||||||
InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
|
InputStream in = PGPUtil.getDecoderStream(inputData.getInputStream());
|
||||||
|
|
||||||
if (in instanceof ArmoredInputStream) {
|
if (in instanceof ArmoredInputStream) {
|
||||||
ArmoredInputStream aIn = (ArmoredInputStream) in;
|
ArmoredInputStream aIn = (ArmoredInputStream) in;
|
||||||
// it is ascii armored
|
// it is ascii armored
|
||||||
Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine());
|
Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine());
|
||||||
|
|
||||||
if (mSignedLiteralData) {
|
if (input.isSignedLiteralData()) {
|
||||||
return verifySignedLiteralData(aIn, 0);
|
return verifySignedLiteralData(input, aIn, outputStream, 0);
|
||||||
} else if (aIn.isClearText()) {
|
} else if (aIn.isClearText()) {
|
||||||
// a cleartext signature, verify it with the other method
|
// a cleartext signature, verify it with the other method
|
||||||
return verifyCleartextSignature(aIn, 0);
|
return verifyCleartextSignature(aIn, 0);
|
||||||
} else {
|
} else {
|
||||||
// else: ascii armored encryption! go on...
|
// else: ascii armored encryption! go on...
|
||||||
return decryptVerify(cryptoInput, in, 0);
|
return decryptVerify(input, cryptoInput, in, outputStream, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return decryptVerify(cryptoInput, in, 0);
|
return decryptVerify(input, cryptoInput, in, outputStream, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
@ -232,7 +177,8 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
/**
|
/**
|
||||||
* Verify Keybase.io style signed literal data
|
* Verify Keybase.io style signed literal data
|
||||||
*/
|
*/
|
||||||
private DecryptVerifyResult verifySignedLiteralData(InputStream in, int indent)
|
private DecryptVerifyResult verifySignedLiteralData(
|
||||||
|
PgpDecryptVerifyInputParcel input, InputStream in, OutputStream out, int indent)
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
OperationLog log = new OperationLog();
|
OperationLog log = new OperationLog();
|
||||||
log.add(LogType.MSG_VL, indent);
|
log.add(LogType.MSG_VL, indent);
|
||||||
@ -283,9 +229,9 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signingRing.getFingerprint());
|
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signingRing.getFingerprint());
|
||||||
if (!(mRequiredSignerFingerprint.equals(fingerprint))) {
|
if (!(input.getRequiredSignerFingerprint().equals(fingerprint))) {
|
||||||
log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent);
|
log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent);
|
||||||
Log.d(Constants.TAG, "Fingerprint mismatch; wanted " + mRequiredSignerFingerprint +
|
Log.d(Constants.TAG, "Fingerprint mismatch; wanted " + input.getRequiredSignerFingerprint() +
|
||||||
" got " + fingerprint + "!");
|
" got " + fingerprint + "!");
|
||||||
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
|
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
|
||||||
}
|
}
|
||||||
@ -317,7 +263,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
int length;
|
int length;
|
||||||
byte[] buffer = new byte[1 << 16];
|
byte[] buffer = new byte[1 << 16];
|
||||||
while ((length = dataIn.read(buffer)) > 0) {
|
while ((length = dataIn.read(buffer)) > 0) {
|
||||||
mOutStream.write(buffer, 0, length);
|
out.write(buffer, 0, length);
|
||||||
signature.update(buffer, 0, length);
|
signature.update(buffer, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,8 +309,9 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
/**
|
/**
|
||||||
* Decrypt and/or verifies binary or ascii armored pgp
|
* Decrypt and/or verifies binary or ascii armored pgp
|
||||||
*/
|
*/
|
||||||
private DecryptVerifyResult decryptVerify(CryptoInputParcel cryptoInput,
|
private DecryptVerifyResult decryptVerify(
|
||||||
InputStream in, int indent) throws IOException, PGPException {
|
PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
|
||||||
|
InputStream in, OutputStream out, int indent) throws IOException, PGPException {
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
OperationLog log = new OperationLog();
|
||||||
|
|
||||||
@ -455,13 +402,13 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allow only specific keys for decryption?
|
// allow only specific keys for decryption?
|
||||||
if (mAllowedKeyIds != null) {
|
if (input.getAllowedKeyIds() != null) {
|
||||||
long masterKeyId = secretKeyRing.getMasterKeyId();
|
long masterKeyId = secretKeyRing.getMasterKeyId();
|
||||||
Log.d(Constants.TAG, "encData.getKeyID(): " + subKeyId);
|
Log.d(Constants.TAG, "encData.getKeyID(): " + subKeyId);
|
||||||
Log.d(Constants.TAG, "mAllowedKeyIds: " + mAllowedKeyIds);
|
Log.d(Constants.TAG, "mAllowedKeyIds: " + input.getAllowedKeyIds());
|
||||||
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
|
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
|
||||||
|
|
||||||
if (!mAllowedKeyIds.contains(masterKeyId)) {
|
if (!input.getAllowedKeyIds().contains(masterKeyId)) {
|
||||||
// this key is in our db, but NOT allowed!
|
// this key is in our db, but NOT allowed!
|
||||||
// continue with the next packet in the while loop
|
// continue with the next packet in the while loop
|
||||||
skippedDisallowedKey = true;
|
skippedDisallowedKey = true;
|
||||||
@ -515,7 +462,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
|
|
||||||
log.add(LogType.MSG_DC_SYM, indent);
|
log.add(LogType.MSG_DC_SYM, indent);
|
||||||
|
|
||||||
if (!mAllowSymmetricDecryption) {
|
if (!input.isAllowSymmetricDecryption()) {
|
||||||
log.add(LogType.MSG_DC_SYM_SKIP, indent + 1);
|
log.add(LogType.MSG_DC_SYM_SKIP, indent + 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -764,7 +711,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return here if we want to decrypt the metadata only
|
// return here if we want to decrypt the metadata only
|
||||||
if (mDecryptMetadataOnly) {
|
if (input.isDecryptMetadataOnly()) {
|
||||||
log.add(LogType.MSG_DC_OK_META_ONLY, indent);
|
log.add(LogType.MSG_DC_OK_META_ONLY, indent);
|
||||||
DecryptVerifyResult result =
|
DecryptVerifyResult result =
|
||||||
new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
|
new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
|
||||||
@ -787,13 +734,13 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
InputStream dataIn = literalData.getInputStream();
|
InputStream dataIn = literalData.getInputStream();
|
||||||
|
|
||||||
long alreadyWritten = 0;
|
long alreadyWritten = 0;
|
||||||
long wholeSize = mData.getSize() - mData.getStreamPosition();
|
long wholeSize = 0; // TODO inputData.getSize() - inputData.getStreamPosition();
|
||||||
int length;
|
int length;
|
||||||
byte[] buffer = new byte[1 << 16];
|
byte[] buffer = new byte[1 << 16];
|
||||||
while ((length = dataIn.read(buffer)) > 0) {
|
while ((length = dataIn.read(buffer)) > 0) {
|
||||||
Log.d(Constants.TAG, "read bytes: " + length);
|
// Log.d(Constants.TAG, "read bytes: " + length);
|
||||||
if (mOutStream != null) {
|
if (out != null) {
|
||||||
mOutStream.write(buffer, 0, length);
|
out.write(buffer, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update signature buffer if signature is also present
|
// update signature buffer if signature is also present
|
||||||
@ -919,8 +866,8 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
out.close();
|
out.close();
|
||||||
|
|
||||||
byte[] clearText = out.toByteArray();
|
byte[] clearText = out.toByteArray();
|
||||||
if (mOutStream != null) {
|
if (out != null) {
|
||||||
mOutStream.write(clearText);
|
out.write(clearText);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProgress(R.string.progress_processing_signature, 60, 100);
|
updateProgress(R.string.progress_processing_signature, 60, 100);
|
||||||
@ -987,7 +934,8 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DecryptVerifyResult verifyDetachedSignature(InputStream in, int indent)
|
private DecryptVerifyResult verifyDetachedSignature(
|
||||||
|
PgpDecryptVerifyInputParcel input, InputData inputData, OutputStream out, int indent)
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
OperationLog log = new OperationLog();
|
||||||
@ -997,7 +945,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
signatureResultBuilder.setSignatureOnly(true);
|
signatureResultBuilder.setSignatureOnly(true);
|
||||||
|
|
||||||
updateProgress(R.string.progress_processing_signature, 0, 100);
|
updateProgress(R.string.progress_processing_signature, 0, 100);
|
||||||
InputStream detachedSigIn = new ByteArrayInputStream(mDetachedSignature);
|
InputStream detachedSigIn = new ByteArrayInputStream(input.getDetachedSignature());
|
||||||
detachedSigIn = PGPUtil.getDecoderStream(detachedSigIn);
|
detachedSigIn = PGPUtil.getDecoderStream(detachedSigIn);
|
||||||
|
|
||||||
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(detachedSigIn);
|
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(detachedSigIn);
|
||||||
@ -1022,12 +970,13 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
|
|
||||||
ProgressScaler progressScaler = new ProgressScaler(mProgressable, 60, 90, 100);
|
ProgressScaler progressScaler = new ProgressScaler(mProgressable, 60, 90, 100);
|
||||||
long alreadyWritten = 0;
|
long alreadyWritten = 0;
|
||||||
long wholeSize = mData.getSize() - mData.getStreamPosition();
|
long wholeSize = inputData.getSize() - inputData.getStreamPosition();
|
||||||
int length;
|
int length;
|
||||||
byte[] buffer = new byte[1 << 16];
|
byte[] buffer = new byte[1 << 16];
|
||||||
|
InputStream in = inputData.getInputStream();
|
||||||
while ((length = in.read(buffer)) > 0) {
|
while ((length = in.read(buffer)) > 0) {
|
||||||
if (mOutStream != null) {
|
if (out != null) {
|
||||||
mOutStream.write(buffer, 0, length);
|
out.write(buffer, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update signature buffer if signature is also present
|
// update signature buffer if signature is also present
|
||||||
|
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* 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 java.util.HashSet;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
public class PgpDecryptVerifyInputParcel implements Parcelable {
|
||||||
|
|
||||||
|
private Uri mInputUri;
|
||||||
|
private Uri mOutputUri;
|
||||||
|
private byte[] mInputBytes;
|
||||||
|
|
||||||
|
private boolean mAllowSymmetricDecryption;
|
||||||
|
private HashSet<Long> mAllowedKeyIds;
|
||||||
|
private boolean mDecryptMetadataOnly;
|
||||||
|
private byte[] mDetachedSignature;
|
||||||
|
private String mRequiredSignerFingerprint;
|
||||||
|
private boolean mSignedLiteralData;
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel(Uri inputUri, Uri outputUri) {
|
||||||
|
mInputUri = inputUri;
|
||||||
|
mOutputUri = outputUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel(byte[] inputBytes) {
|
||||||
|
mInputBytes = inputBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
PgpDecryptVerifyInputParcel(Parcel source) {
|
||||||
|
// we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable
|
||||||
|
mInputUri = source.readParcelable(getClass().getClassLoader());
|
||||||
|
mOutputUri = source.readParcelable(getClass().getClassLoader());
|
||||||
|
mInputBytes = source.createByteArray();
|
||||||
|
|
||||||
|
mAllowSymmetricDecryption = source.readInt() != 0;
|
||||||
|
mAllowedKeyIds = (HashSet<Long>) source.readSerializable();
|
||||||
|
mDecryptMetadataOnly = source.readInt() != 0;
|
||||||
|
mDetachedSignature = source.createByteArray();
|
||||||
|
mRequiredSignerFingerprint = source.readString();
|
||||||
|
mSignedLiteralData = source.readInt() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeParcelable(mInputUri, 0);
|
||||||
|
dest.writeParcelable(mOutputUri, 0);
|
||||||
|
dest.writeByteArray(mInputBytes);
|
||||||
|
|
||||||
|
dest.writeInt(mAllowSymmetricDecryption ? 1 : 0);
|
||||||
|
dest.writeSerializable(mAllowedKeyIds);
|
||||||
|
dest.writeInt(mDecryptMetadataOnly ? 1 : 0);
|
||||||
|
dest.writeByteArray(mDetachedSignature);
|
||||||
|
dest.writeString(mRequiredSignerFingerprint);
|
||||||
|
dest.writeInt(mSignedLiteralData ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] getInputBytes() {
|
||||||
|
return mInputBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri getInputUri() {
|
||||||
|
return mInputUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri getOutputUri() {
|
||||||
|
return mOutputUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAllowSymmetricDecryption() {
|
||||||
|
return mAllowSymmetricDecryption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel setAllowSymmetricDecryption(boolean allowSymmetricDecryption) {
|
||||||
|
mAllowSymmetricDecryption = allowSymmetricDecryption;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSet<Long> getAllowedKeyIds() {
|
||||||
|
return mAllowedKeyIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel setAllowedKeyIds(HashSet<Long> allowedKeyIds) {
|
||||||
|
mAllowedKeyIds = allowedKeyIds;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDecryptMetadataOnly() {
|
||||||
|
return mDecryptMetadataOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel setDecryptMetadataOnly(boolean decryptMetadataOnly) {
|
||||||
|
mDecryptMetadataOnly = decryptMetadataOnly;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] getDetachedSignature() {
|
||||||
|
return mDetachedSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel setDetachedSignature(byte[] detachedSignature) {
|
||||||
|
mDetachedSignature = detachedSignature;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getRequiredSignerFingerprint() {
|
||||||
|
return mRequiredSignerFingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel setRequiredSignerFingerprint(String requiredSignerFingerprint) {
|
||||||
|
mRequiredSignerFingerprint = requiredSignerFingerprint;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isSignedLiteralData() {
|
||||||
|
return mSignedLiteralData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel setSignedLiteralData(boolean signedLiteralData) {
|
||||||
|
mSignedLiteralData = signedLiteralData;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<PgpDecryptVerifyInputParcel> CREATOR = new Creator<PgpDecryptVerifyInputParcel>() {
|
||||||
|
public PgpDecryptVerifyInputParcel createFromParcel(final Parcel source) {
|
||||||
|
return new PgpDecryptVerifyInputParcel(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgpDecryptVerifyInputParcel[] newArray(final int size) {
|
||||||
|
return new PgpDecryptVerifyInputParcel[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1514,8 +1514,8 @@ public class ProviderHelper {
|
|||||||
return keyIds;
|
return keyIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Long> getAllowedKeyIdsForApp(Uri uri) {
|
public HashSet<Long> getAllowedKeyIdsForApp(Uri uri) {
|
||||||
Set<Long> keyIds = new HashSet<>();
|
HashSet<Long> keyIds = new HashSet<>();
|
||||||
|
|
||||||
Cursor cursor = mContentResolver.query(uri, null, null, null, null);
|
Cursor cursor = mContentResolver.query(uri, null, null, null, null);
|
||||||
try {
|
try {
|
||||||
|
@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEnt
|
|||||||
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
|
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpConstants;
|
import org.sufficientlysecure.keychain.pgp.PgpConstants;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel;
|
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
|
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
@ -63,7 +64,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Set;
|
import java.util.HashSet;
|
||||||
|
|
||||||
public class OpenPgpService extends RemoteService {
|
public class OpenPgpService extends RemoteService {
|
||||||
|
|
||||||
@ -488,23 +489,23 @@ public class OpenPgpService extends RemoteService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
|
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor inputDescriptor,
|
||||||
ParcelFileDescriptor output, boolean decryptMetadataOnly) {
|
ParcelFileDescriptor output, boolean decryptMetadataOnly) {
|
||||||
InputStream is = null;
|
InputStream inputStream = null;
|
||||||
OutputStream os = null;
|
OutputStream outputStream = null;
|
||||||
try {
|
try {
|
||||||
// Get Input- and OutputStream from ParcelFileDescriptor
|
// Get Input- and OutputStream from ParcelFileDescriptor
|
||||||
is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
inputStream = new ParcelFileDescriptor.AutoCloseInputStream(inputDescriptor);
|
||||||
|
|
||||||
// output is optional, e.g., for verifying detached signatures
|
// output is optional, e.g., for verifying detached signatures
|
||||||
if (decryptMetadataOnly || output == null) {
|
if (decryptMetadataOnly || output == null) {
|
||||||
os = null;
|
outputStream = null;
|
||||||
} else {
|
} else {
|
||||||
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
outputStream = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
String currentPkg = getCurrentCallingPackage();
|
String currentPkg = getCurrentCallingPackage();
|
||||||
Set<Long> allowedKeyIds = mProviderHelper.getAllowedKeyIdsForApp(
|
HashSet<Long> allowedKeyIds = mProviderHelper.getAllowedKeyIdsForApp(
|
||||||
KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));
|
KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));
|
||||||
|
|
||||||
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 7) {
|
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 7) {
|
||||||
@ -512,33 +513,31 @@ public class OpenPgpService extends RemoteService {
|
|||||||
ApiAccounts.buildBaseUri(currentPkg)));
|
ApiAccounts.buildBaseUri(currentPkg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
long inputLength = is.available();
|
CryptoInputParcel cryptoInput = CryptoInputParcelCacheService.getCryptoInputParcel(this, data);
|
||||||
InputData inputData = new InputData(is, inputLength);
|
if (cryptoInput == null) {
|
||||||
|
cryptoInput = new CryptoInputParcel();
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
|
||||||
this, new ProviderHelper(getContext()), null, inputData, os
|
|
||||||
);
|
|
||||||
|
|
||||||
CryptoInputParcel inputParcel = CryptoInputParcelCacheService.getCryptoInputParcel(this, data);
|
|
||||||
if (inputParcel == null) {
|
|
||||||
inputParcel = new CryptoInputParcel();
|
|
||||||
}
|
}
|
||||||
// override passphrase in input parcel if given by API call
|
// override passphrase in input parcel if given by API call
|
||||||
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
|
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
|
||||||
inputParcel = new CryptoInputParcel(inputParcel.getSignatureTime(),
|
cryptoInput = new CryptoInputParcel(cryptoInput.getSignatureTime(),
|
||||||
new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)));
|
new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE);
|
byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE);
|
||||||
|
|
||||||
|
PgpDecryptVerify op = new PgpDecryptVerify(this, mProviderHelper, null);
|
||||||
|
|
||||||
|
long inputLength = inputStream.available();
|
||||||
|
|
||||||
// allow only private keys associated with accounts of this app
|
// allow only private keys associated with accounts of this app
|
||||||
// no support for symmetric encryption
|
// no support for symmetric encryption
|
||||||
builder.setAllowSymmetricDecryption(false)
|
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel()
|
||||||
.setAllowedKeyIds(allowedKeyIds)
|
.setAllowSymmetricDecryption(false)
|
||||||
.setDecryptMetadataOnly(decryptMetadataOnly)
|
.setAllowedKeyIds(allowedKeyIds)
|
||||||
.setDetachedSignature(detachedSignature);
|
.setDecryptMetadataOnly(decryptMetadataOnly)
|
||||||
|
.setDetachedSignature(detachedSignature);
|
||||||
|
|
||||||
DecryptVerifyResult pgpResult = builder.build().execute(inputParcel);
|
DecryptVerifyResult pgpResult = op.execute(input, cryptoInput, inputStream, outputStream);
|
||||||
|
|
||||||
if (pgpResult.isPending()) {
|
if (pgpResult.isPending()) {
|
||||||
// prepare and return PendingIntent to be executed by client
|
// prepare and return PendingIntent to be executed by client
|
||||||
@ -624,16 +623,16 @@ public class OpenPgpService extends RemoteService {
|
|||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
} finally {
|
} finally {
|
||||||
if (is != null) {
|
if (inputStream != null) {
|
||||||
try {
|
try {
|
||||||
is.close();
|
inputStream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(Constants.TAG, "IOException when closing InputStream", e);
|
Log.e(Constants.TAG, "IOException when closing InputStream", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (os != null) {
|
if (outputStream != null) {
|
||||||
try {
|
try {
|
||||||
os.close();
|
outputStream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(Constants.TAG, "IOException when closing OutputStream", e);
|
Log.e(Constants.TAG, "IOException when closing OutputStream", e);
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
|||||||
import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
|
import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||||
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
@ -61,17 +62,11 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
|
|||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
|
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
|
||||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@ -122,34 +117,13 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
/* keys for data bundle */
|
/* keys for data bundle */
|
||||||
|
|
||||||
// encrypt, decrypt, import export
|
|
||||||
public static final String TARGET = "target";
|
|
||||||
public static final String SOURCE = "source";
|
|
||||||
|
|
||||||
// possible targets:
|
|
||||||
public static enum IOType {
|
|
||||||
UNKNOWN,
|
|
||||||
BYTES,
|
|
||||||
URI;
|
|
||||||
|
|
||||||
private static final IOType[] values = values();
|
|
||||||
|
|
||||||
public static IOType fromInt(int n) {
|
|
||||||
if (n < 0 || n >= values.length) {
|
|
||||||
return UNKNOWN;
|
|
||||||
} else {
|
|
||||||
return values[n];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// encrypt
|
// encrypt
|
||||||
public static final String ENCRYPT_DECRYPT_INPUT_URI = "input_uri";
|
public static final String ENCRYPT_DECRYPT_INPUT_URI = "input_uri";
|
||||||
public static final String ENCRYPT_DECRYPT_OUTPUT_URI = "output_uri";
|
public static final String ENCRYPT_DECRYPT_OUTPUT_URI = "output_uri";
|
||||||
public static final String SIGN_ENCRYPT_PARCEL = "sign_encrypt_parcel";
|
public static final String SIGN_ENCRYPT_PARCEL = "sign_encrypt_parcel";
|
||||||
|
|
||||||
// decrypt/verify
|
// decrypt/verify
|
||||||
public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes";
|
public static final String DECRYPT_VERIFY_PARCEL = "decrypt_verify_parcel";
|
||||||
|
|
||||||
// keybase proof
|
// keybase proof
|
||||||
public static final String KEYBASE_REQUIRED_FINGERPRINT = "keybase_required_fingerprint";
|
public static final String KEYBASE_REQUIRED_FINGERPRINT = "keybase_required_fingerprint";
|
||||||
@ -189,14 +163,6 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
// consolidate
|
// consolidate
|
||||||
public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery";
|
public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery";
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* possible data keys as result send over messenger
|
|
||||||
*/
|
|
||||||
|
|
||||||
// decrypt/verify
|
|
||||||
public static final String RESULT_DECRYPTED_BYTES = "decrypted_data";
|
|
||||||
|
|
||||||
Messenger mMessenger;
|
Messenger mMessenger;
|
||||||
|
|
||||||
// this attribute can possibly merged with the one above? not sure...
|
// this attribute can possibly merged with the one above? not sure...
|
||||||
@ -280,26 +246,16 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
}
|
}
|
||||||
case ACTION_DECRYPT_METADATA: {
|
case ACTION_DECRYPT_METADATA: {
|
||||||
|
|
||||||
try {
|
/* Input */
|
||||||
/* Input */
|
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
|
||||||
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
|
PgpDecryptVerifyInputParcel input = data.getParcelable(DECRYPT_VERIFY_PARCEL);
|
||||||
|
|
||||||
InputData inputData = createDecryptInputData(data);
|
// verifyText and decrypt returning additional resultData values for the
|
||||||
|
// verification of signatures
|
||||||
|
PgpDecryptVerify op = new PgpDecryptVerify(this, new ProviderHelper(this), this);
|
||||||
|
DecryptVerifyResult decryptVerifyResult = op.execute(input, cryptoInput);
|
||||||
|
|
||||||
// verifyText and decrypt returning additional resultData values for the
|
sendMessageToHandler(MessageStatus.OKAY, decryptVerifyResult);
|
||||||
// verification of signatures
|
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
|
||||||
this, new ProviderHelper(this), this, inputData, null
|
|
||||||
);
|
|
||||||
builder.setAllowSymmetricDecryption(true)
|
|
||||||
.setDecryptMetadataOnly(true);
|
|
||||||
|
|
||||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute(cryptoInput);
|
|
||||||
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, decryptVerifyResult);
|
|
||||||
} catch (Exception e) {
|
|
||||||
sendErrorToHandler(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -356,22 +312,13 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// kind of awkward, but this whole class wants to pull bytes out of “data”
|
PgpDecryptVerify op = new PgpDecryptVerify(this, new ProviderHelper(this), this);
|
||||||
data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal());
|
|
||||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, messageBytes);
|
|
||||||
|
|
||||||
InputData inputData = createDecryptInputData(data);
|
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(messageBytes)
|
||||||
OutputStream outStream = createCryptOutputStream(data);
|
.setSignedLiteralData(true)
|
||||||
|
.setRequiredSignerFingerprint(requiredFingerprint);
|
||||||
|
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
DecryptVerifyResult decryptVerifyResult = op.execute(input, new CryptoInputParcel());
|
||||||
this, new ProviderHelper(this), this,
|
|
||||||
inputData, outStream
|
|
||||||
);
|
|
||||||
builder.setSignedLiteralData(true).setRequiredSignerFingerprint(requiredFingerprint);
|
|
||||||
|
|
||||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute(
|
|
||||||
new CryptoInputParcel());
|
|
||||||
outStream.close();
|
|
||||||
|
|
||||||
if (!decryptVerifyResult.success()) {
|
if (!decryptVerifyResult.success()) {
|
||||||
OperationLog log = decryptVerifyResult.getLog();
|
OperationLog log = decryptVerifyResult.getLog();
|
||||||
@ -383,7 +330,7 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prover.validate(outStream.toString())) {
|
if (!prover.validate(new String(decryptVerifyResult.getOutputBytes()))) {
|
||||||
sendProofError(getString(R.string.keybase_message_payload_mismatch));
|
sendProofError(getString(R.string.keybase_message_payload_mismatch));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -404,40 +351,16 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
}
|
}
|
||||||
case ACTION_DECRYPT_VERIFY: {
|
case ACTION_DECRYPT_VERIFY: {
|
||||||
|
|
||||||
try {
|
/* Input */
|
||||||
/* Input */
|
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
|
||||||
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
|
PgpDecryptVerifyInputParcel input = data.getParcelable(DECRYPT_VERIFY_PARCEL);
|
||||||
|
|
||||||
InputData inputData = createDecryptInputData(data);
|
/* Operation */
|
||||||
OutputStream outStream = createCryptOutputStream(data);
|
PgpDecryptVerify op = new PgpDecryptVerify(this, new ProviderHelper(this), this);
|
||||||
|
DecryptVerifyResult decryptVerifyResult = op.execute(input, cryptoInput);
|
||||||
|
|
||||||
/* Operation */
|
/* Output */
|
||||||
Bundle resultData = new Bundle();
|
sendMessageToHandler(MessageStatus.OKAY, decryptVerifyResult);
|
||||||
|
|
||||||
// verifyText and decrypt returning additional resultData values for the
|
|
||||||
// verification of signatures
|
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
|
||||||
this, new ProviderHelper(this), this,
|
|
||||||
inputData, outStream
|
|
||||||
);
|
|
||||||
builder.setAllowSymmetricDecryption(true);
|
|
||||||
|
|
||||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute(cryptoInput);
|
|
||||||
|
|
||||||
outStream.close();
|
|
||||||
|
|
||||||
resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult);
|
|
||||||
|
|
||||||
/* Output */
|
|
||||||
finalizeDecryptOutputStream(data, resultData, outStream);
|
|
||||||
Log.logDebugBundle(resultData, "resultData");
|
|
||||||
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, resultData);
|
|
||||||
|
|
||||||
} catch (IOException | PgpGeneralException e) {
|
|
||||||
// TODO get rid of this!
|
|
||||||
sendErrorToHandler(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -676,65 +599,6 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
|
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputData createDecryptInputData(Bundle data) throws IOException, PgpGeneralException {
|
|
||||||
return createCryptInputData(data, DECRYPT_CIPHERTEXT_BYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
private InputData createCryptInputData(Bundle data, String bytesName) throws PgpGeneralException, IOException {
|
|
||||||
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
|
||||||
IOType type = IOType.fromInt(source);
|
|
||||||
switch (type) {
|
|
||||||
case BYTES: /* encrypting bytes directly */
|
|
||||||
byte[] bytes = data.getByteArray(bytesName);
|
|
||||||
return new InputData(new ByteArrayInputStream(bytes), bytes.length);
|
|
||||||
|
|
||||||
case URI: /* encrypting content uri */
|
|
||||||
Uri providerUri = data.getParcelable(ENCRYPT_DECRYPT_INPUT_URI);
|
|
||||||
|
|
||||||
// InputStream
|
|
||||||
return new InputData(getContentResolver().openInputStream(providerUri), FileHelper.getFileSize(this, providerUri, 0));
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new PgpGeneralException("No target chosen!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private OutputStream createCryptOutputStream(Bundle data) throws PgpGeneralException, FileNotFoundException {
|
|
||||||
int target = data.getInt(TARGET);
|
|
||||||
IOType type = IOType.fromInt(target);
|
|
||||||
switch (type) {
|
|
||||||
case BYTES:
|
|
||||||
return new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
case URI:
|
|
||||||
Uri providerUri = data.getParcelable(ENCRYPT_DECRYPT_OUTPUT_URI);
|
|
||||||
|
|
||||||
return getContentResolver().openOutputStream(providerUri);
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new PgpGeneralException("No target chosen!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finalizeDecryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream) {
|
|
||||||
finalizeCryptOutputStream(data, resultData, outStream, RESULT_DECRYPTED_BYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finalizeCryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream, String bytesName) {
|
|
||||||
int target = data.getInt(TARGET);
|
|
||||||
IOType type = IOType.fromInt(target);
|
|
||||||
switch (type) {
|
|
||||||
case BYTES:
|
|
||||||
byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
|
|
||||||
resultData.putByteArray(bytesName, output);
|
|
||||||
break;
|
|
||||||
case URI:
|
|
||||||
// nothing, output was written, just send okay and verification bundle
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
if (ACTION_CANCEL.equals(intent.getAction())) {
|
if (ACTION_CANCEL.equals(intent.getAction())) {
|
||||||
|
@ -36,8 +36,8 @@ import android.widget.TextView;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType;
|
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
|
||||||
@ -202,16 +202,14 @@ public class DecryptFilesFragment extends DecryptFragment {
|
|||||||
intent.setAction(mCurrentCryptoOperation);
|
intent.setAction(mCurrentCryptoOperation);
|
||||||
|
|
||||||
// data
|
// data
|
||||||
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);
|
|
||||||
|
|
||||||
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
|
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
|
||||||
|
|
||||||
data.putInt(KeychainIntentService.SOURCE, IOType.URI.ordinal());
|
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(mInputUri, mOutputUri)
|
||||||
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_INPUT_URI, mInputUri);
|
.setAllowSymmetricDecryption(true)
|
||||||
|
.setDecryptMetadataOnly(true);
|
||||||
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
|
|
||||||
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
|
|
||||||
|
|
||||||
|
data.putParcelable(KeychainIntentService.DECRYPT_VERIFY_PARCEL, input);
|
||||||
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);
|
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);
|
||||||
|
|
||||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
|
@ -34,8 +34,8 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
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.operations.results.DecryptVerifyResult;
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType;
|
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
||||||
@ -168,10 +168,8 @@ public class DecryptTextFragment extends DecryptFragment {
|
|||||||
|
|
||||||
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY);
|
||||||
|
|
||||||
// data
|
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(mCiphertext.getBytes());
|
||||||
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);
|
data.putParcelable(KeychainIntentService.DECRYPT_VERIFY_PARCEL, input);
|
||||||
data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal());
|
|
||||||
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
|
|
||||||
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);
|
data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput);
|
||||||
|
|
||||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
@ -199,8 +197,7 @@ public class DecryptTextFragment extends DecryptFragment {
|
|||||||
returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT);
|
returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT);
|
||||||
|
|
||||||
if (pgpResult.success()) {
|
if (pgpResult.success()) {
|
||||||
byte[] decryptedMessage = returnData
|
byte[] decryptedMessage = pgpResult.getOutputBytes();
|
||||||
.getByteArray(KeychainIntentService.RESULT_DECRYPTED_BYTES);
|
|
||||||
String displayMessage;
|
String displayMessage;
|
||||||
if (pgpResult.getCharset() != null) {
|
if (pgpResult.getCharset() != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -120,6 +120,9 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
|
|||||||
// preselect keys given, from state or arguments
|
// preselect keys given, from state or arguments
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
Long signatureKeyId = getArguments().getLong(ARG_SINGATURE_KEY_ID);
|
Long signatureKeyId = getArguments().getLong(ARG_SINGATURE_KEY_ID);
|
||||||
|
if (signatureKeyId == Constants.key.none) {
|
||||||
|
signatureKeyId = null;
|
||||||
|
}
|
||||||
long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS);
|
long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS);
|
||||||
preselectKeys(signatureKeyId, encryptionKeyIds);
|
preselectKeys(signatureKeyId, encryptionKeyIds);
|
||||||
}
|
}
|
||||||
|
@ -163,9 +163,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
|
|||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putLong(EXTRA_SUBKEY_ID, keyId);
|
args.putLong(EXTRA_SUBKEY_ID, keyId);
|
||||||
args.putParcelable(EXTRA_SERVICE_INTENT, serviceIntent);
|
args.putParcelable(EXTRA_SERVICE_INTENT, serviceIntent);
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
frag.show(context.getSupportFragmentManager(), "passphraseDialog");
|
frag.show(context.getSupportFragmentManager(), "passphraseDialog");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user