aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-04-24 14:18:01 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2015-04-24 14:18:01 +0200
commitb4aec3114d9911cf9aef0d14ee697e5131b2853f (patch)
tree7237de5955ec34d8849737b2f9229bfbb37d0c45 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service
parentc2163460971cc01e65d7dfd18eec491f01ebc744 (diff)
parentbaac30508d24dcda6135bf8ae338c99d8c3b8ad8 (diff)
downloadopen-keychain-b4aec3114d9911cf9aef0d14ee697e5131b2853f.tar.gz
open-keychain-b4aec3114d9911cf9aef0d14ee697e5131b2853f.tar.bz2
open-keychain-b4aec3114d9911cf9aef0d14ee697e5131b2853f.zip
Merge branch 'development' into linked-identities
Conflicts: Graphics/update-drawables.sh OpenKeychain-Test/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java OpenKeychain/build.gradle OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java62
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java134
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java141
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java214
7 files changed, 475 insertions, 88 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
index 57a11de21..a7571a7ac 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
@@ -22,10 +22,14 @@ import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.Date;
+import java.util.Map;
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
/**
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index e210536fd..63ea6285c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -46,7 +46,6 @@ import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
-import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
@@ -68,6 +67,7 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.InputData;
@@ -159,8 +159,6 @@ public class KeychainIntentService extends IntentService implements Progressable
// decrypt/verify
public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes";
- public static final String DECRYPT_PASSPHRASE = "passphrase";
- public static final String DECRYPT_NFC_DECRYPTED_SESSION_KEY = "nfc_decrypted_session_key";
// keybase proof
public static final String KEYBASE_REQUIRED_FINGERPRINT = "keybase_required_fingerprint";
@@ -169,6 +167,7 @@ public class KeychainIntentService extends IntentService implements Progressable
// save keyring
public static final String EDIT_KEYRING_PARCEL = "save_parcel";
public static final String EDIT_KEYRING_PASSPHRASE = "passphrase";
+ public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
// delete keyring(s)
public static final String DELETE_KEY_LIST = "delete_list";
@@ -193,7 +192,7 @@ public class KeychainIntentService extends IntentService implements Progressable
// promote key
public static final String PROMOTE_MASTER_KEY_ID = "promote_master_key_id";
- public static final String PROMOTE_TYPE = "promote_type";
+ public static final String PROMOTE_CARD_AID = "promote_card_aid";
// consolidate
public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery";
@@ -260,11 +259,12 @@ public class KeychainIntentService extends IntentService implements Progressable
// Input
CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL);
+ CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
String keyServerUri = data.getString(UPLOAD_KEY_SERVER);
// Operation
CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled);
- CertifyResult result = op.certify(parcel, keyServerUri);
+ CertifyResult result = op.certify(parcel, cryptoInput, keyServerUri);
// Result
sendMessageToHandler(MessageStatus.OKAY, result);
@@ -289,27 +289,20 @@ public class KeychainIntentService extends IntentService implements Progressable
case ACTION_DECRYPT_METADATA: {
try {
- /* Input */
- Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE);
- byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
+ /* Input */
+ CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
InputData inputData = createDecryptInputData(data);
- /* Operation */
-
- Bundle resultData = new Bundle();
-
// verifyText and decrypt returning additional resultData values for the
// verification of signatures
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
this, new ProviderHelper(this), this, inputData, null
);
builder.setAllowSymmetricDecryption(true)
- .setPassphrase(passphrase)
- .setDecryptMetadataOnly(true)
- .setNfcState(nfcDecryptedSessionKey);
+ .setDecryptMetadataOnly(true);
- DecryptVerifyResult decryptVerifyResult = builder.build().execute();
+ DecryptVerifyResult decryptVerifyResult = builder.build().execute(cryptoInput);
sendMessageToHandler(MessageStatus.OKAY, decryptVerifyResult);
} catch (Exception e) {
@@ -384,7 +377,8 @@ public class KeychainIntentService extends IntentService implements Progressable
);
builder.setSignedLiteralData(true).setRequiredSignerFingerprint(requiredFingerprint);
- DecryptVerifyResult decryptVerifyResult = builder.build().execute();
+ DecryptVerifyResult decryptVerifyResult = builder.build().execute(
+ new CryptoInputParcel());
outStream.close();
if (!decryptVerifyResult.success()) {
@@ -419,15 +413,13 @@ public class KeychainIntentService extends IntentService implements Progressable
case ACTION_DECRYPT_VERIFY: {
try {
- /* Input */
- Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE);
- byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
+ /* Input */
+ CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
InputData inputData = createDecryptInputData(data);
OutputStream outStream = createCryptOutputStream(data);
- /* Operation */
-
+ /* Operation */
Bundle resultData = new Bundle();
// verifyText and decrypt returning additional resultData values for the
@@ -436,24 +428,22 @@ public class KeychainIntentService extends IntentService implements Progressable
this, new ProviderHelper(this), this,
inputData, outStream
);
- builder.setAllowSymmetricDecryption(true)
- .setPassphrase(passphrase)
- .setNfcState(nfcDecryptedSessionKey);
+ builder.setAllowSymmetricDecryption(true);
- DecryptVerifyResult decryptVerifyResult = builder.build().execute();
+ DecryptVerifyResult decryptVerifyResult = builder.build().execute(cryptoInput);
outStream.close();
resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult);
- /* Output */
-
+ /* Output */
finalizeDecryptOutputStream(data, resultData, outStream);
-
Log.logDebugBundle(resultData, "resultData");
sendMessageToHandler(MessageStatus.OKAY, resultData);
- } catch (Exception e) {
+
+ } catch (IOException | PgpGeneralException e) {
+ // TODO get rid of this!
sendErrorToHandler(e);
}
@@ -478,11 +468,11 @@ public class KeychainIntentService extends IntentService implements Progressable
// Input
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
- Passphrase passphrase = data.getParcelable(EDIT_KEYRING_PASSPHRASE);
+ CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
// Operation
EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled);
- EditKeyResult result = op.execute(saveParcel, passphrase);
+ OperationResult result = op.execute(saveParcel, cryptoInput);
// Result
sendMessageToHandler(MessageStatus.OKAY, result);
@@ -492,11 +482,12 @@ public class KeychainIntentService extends IntentService implements Progressable
case ACTION_PROMOTE_KEYRING: {
// Input
- long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID);
+ long keyRingId = data.getLong(PROMOTE_MASTER_KEY_ID);
+ byte[] cardAid = data.getByteArray(PROMOTE_CARD_AID);
// Operation
PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled);
- PromoteKeyResult result = op.execute(keyRingId);
+ PromoteKeyResult result = op.execute(keyRingId, cardAid);
// Result
sendMessageToHandler(MessageStatus.OKAY, result);
@@ -553,11 +544,12 @@ public class KeychainIntentService extends IntentService implements Progressable
// Input
SignEncryptParcel inputParcel = data.getParcelable(SIGN_ENCRYPT_PARCEL);
+ CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
// Operation
SignEncryptOperation op = new SignEncryptOperation(
this, new ProviderHelper(this), this, mActionCanceled);
- SignEncryptResult result = op.execute(inputParcel);
+ SignEncryptResult result = op.execute(inputParcel, cryptoInput);
// Result
sendMessageToHandler(MessageStatus.OKAY, result);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index 93a2bee23..78137170d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -60,18 +60,18 @@ import java.util.Date;
*
* Caching behavior for subkeys depends on the cacheSubs preference:
*
- * - If cacheSubs is NOT set, passphrases will be cached and retrieved by master key id. The
- * checks for special subkeys will still be done, but otherwise it is assumed that all subkeys
- * from the same master key will use the same passphrase. This can lead to bad passphrase
- * errors if two subkeys are encrypted differently. This is the default behavior.
+ * - If cacheSubs is NOT set, passphrases will be cached and retrieved by master key id. The
+ * checks for special subkeys will still be done, but otherwise it is assumed that all subkeys
+ * from the same master key will use the same passphrase. This can lead to bad passphrase
+ * errors if two subkeys are encrypted differently. This is the default behavior.
*
- * - If cacheSubs IS set, passphrases will be cached per subkey id. This means that if a keyring
- * has two subkeys for different purposes, passphrases will be cached independently and the
- * user will be asked for a passphrase once per subkey even if it is the same one. This mode
- * of operation is more precise, since we can assume that all passphrases returned from cache
- * will be correct without fail. Since keyrings with differently encrypted subkeys are a very
- * rare occurrence, and caching by keyring is what the user expects in the vast majority of
- * cases, this is not the default behavior.
+ * - If cacheSubs IS set, passphrases will be cached per subkey id. This means that if a keyring
+ * has two subkeys for different purposes, passphrases will be cached independently and the
+ * user will be asked for a passphrase once per subkey even if it is the same one. This mode
+ * of operation is more precise, since we can assume that all passphrases returned from cache
+ * will be correct without fail. Since keyrings with differently encrypted subkeys are a very
+ * rare occurrence, and caching by keyring is what the user expects in the vast majority of
+ * cases, this is not the default behavior.
*
*/
public class PassphraseCacheService extends Service {
@@ -123,7 +123,7 @@ public class PassphraseCacheService extends Service {
public static void addCachedPassphrase(Context context, long masterKeyId, long subKeyId,
Passphrase passphrase,
String primaryUserId) {
- Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + masterKeyId);
+ Log.d(Constants.TAG, "PassphraseCacheService.addCachedPassphrase() for " + masterKeyId);
Intent intent = new Intent(context, PassphraseCacheService.class);
intent.setAction(ACTION_PASSPHRASE_CACHE_ADD);
@@ -137,10 +137,23 @@ public class PassphraseCacheService extends Service {
context.startService(intent);
}
+ public static void clearCachedPassphrase(Context context, long masterKeyId, long subKeyId) {
+ Log.d(Constants.TAG, "PassphraseCacheService.clearCachedPassphrase() for " + masterKeyId);
+
+ Intent intent = new Intent(context, PassphraseCacheService.class);
+ intent.setAction(ACTION_PASSPHRASE_CACHE_CLEAR);
+
+ intent.putExtra(EXTRA_KEY_ID, masterKeyId);
+ intent.putExtra(EXTRA_SUBKEY_ID, subKeyId);
+
+ context.startService(intent);
+ }
+
+
/**
* Gets a cached passphrase from memory by sending an intent to the service. This method is
* designed to wait until the service returns the passphrase.
-
+ *
* @return passphrase or null (if no passphrase is cached for this keyId)
*/
public static Passphrase getCachedPassphrase(Context context, long masterKeyId, long subKeyId) throws KeyNotFoundException {
@@ -218,7 +231,7 @@ public class PassphraseCacheService extends Service {
}
// on "none" key, just do nothing
- if(masterKeyId == Constants.key.none) {
+ if (masterKeyId == Constants.key.none) {
return null;
}
@@ -232,11 +245,11 @@ public class PassphraseCacheService extends Service {
switch (keyType) {
case DIVERT_TO_CARD:
- if (Preferences.getPreferences(this).useDefaultYubikeyPin()) {
- Log.d(Constants.TAG, "PassphraseCacheService: Using default Yubikey PIN: 123456");
- return new Passphrase("123456"); // default Yubikey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/
+ if (Preferences.getPreferences(this).useDefaultYubiKeyPin()) {
+ Log.d(Constants.TAG, "PassphraseCacheService: Using default YubiKey PIN: 123456");
+ return new Passphrase("123456"); // default YubiKey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/
} else {
- Log.d(Constants.TAG, "PassphraseCacheService: NOT using default Yubikey PIN");
+ Log.d(Constants.TAG, "PassphraseCacheService: NOT using default YubiKey PIN");
break;
}
case PASSPHRASE_EMPTY:
@@ -310,11 +323,11 @@ public class PassphraseCacheService extends Service {
/**
* Build pending intent that is executed by alarm manager to time out a specific passphrase
*/
- private static PendingIntent buildIntent(Context context, long keyId) {
+ private static PendingIntent buildIntent(Context context, long referenceKeyId) {
Intent intent = new Intent(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE);
- intent.putExtra(EXTRA_KEY_ID, keyId);
+ intent.putExtra(EXTRA_KEY_ID, referenceKeyId);
// request code should be unique for each PendingIntent, thus keyId is used
- return PendingIntent.getBroadcast(context, (int) keyId, intent,
+ return PendingIntent.getBroadcast(context, (int) referenceKeyId, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
@@ -325,11 +338,17 @@ public class PassphraseCacheService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(Constants.TAG, "PassphraseCacheService.onStartCommand()");
+ if (intent == null || intent.getAction() == null) {
+ updateService();
+ return START_STICKY;
+ }
+
// register broadcastreceiver
registerReceiver();
- if (intent != null && intent.getAction() != null) {
- if (ACTION_PASSPHRASE_CACHE_ADD.equals(intent.getAction())) {
+ String action = intent.getAction();
+ switch (action) {
+ case ACTION_PASSPHRASE_CACHE_ADD: {
long ttl = intent.getLongExtra(EXTRA_TTL, DEFAULT_TTL);
long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1);
@@ -343,28 +362,19 @@ public class PassphraseCacheService extends Service {
);
// if we don't cache by specific subkey id, or the requested subkey is the master key,
- // just add master key id to the cache
- if (subKeyId == masterKeyId || !Preferences.getPreferences(mContext).getPassphraseCacheSubs()) {
- mPassphraseCache.put(masterKeyId, new CachedPassphrase(passphrase, primaryUserID));
- if (ttl > 0) {
- // register new alarm with keyId for this passphrase
- long triggerTime = new Date().getTime() + (ttl * 1000);
- AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
- am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, masterKeyId));
- }
- } else {
- // otherwise, add this specific subkey to the cache
- mPassphraseCache.put(subKeyId, new CachedPassphrase(passphrase, primaryUserID));
- if (ttl > 0) {
- // register new alarm with keyId for this passphrase
- long triggerTime = new Date().getTime() + (ttl * 1000);
- AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
- am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, subKeyId));
- }
+ // just add master key id to the cache, otherwise, add this specific subkey to the cache
+ long referenceKeyId =
+ Preferences.getPreferences(mContext).getPassphraseCacheSubs() ? subKeyId : masterKeyId;
+ mPassphraseCache.put(referenceKeyId, new CachedPassphrase(passphrase, primaryUserID));
+ if (ttl > 0) {
+ // register new alarm with keyId for this passphrase
+ long triggerTime = new Date().getTime() + (ttl * 1000);
+ AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
+ am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, referenceKeyId));
}
-
- updateService();
- } else if (ACTION_PASSPHRASE_CACHE_GET.equals(intent.getAction())) {
+ break;
+ }
+ case ACTION_PASSPHRASE_CACHE_GET: {
long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, Constants.key.symmetric);
long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, Constants.key.symmetric);
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
@@ -392,22 +402,42 @@ public class PassphraseCacheService extends Service {
} catch (RemoteException e) {
Log.e(Constants.TAG, "PassphraseCacheService: Sending message failed", e);
}
- } else if (ACTION_PASSPHRASE_CACHE_CLEAR.equals(intent.getAction())) {
+ break;
+ }
+ case ACTION_PASSPHRASE_CACHE_CLEAR: {
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
- // Stop all ttl alarms
- for (int i = 0; i < mPassphraseCache.size(); i++) {
- am.cancel(buildIntent(this, mPassphraseCache.keyAt(i)));
- }
+ if (intent.hasExtra(EXTRA_SUBKEY_ID) && intent.hasExtra(EXTRA_KEY_ID)) {
- mPassphraseCache.clear();
+ long referenceKeyId;
+ if (Preferences.getPreferences(mContext).getPassphraseCacheSubs()) {
+ referenceKeyId = intent.getLongExtra(EXTRA_KEY_ID, 0L);
+ } else {
+ referenceKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, 0L);
+ }
+ // Stop specific ttl alarm and
+ am.cancel(buildIntent(this, referenceKeyId));
+ mPassphraseCache.delete(referenceKeyId);
- updateService();
- } else {
+ } else {
+
+ // Stop all ttl alarms
+ for (int i = 0; i < mPassphraseCache.size(); i++) {
+ am.cancel(buildIntent(this, mPassphraseCache.keyAt(i)));
+ }
+ mPassphraseCache.clear();
+
+ }
+ break;
+ }
+ default: {
Log.e(Constants.TAG, "PassphraseCacheService: Intent or Intent Action not supported!");
+ break;
}
}
+ updateService();
+
return START_STICKY;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
index 9fd278c13..2e0524141 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
@@ -82,10 +82,14 @@ public class SaveKeyringParcel implements Parcelable {
mRevokeSubKeys = new ArrayList<>();
}
+ public boolean isEmpty() {
+ return isRestrictedOnly() && mChangeSubKeys.isEmpty();
+ }
+
/** Returns true iff this parcel does not contain any operations which require a passphrase. */
public boolean isRestrictedOnly() {
if (mNewUnlock != null || !mAddUserIds.isEmpty() || !mAddUserAttribute.isEmpty()
- || !mAddSubKeys.isEmpty() || mChangePrimaryUserId != null || !mRevokeSubKeys .isEmpty()
+ || !mAddSubKeys.isEmpty() || mChangePrimaryUserId != null || !mRevokeUserIds.isEmpty()
|| !mRevokeSubKeys.isEmpty()) {
return false;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java
index 4bd3481e6..430d8a49b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.service;
import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -26,6 +27,7 @@ import android.support.v4.app.FragmentManager;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
new file mode 100644
index 000000000..3d1ccaca1
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * 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.service.input;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.sufficientlysecure.keychain.util.Passphrase;
+
+/**
+ * This is a base class for the input of crypto operations.
+ */
+public class CryptoInputParcel implements Parcelable {
+
+ final Date mSignatureTime;
+ final Passphrase mPassphrase;
+
+ // this map contains both decrypted session keys and signed hashes to be
+ // used in the crypto operation described by this parcel.
+ private HashMap<ByteBuffer, byte[]> mCryptoData = new HashMap<>();
+
+ public CryptoInputParcel() {
+ mSignatureTime = new Date();
+ mPassphrase = null;
+ }
+
+ public CryptoInputParcel(Date signatureTime, Passphrase passphrase) {
+ mSignatureTime = signatureTime == null ? new Date() : signatureTime;
+ mPassphrase = passphrase;
+ }
+
+ public CryptoInputParcel(Passphrase passphrase) {
+ mSignatureTime = new Date();
+ mPassphrase = passphrase;
+ }
+
+ public CryptoInputParcel(Date signatureTime) {
+ mSignatureTime = signatureTime == null ? new Date() : signatureTime;
+ mPassphrase = null;
+ }
+
+ protected CryptoInputParcel(Parcel source) {
+ mSignatureTime = new Date(source.readLong());
+ mPassphrase = source.readParcelable(getClass().getClassLoader());
+
+ {
+ int count = source.readInt();
+ mCryptoData = new HashMap<>(count);
+ for (int i = 0; i < count; i++) {
+ byte[] key = source.createByteArray();
+ byte[] value = source.createByteArray();
+ mCryptoData.put(ByteBuffer.wrap(key), value);
+ }
+ }
+
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mSignatureTime.getTime());
+ dest.writeParcelable(mPassphrase, 0);
+
+ dest.writeInt(mCryptoData.size());
+ for (HashMap.Entry<ByteBuffer, byte[]> entry : mCryptoData.entrySet()) {
+ dest.writeByteArray(entry.getKey().array());
+ dest.writeByteArray(entry.getValue());
+ }
+ }
+
+ public void addCryptoData(byte[] hash, byte[] signedHash) {
+ mCryptoData.put(ByteBuffer.wrap(hash), signedHash);
+ }
+
+ public Map<ByteBuffer, byte[]> getCryptoData() {
+ return Collections.unmodifiableMap(mCryptoData);
+ }
+
+ public Date getSignatureTime() {
+ return mSignatureTime;
+ }
+
+ public boolean hasPassphrase() {
+ return mPassphrase != null;
+ }
+
+ public Passphrase getPassphrase() {
+ return mPassphrase;
+ }
+
+ public static final Creator<CryptoInputParcel> CREATOR = new Creator<CryptoInputParcel>() {
+ public CryptoInputParcel createFromParcel(final Parcel source) {
+ return new CryptoInputParcel(source);
+ }
+
+ public CryptoInputParcel[] newArray(final int size) {
+ return new CryptoInputParcel[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder();
+ b.append("CryptoInput: { ");
+ b.append(mSignatureTime).append(" ");
+ if (mPassphrase != null) {
+ b.append("passphrase");
+ }
+ if (mCryptoData != null) {
+ b.append(mCryptoData.size());
+ b.append(" hashes ");
+ }
+ b.append("}");
+ return b.toString();
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
new file mode 100644
index 000000000..535c1e735
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
@@ -0,0 +1,214 @@
+package org.sufficientlysecure.keychain.service.input;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.sufficientlysecure.keychain.Constants.key;
+
+
+public class RequiredInputParcel implements Parcelable {
+
+ public enum RequiredInputType {
+ PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT
+ }
+
+ public Date mSignatureTime;
+
+ public final RequiredInputType mType;
+
+ public final byte[][] mInputHashes;
+ public final int[] mSignAlgos;
+
+ private Long mMasterKeyId;
+ private Long mSubKeyId;
+
+ private RequiredInputParcel(RequiredInputType type, byte[][] inputHashes,
+ int[] signAlgos, Date signatureTime, Long masterKeyId, Long subKeyId) {
+ mType = type;
+ mInputHashes = inputHashes;
+ mSignAlgos = signAlgos;
+ mSignatureTime = signatureTime;
+ mMasterKeyId = masterKeyId;
+ mSubKeyId = subKeyId;
+ }
+
+ public RequiredInputParcel(Parcel source) {
+ mType = RequiredInputType.values()[source.readInt()];
+
+ // 0 = none, 1 = both, 2 = only hashes (decrypt)
+ int hashTypes = source.readInt();
+ if (hashTypes != 0) {
+ int count = source.readInt();
+ mInputHashes = new byte[count][];
+ if (hashTypes == 1) {
+ mSignAlgos = new int[count];
+ for (int i = 0; i < count; i++) {
+ mInputHashes[i] = source.createByteArray();
+ mSignAlgos[i] = source.readInt();
+ }
+ } else {
+ mSignAlgos = null;
+ for (int i = 0; i < count; i++) {
+ mInputHashes[i] = source.createByteArray();
+ }
+ }
+ } else {
+ mInputHashes = null;
+ mSignAlgos = null;
+ }
+
+ mSignatureTime = source.readInt() != 0 ? new Date(source.readLong()) : null;
+ mMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
+ mSubKeyId = source.readInt() != 0 ? source.readLong() : null;
+
+ }
+
+ public Long getMasterKeyId() {
+ return mMasterKeyId;
+ }
+
+ public Long getSubKeyId() {
+ return mSubKeyId;
+ }
+
+ public static RequiredInputParcel createNfcSignOperation(
+ byte[] inputHash, int signAlgo, Date signatureTime) {
+ return new RequiredInputParcel(RequiredInputType.NFC_SIGN,
+ new byte[][] { inputHash }, new int[] { signAlgo },
+ signatureTime, null, null);
+ }
+
+ public static RequiredInputParcel createNfcDecryptOperation(byte[] inputHash, long subKeyId) {
+ return new RequiredInputParcel(RequiredInputType.NFC_DECRYPT,
+ new byte[][] { inputHash }, null, null, null, subKeyId);
+ }
+
+ public static RequiredInputParcel createRequiredSignPassphrase(
+ long masterKeyId, long subKeyId, Date signatureTime) {
+ return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
+ null, null, signatureTime, masterKeyId, subKeyId);
+ }
+
+ public static RequiredInputParcel createRequiredDecryptPassphrase(
+ long masterKeyId, long subKeyId) {
+ return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
+ null, null, null, masterKeyId, subKeyId);
+ }
+
+ public static RequiredInputParcel createRequiredSymmetricPassphrase() {
+ return new RequiredInputParcel(RequiredInputType.PASSPHRASE_SYMMETRIC,
+ null, null, null, null, null);
+ }
+
+ public static RequiredInputParcel createRequiredPassphrase(
+ RequiredInputParcel req) {
+ return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
+ null, null, req.mSignatureTime, req.mMasterKeyId, req.mSubKeyId);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mType.ordinal());
+ if (mInputHashes != null) {
+ dest.writeInt(mSignAlgos != null ? 1 : 2);
+ dest.writeInt(mInputHashes.length);
+ for (int i = 0; i < mInputHashes.length; i++) {
+ dest.writeByteArray(mInputHashes[i]);
+ if (mSignAlgos != null) {
+ dest.writeInt(mSignAlgos[i]);
+ }
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSignatureTime != null) {
+ dest.writeInt(1);
+ dest.writeLong(mSignatureTime.getTime());
+ } else {
+ dest.writeInt(0);
+ }
+ if (mMasterKeyId != null) {
+ dest.writeInt(1);
+ dest.writeLong(mMasterKeyId);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSubKeyId != null) {
+ dest.writeInt(1);
+ dest.writeLong(mSubKeyId);
+ } else {
+ dest.writeInt(0);
+ }
+
+ }
+
+ public static final Creator<RequiredInputParcel> CREATOR = new Creator<RequiredInputParcel>() {
+ public RequiredInputParcel createFromParcel(final Parcel source) {
+ return new RequiredInputParcel(source);
+ }
+
+ public RequiredInputParcel[] newArray(final int size) {
+ return new RequiredInputParcel[size];
+ }
+ };
+
+ public static class NfcSignOperationsBuilder {
+ Date mSignatureTime;
+ ArrayList<Integer> mSignAlgos = new ArrayList<>();
+ ArrayList<byte[]> mInputHashes = new ArrayList<>();
+ Long mMasterKeyId;
+ Long mSubKeyId;
+
+ public NfcSignOperationsBuilder(Date signatureTime, Long masterKeyId, Long subKeyId) {
+ mSignatureTime = signatureTime;
+ mMasterKeyId = masterKeyId;
+ mSubKeyId = subKeyId;
+ }
+
+ public RequiredInputParcel build() {
+ byte[][] inputHashes = new byte[mInputHashes.size()][];
+ mInputHashes.toArray(inputHashes);
+ int[] signAlgos = new int[mSignAlgos.size()];
+ for (int i = 0; i < mSignAlgos.size(); i++) {
+ signAlgos[i] = mSignAlgos.get(i);
+ }
+
+ return new RequiredInputParcel(RequiredInputType.NFC_SIGN,
+ inputHashes, signAlgos, mSignatureTime, mMasterKeyId, mSubKeyId);
+ }
+
+ public void addHash(byte[] hash, int algo) {
+ mInputHashes.add(hash);
+ mSignAlgos.add(algo);
+ }
+
+ public void addAll(RequiredInputParcel input) {
+ if (!mSignatureTime.equals(input.mSignatureTime)) {
+ throw new AssertionError("input times must match, this is a programming error!");
+ }
+ if (input.mType != RequiredInputType.NFC_SIGN) {
+ throw new AssertionError("operation types must match, this is a progrmming error!");
+ }
+
+ Collections.addAll(mInputHashes, input.mInputHashes);
+ for (int signAlgo : input.mSignAlgos) {
+ mSignAlgos.add(signAlgo);
+ }
+ }
+
+ public boolean isEmpty() {
+ return mInputHashes.isEmpty();
+ }
+
+ }
+
+}