working version of DecryptVerifyResult
This commit is contained in:
@@ -49,6 +49,8 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
|||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult;
|
import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult;
|
||||||
|
import org.sufficientlysecure.keychain.service.results.OperationResultParcel.LogLevel;
|
||||||
|
import org.sufficientlysecure.keychain.service.results.OperationResultParcel.LogType;
|
||||||
import org.sufficientlysecure.keychain.service.results.OperationResultParcel.OperationLog;
|
import org.sufficientlysecure.keychain.service.results.OperationResultParcel.OperationLog;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@@ -70,6 +72,7 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class PgpDecryptVerify {
|
public class PgpDecryptVerify {
|
||||||
private ProviderHelper mProviderHelper;
|
private ProviderHelper mProviderHelper;
|
||||||
|
private PassphraseCache mPassphraseCache;
|
||||||
private InputData mData;
|
private InputData mData;
|
||||||
private OutputStream mOutStream;
|
private OutputStream mOutStream;
|
||||||
|
|
||||||
@@ -83,6 +86,7 @@ public class PgpDecryptVerify {
|
|||||||
private PgpDecryptVerify(Builder builder) {
|
private PgpDecryptVerify(Builder builder) {
|
||||||
// private Constructor can only be called from Builder
|
// private Constructor can only be called from Builder
|
||||||
this.mProviderHelper = builder.mProviderHelper;
|
this.mProviderHelper = builder.mProviderHelper;
|
||||||
|
this.mPassphraseCache = builder.mPassphraseCache;
|
||||||
this.mData = builder.mData;
|
this.mData = builder.mData;
|
||||||
this.mOutStream = builder.mOutStream;
|
this.mOutStream = builder.mOutStream;
|
||||||
|
|
||||||
@@ -97,6 +101,7 @@ public class PgpDecryptVerify {
|
|||||||
public static class Builder {
|
public static class Builder {
|
||||||
// mandatory parameter
|
// mandatory parameter
|
||||||
private ProviderHelper mProviderHelper;
|
private ProviderHelper mProviderHelper;
|
||||||
|
private PassphraseCache mPassphraseCache;
|
||||||
private InputData mData;
|
private InputData mData;
|
||||||
private OutputStream mOutStream;
|
private OutputStream mOutStream;
|
||||||
|
|
||||||
@@ -108,8 +113,10 @@ public class PgpDecryptVerify {
|
|||||||
private boolean mDecryptMetadataOnly = false;
|
private boolean mDecryptMetadataOnly = false;
|
||||||
private byte[] mDecryptedSessionKey = null;
|
private byte[] mDecryptedSessionKey = null;
|
||||||
|
|
||||||
public Builder(ProviderHelper providerHelper, InputData data, OutputStream outStream) {
|
public Builder(ProviderHelper providerHelper, PassphraseCache passphraseCache,
|
||||||
|
InputData data, OutputStream outStream) {
|
||||||
this.mProviderHelper = providerHelper;
|
this.mProviderHelper = providerHelper;
|
||||||
|
this.mPassphraseCache = passphraseCache;
|
||||||
this.mData = data;
|
this.mData = data;
|
||||||
this.mOutStream = outStream;
|
this.mOutStream = outStream;
|
||||||
}
|
}
|
||||||
@@ -169,6 +176,16 @@ public class PgpDecryptVerify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface PassphraseCache {
|
||||||
|
public String getCachedPassphrase(long masterKeyId)
|
||||||
|
throws NoSecretKeyException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoSecretKeyException extends Exception {
|
||||||
|
public NoSecretKeyException() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts and/or verifies data based on parameters of class
|
* Decrypts and/or verifies data based on parameters of class
|
||||||
*/
|
*/
|
||||||
@@ -286,12 +303,24 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
encryptedDataAsymmetric = encData;
|
encryptedDataAsymmetric = encData;
|
||||||
|
|
||||||
// if passphrase was not cached, return here indicating that a passphrase is missing!
|
// if no passphrase was explicitly set try to get it from the cache service
|
||||||
if (mPassphrase == null) {
|
if (mPassphrase == null) {
|
||||||
DecryptVerifyResult result =
|
try {
|
||||||
new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, log);
|
// returns "" if key has no passphrase
|
||||||
result.setKeyIdPassphraseNeeded(subKeyId);
|
mPassphrase = mPassphraseCache.getCachedPassphrase(subKeyId);
|
||||||
return result;
|
} catch (NoSecretKeyException e) {
|
||||||
|
// log.add(LogLevel.ERROR, LogType.MSG_DEC_ERROR_NO_KEY);
|
||||||
|
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if passphrase was not cached, return here
|
||||||
|
// indicating that a passphrase is missing!
|
||||||
|
if (mPassphrase == null) {
|
||||||
|
DecryptVerifyResult result =
|
||||||
|
new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, log);
|
||||||
|
result.setKeyIdPassphraseNeeded(subKeyId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// break out of while, only decrypt the first packet where we have a key
|
// break out of while, only decrypt the first packet where we have a key
|
||||||
|
|||||||
@@ -462,32 +462,23 @@ public class OpenPgpService extends RemoteService {
|
|||||||
.setDecryptMetadataOnly(decryptMetadataOnly)
|
.setDecryptMetadataOnly(decryptMetadataOnly)
|
||||||
.setNfcState(nfcDecryptedSessionKey);
|
.setNfcState(nfcDecryptedSessionKey);
|
||||||
|
|
||||||
DecryptVerifyResult decryptVerifyResult;
|
// TODO: currently does not support binary signed-only content
|
||||||
try {
|
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||||
// TODO: currently does not support binary signed-only content
|
|
||||||
decryptVerifyResult = builder.build().execute();
|
|
||||||
|
|
||||||
// throw exceptions upwards to client with meaningful messages
|
if (decryptVerifyResult.isPending()) {
|
||||||
} catch (PgpDecryptVerify.InvalidDataException e) {
|
switch (decryptVerifyResult.getResult()) {
|
||||||
throw new Exception(getString(R.string.error_invalid_data));
|
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
|
||||||
} catch (PgpDecryptVerify.KeyExtractionException e) {
|
return getPassphraseIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded());
|
||||||
throw new Exception(getString(R.string.error_could_not_extract_private_key));
|
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
|
||||||
} catch (PgpDecryptVerify.WrongPassphraseException e) {
|
throw new PgpGeneralException(
|
||||||
throw new Exception(getString(R.string.error_wrong_passphrase));
|
"Decryption of symmetric content not supported by API!");
|
||||||
} catch (PgpDecryptVerify.NoSecretKeyException e) {
|
case DecryptVerifyResult.RESULT_PENDING_NFC:
|
||||||
throw new Exception(getString(R.string.error_no_secret_key_found));
|
// TODO get passphrase here? currently not in DecryptVerifyResult
|
||||||
} catch (PgpDecryptVerify.IntegrityCheckFailedException e) {
|
return getNfcDecryptIntent(
|
||||||
throw new Exception(getString(R.string.error_integrity_check_failed));
|
data, null, decryptVerifyResult.getNfcEncryptedSessionKey());
|
||||||
} catch (PgpDecryptVerify.NeedNfcDataException e) {
|
}
|
||||||
// return PendingIntent to execute NFC activity
|
throw new PgpGeneralException(
|
||||||
return getNfcDecryptIntent(data, e.mPassphrase, e.mEncryptedSessionKey);
|
"Encountered unhandled type of pending action not supported by API!");
|
||||||
}
|
|
||||||
|
|
||||||
if (DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE == decryptVerifyResult.getStatus()) {
|
|
||||||
// get PendingIntent for passphrase input, add it to given params and return to client
|
|
||||||
return getPassphraseIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded());
|
|
||||||
} else if (DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE == decryptVerifyResult.getStatus()) {
|
|
||||||
throw new PgpGeneralException("Decryption of symmetric content not supported by API!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
|
||||||
|
|||||||
@@ -337,15 +337,22 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
Bundle resultData = new Bundle();
|
Bundle resultData = new Bundle();
|
||||||
|
|
||||||
/* TODO find passphrase from cache, if not provided
|
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
|
||||||
KeychainIntentService.this, masterKeyId);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// verifyText and decrypt returning additional resultData values for the
|
// verifyText and decrypt returning additional resultData values for the
|
||||||
// verification of signatures
|
// verification of signatures
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||||
new ProviderHelper(this), inputData, outStream
|
new ProviderHelper(this),
|
||||||
|
new PgpDecryptVerify.PassphraseCache() {
|
||||||
|
@Override
|
||||||
|
public String getCachedPassphrase(long masterKeyId) {
|
||||||
|
try {
|
||||||
|
return PassphraseCacheService.getCachedPassphrase(
|
||||||
|
KeychainIntentService.this, masterKeyId);
|
||||||
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inputData, outStream
|
||||||
);
|
);
|
||||||
builder.setProgressable(this)
|
builder.setProgressable(this)
|
||||||
.setAllowSymmetricDecryption(true)
|
.setAllowSymmetricDecryption(true)
|
||||||
@@ -378,15 +385,22 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
Bundle resultData = new Bundle();
|
Bundle resultData = new Bundle();
|
||||||
|
|
||||||
/* TODO find passphrase from cache, if not provided
|
|
||||||
return PassphraseCacheService.getCachedPassphrase(
|
|
||||||
KeychainIntentService.this, masterKeyId);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// verifyText and decrypt returning additional resultData values for the
|
// verifyText and decrypt returning additional resultData values for the
|
||||||
// verification of signatures
|
// verification of signatures
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||||
new ProviderHelper(this), inputData, null
|
new ProviderHelper(this),
|
||||||
|
new PgpDecryptVerify.PassphraseCache() {
|
||||||
|
@Override
|
||||||
|
public String getCachedPassphrase(long masterKeyId) throws PgpDecryptVerify.NoSecretKeyException {
|
||||||
|
try {
|
||||||
|
return PassphraseCacheService.getCachedPassphrase(
|
||||||
|
KeychainIntentService.this, masterKeyId);
|
||||||
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
|
throw new PgpDecryptVerify.NoSecretKeyException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inputData, null
|
||||||
);
|
);
|
||||||
builder.setProgressable(this)
|
builder.setProgressable(this)
|
||||||
.setAllowSymmetricDecryption(true)
|
.setAllowSymmetricDecryption(true)
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.sufficientlysecure.keychain.service.results;
|
package org.sufficientlysecure.keychain.service.results;
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
|
||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpMetadata;
|
import org.openintents.openpgp.OpenPgpMetadata;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
@@ -34,7 +33,7 @@ public class DecryptVerifyResult extends OperationResultParcel {
|
|||||||
public static final int RESULT_PENDING_NFC = RESULT_PENDING +48;
|
public static final int RESULT_PENDING_NFC = RESULT_PENDING +48;
|
||||||
|
|
||||||
long mKeyIdPassphraseNeeded;
|
long mKeyIdPassphraseNeeded;
|
||||||
byte[] mSessionKey;
|
byte[] mNfcSessionKey;
|
||||||
|
|
||||||
OpenPgpSignatureResult mSignatureResult;
|
OpenPgpSignatureResult mSignatureResult;
|
||||||
OpenPgpMetadata mDecryptMetadata;
|
OpenPgpMetadata mDecryptMetadata;
|
||||||
@@ -48,7 +47,11 @@ public class DecryptVerifyResult extends OperationResultParcel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setNfcEncryptedSessionKey(byte[] sessionKey) {
|
public void setNfcEncryptedSessionKey(byte[] sessionKey) {
|
||||||
mSessionKey = sessionKey;
|
mNfcSessionKey = sessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getNfcEncryptedSessionKey() {
|
||||||
|
return mNfcSessionKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenPgpSignatureResult getSignatureResult() {
|
public OpenPgpSignatureResult getSignatureResult() {
|
||||||
@@ -80,7 +83,7 @@ public class DecryptVerifyResult extends OperationResultParcel {
|
|||||||
mKeyIdPassphraseNeeded = source.readLong();
|
mKeyIdPassphraseNeeded = source.readLong();
|
||||||
mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
|
mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
|
||||||
mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader());
|
mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader());
|
||||||
mSessionKey = source.readInt() != 0 ? source.createByteArray() : null;
|
mNfcSessionKey = source.readInt() != 0 ? source.createByteArray() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
@@ -92,9 +95,9 @@ public class DecryptVerifyResult extends OperationResultParcel {
|
|||||||
dest.writeLong(mKeyIdPassphraseNeeded);
|
dest.writeLong(mKeyIdPassphraseNeeded);
|
||||||
dest.writeParcelable(mSignatureResult, 0);
|
dest.writeParcelable(mSignatureResult, 0);
|
||||||
dest.writeParcelable(mDecryptMetadata, 0);
|
dest.writeParcelable(mDecryptMetadata, 0);
|
||||||
if (mSessionKey != null) {
|
if (mNfcSessionKey != null) {
|
||||||
dest.writeInt(1);
|
dest.writeInt(1);
|
||||||
dest.writeByteArray(mSessionKey);
|
dest.writeByteArray(mNfcSessionKey);
|
||||||
} else {
|
} else {
|
||||||
dest.writeInt(0);
|
dest.writeInt(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,13 +261,18 @@ public class DecryptFileFragment extends DecryptFragment {
|
|||||||
DecryptVerifyResult result =
|
DecryptVerifyResult result =
|
||||||
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
||||||
|
|
||||||
switch (result.getResult()) {
|
if (result.isPending()) {
|
||||||
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
|
switch (result.getResult()) {
|
||||||
showPassphraseDialog(result.getKeyIdPassphraseNeeded());
|
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
|
||||||
return;
|
showPassphraseDialog(result.getKeyIdPassphraseNeeded());
|
||||||
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
|
return;
|
||||||
showPassphraseDialog(Constants.key.symmetric);
|
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
|
||||||
return;
|
showPassphraseDialog(Constants.key.symmetric);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// error, we can't work with this!
|
||||||
|
result.createNotify(getActivity());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// display signature result in activity
|
// display signature result in activity
|
||||||
|
|||||||
@@ -146,13 +146,18 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
DecryptVerifyResult result =
|
DecryptVerifyResult result =
|
||||||
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
|
||||||
|
|
||||||
switch (result.getResult()) {
|
if (result.isPending()) {
|
||||||
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
|
switch (result.getResult()) {
|
||||||
showPassphraseDialog(result.getKeyIdPassphraseNeeded());
|
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
|
||||||
return;
|
showPassphraseDialog(result.getKeyIdPassphraseNeeded());
|
||||||
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
|
return;
|
||||||
showPassphraseDialog(Constants.key.symmetric);
|
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
|
||||||
return;
|
showPassphraseDialog(Constants.key.symmetric);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// error, we can't work with this!
|
||||||
|
result.createNotify(getActivity());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] decryptedMessage = returnData
|
byte[] decryptedMessage = returnData
|
||||||
@@ -160,6 +165,8 @@ public class DecryptMessageFragment extends DecryptFragment {
|
|||||||
mMessage.setText(new String(decryptedMessage));
|
mMessage.setText(new String(decryptedMessage));
|
||||||
mMessage.setHorizontallyScrolling(false);
|
mMessage.setHorizontallyScrolling(false);
|
||||||
|
|
||||||
|
result.createNotify(getActivity());
|
||||||
|
|
||||||
// display signature result in activity
|
// display signature result in activity
|
||||||
onResult(result);
|
onResult(result);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user