working version of DecryptVerifyResult

This commit is contained in:
Vincent Breitmoser 2014-09-13 19:30:10 +02:00
parent 4c636a1471
commit dbbefe2f41
6 changed files with 112 additions and 63 deletions

View File

@ -49,6 +49,8 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
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.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@ -70,6 +72,7 @@ import java.util.Set;
*/
public class PgpDecryptVerify {
private ProviderHelper mProviderHelper;
private PassphraseCache mPassphraseCache;
private InputData mData;
private OutputStream mOutStream;
@ -83,6 +86,7 @@ public class PgpDecryptVerify {
private PgpDecryptVerify(Builder builder) {
// private Constructor can only be called from Builder
this.mProviderHelper = builder.mProviderHelper;
this.mPassphraseCache = builder.mPassphraseCache;
this.mData = builder.mData;
this.mOutStream = builder.mOutStream;
@ -97,6 +101,7 @@ public class PgpDecryptVerify {
public static class Builder {
// mandatory parameter
private ProviderHelper mProviderHelper;
private PassphraseCache mPassphraseCache;
private InputData mData;
private OutputStream mOutStream;
@ -108,8 +113,10 @@ public class PgpDecryptVerify {
private boolean mDecryptMetadataOnly = false;
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.mPassphraseCache = passphraseCache;
this.mData = data;
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
*/
@ -286,12 +303,24 @@ public class PgpDecryptVerify {
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) {
DecryptVerifyResult result =
new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, log);
result.setKeyIdPassphraseNeeded(subKeyId);
return result;
try {
// returns "" if key has no passphrase
mPassphrase = mPassphraseCache.getCachedPassphrase(subKeyId);
} 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

View File

@ -462,32 +462,23 @@ public class OpenPgpService extends RemoteService {
.setDecryptMetadataOnly(decryptMetadataOnly)
.setNfcState(nfcDecryptedSessionKey);
DecryptVerifyResult decryptVerifyResult;
try {
// TODO: currently does not support binary signed-only content
decryptVerifyResult = builder.build().execute();
// TODO: currently does not support binary signed-only content
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
// throw exceptions upwards to client with meaningful messages
} catch (PgpDecryptVerify.InvalidDataException e) {
throw new Exception(getString(R.string.error_invalid_data));
} catch (PgpDecryptVerify.KeyExtractionException e) {
throw new Exception(getString(R.string.error_could_not_extract_private_key));
} catch (PgpDecryptVerify.WrongPassphraseException e) {
throw new Exception(getString(R.string.error_wrong_passphrase));
} catch (PgpDecryptVerify.NoSecretKeyException e) {
throw new Exception(getString(R.string.error_no_secret_key_found));
} catch (PgpDecryptVerify.IntegrityCheckFailedException e) {
throw new Exception(getString(R.string.error_integrity_check_failed));
} catch (PgpDecryptVerify.NeedNfcDataException e) {
// return PendingIntent to execute NFC activity
return getNfcDecryptIntent(data, e.mPassphrase, e.mEncryptedSessionKey);
}
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!");
if (decryptVerifyResult.isPending()) {
switch (decryptVerifyResult.getResult()) {
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
return getPassphraseIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded());
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
throw new PgpGeneralException(
"Decryption of symmetric content not supported by API!");
case DecryptVerifyResult.RESULT_PENDING_NFC:
// TODO get passphrase here? currently not in DecryptVerifyResult
return getNfcDecryptIntent(
data, null, decryptVerifyResult.getNfcEncryptedSessionKey());
}
throw new PgpGeneralException(
"Encountered unhandled type of pending action not supported by API!");
}
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();

View File

@ -337,15 +337,22 @@ public class KeychainIntentService extends IntentService implements Progressable
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
// verification of signatures
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)
.setAllowSymmetricDecryption(true)
@ -378,15 +385,22 @@ public class KeychainIntentService extends IntentService implements Progressable
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
// verification of signatures
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)
.setAllowSymmetricDecryption(true)

View File

@ -18,7 +18,6 @@
package org.sufficientlysecure.keychain.service.results;
import android.os.Parcel;
import android.os.Parcelable;
import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpSignatureResult;
@ -34,7 +33,7 @@ public class DecryptVerifyResult extends OperationResultParcel {
public static final int RESULT_PENDING_NFC = RESULT_PENDING +48;
long mKeyIdPassphraseNeeded;
byte[] mSessionKey;
byte[] mNfcSessionKey;
OpenPgpSignatureResult mSignatureResult;
OpenPgpMetadata mDecryptMetadata;
@ -48,7 +47,11 @@ public class DecryptVerifyResult extends OperationResultParcel {
}
public void setNfcEncryptedSessionKey(byte[] sessionKey) {
mSessionKey = sessionKey;
mNfcSessionKey = sessionKey;
}
public byte[] getNfcEncryptedSessionKey() {
return mNfcSessionKey;
}
public OpenPgpSignatureResult getSignatureResult() {
@ -80,7 +83,7 @@ public class DecryptVerifyResult extends OperationResultParcel {
mKeyIdPassphraseNeeded = source.readLong();
mSignatureResult = source.readParcelable(OpenPgpSignatureResult.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() {
@ -92,9 +95,9 @@ public class DecryptVerifyResult extends OperationResultParcel {
dest.writeLong(mKeyIdPassphraseNeeded);
dest.writeParcelable(mSignatureResult, 0);
dest.writeParcelable(mDecryptMetadata, 0);
if (mSessionKey != null) {
if (mNfcSessionKey != null) {
dest.writeInt(1);
dest.writeByteArray(mSessionKey);
dest.writeByteArray(mNfcSessionKey);
} else {
dest.writeInt(0);
}

View File

@ -261,13 +261,18 @@ public class DecryptFileFragment extends DecryptFragment {
DecryptVerifyResult result =
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
switch (result.getResult()) {
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
showPassphraseDialog(result.getKeyIdPassphraseNeeded());
return;
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
showPassphraseDialog(Constants.key.symmetric);
return;
if (result.isPending()) {
switch (result.getResult()) {
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
showPassphraseDialog(result.getKeyIdPassphraseNeeded());
return;
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
showPassphraseDialog(Constants.key.symmetric);
return;
}
// error, we can't work with this!
result.createNotify(getActivity());
return;
}
// display signature result in activity

View File

@ -146,13 +146,18 @@ public class DecryptMessageFragment extends DecryptFragment {
DecryptVerifyResult result =
returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
switch (result.getResult()) {
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
showPassphraseDialog(result.getKeyIdPassphraseNeeded());
return;
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
showPassphraseDialog(Constants.key.symmetric);
return;
if (result.isPending()) {
switch (result.getResult()) {
case DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE:
showPassphraseDialog(result.getKeyIdPassphraseNeeded());
return;
case DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE:
showPassphraseDialog(Constants.key.symmetric);
return;
}
// error, we can't work with this!
result.createNotify(getActivity());
return;
}
byte[] decryptedMessage = returnData
@ -160,6 +165,8 @@ public class DecryptMessageFragment extends DecryptFragment {
mMessage.setText(new String(decryptedMessage));
mMessage.setHorizontallyScrolling(false);
result.createNotify(getActivity());
// display signature result in activity
onResult(result);
}