Enforce private key for applications, verify signed-only texts without passphrase input, better internal decrypt and verify method

This commit is contained in:
Dominik Schürmann
2014-03-04 20:53:44 +01:00
parent 89a4c38cc0
commit 06f9134eb1
6 changed files with 266 additions and 162 deletions

View File

@@ -44,6 +44,7 @@ import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
@@ -181,13 +182,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// decrypt/verify
public static final String RESULT_DECRYPTED_STRING = "decrypted_message";
public static final String RESULT_DECRYPTED_BYTES = "decrypted_data";
public static final String RESULT_SIGNATURE = "signature";
public static final String RESULT_SIGNATURE_KEY_ID = "signature_key_id";
public static final String RESULT_SIGNATURE_USER_ID = "signature_user_id";
public static final String RESULT_CLEARTEXT_SIGNATURE_ONLY = "signature_only";
public static final String RESULT_SIGNATURE_SUCCESS = "signature_success";
public static final String RESULT_SIGNATURE_UNKNOWN = "signature_unknown";
public static final String RESULT_DECRYPT_VERIFY_RESULT = "signature";
// import
public static final String RESULT_IMPORT_ADDED = "added";
@@ -489,15 +484,17 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// verifyText and decrypt returning additional resultData values for the
// verification of signatures
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
builder.progress(this);
builder.progressDialogUpdater(this);
builder.assumeSymmetric(assumeSymmetricEncryption)
.passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
resultData = builder.build().execute();
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
outStream.close();
resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult);
/* Output */
switch (target) {
@@ -867,10 +864,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
}
/**
* Set progress of ProgressDialog by sending message to handler on UI thread
* Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread
*/
public void setProgress(String message, int progress, int max) {
Log.d(Constants.TAG, "Send message by setProgress with progress=" + progress + ", max="
Log.d(Constants.TAG, "Send message by setProgress with progressDialogUpdater=" + progress + ", max="
+ max);
Bundle data = new Bundle();

View File

@@ -21,7 +21,6 @@ import android.app.PendingIntent;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -33,9 +32,10 @@ import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -284,98 +284,29 @@ public class OpenPgpService extends RemoteService {
Intent result = new Intent();
try {
// TODO:
// fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream
// should we allow to decrypt everything under every key id or only the one set?
// TODO: instead of trying to get the passphrase before
// pause stream when passphrase is missing and then resume
// TODO: put this code into PgpDecryptVerify class
// TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
// app, Fix this?
// String passphrase = null;
// if (!signedOnly) {
// // BEGIN Get key
// // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it
// // better!
// InputStream inputStream2 = new ByteArrayInputStream(inputBytes);
//
// // TODO: duplicates functions from DecryptActivity!
// long secretKeyId;
// try {
// if (inputStream2.markSupported()) {
// // should probably set this to the max size of two
// // pgpF objects, if it even needs to be anything other
// // than 0.
// inputStream2.mark(200);
// }
// secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2);
// if (secretKeyId == Id.key.none) {
// throw new PgpGeneralException(getString(R.string.error_no_secret_key_found));
// }
// } catch (NoAsymmetricEncryptionException e) {
// if (inputStream2.markSupported()) {
// inputStream2.reset();
// }
// secretKeyId = Id.key.symmetric;
// if (!PgpDecryptVerify.hasSymmetricEncryption(this, inputStream2)) {
// throw new PgpGeneralException(
// getString(R.string.error_no_known_encryption_found));
// }
// // we do not support symmetric decryption from the API!
// throw new Exception("Symmetric decryption is not supported!");
// }
//
// Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
// NOTE: currently this only gets the passphrase for the key set for this client
String passphrase;
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
} else {
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
}
if (passphrase == null) {
// get PendingIntent for passphrase input, add it to given params and return to client
Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
return passphraseBundle;
}
String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
long inputLength = is.available();
InputData inputData = new InputData(is, inputLength);
Bundle outputBundle;
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
builder.assumeSymmetric(false)
builder.assumeSymmetric(false) // no support for symmetric encryption
.enforcedKeyId(appSettings.getKeyId()) // allow only the private key for this app for decryption
.passphrase(passphrase);
// TODO: this also decrypts with other secret keys that have no passphrase!!!
outputBundle = builder.build().execute();
// TODO: currently does not support binary signed-only content
PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
//TODO: instead of using all these wrapping use OpenPgpSignatureResult directly
// in DecryptVerify class and then in DecryptActivity
boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE, false);
if (signature) {
long signatureKeyId = outputBundle
.getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, 0);
String signatureUserId = outputBundle
.getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
boolean signatureSuccess = outputBundle
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
boolean signatureUnknown = outputBundle
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, false);
boolean signatureOnly = outputBundle
.getBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false);
// TODO: SIGNATURE_SUCCESS_CERTIFIED is currently not implemented
int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
if (signatureSuccess) {
signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED;
} else if (signatureUnknown) {
signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
if (decryptVerifyResult.isKeyPassphraseNeeded()) {
// get PendingIntent for passphrase input, add it to given params and return to client
Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
return passphraseBundle;
} else if (decryptVerifyResult.isSymmetricPassphraseNeeded()) {
throw new PgpGeneralException("Decryption of symmetric content not supported by API!");
}
OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
if (signatureResult != null) {
if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY) {
// If signature is unknown we return an additional PendingIntent
// to retrieve the missing key
// TODO!!!
@@ -390,11 +321,9 @@ public class OpenPgpService extends RemoteService {
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
}
OpenPgpSignatureResult sigResult = new OpenPgpSignatureResult(signatureStatus,
signatureUserId, signatureOnly, signatureKeyId);
result.putExtra(OpenPgpApi.RESULT_SIGNATURE, sigResult);
result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
}
} finally {
is.close();
os.close();