aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java197
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OldSaveKeyringParcel.java128
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java96
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java158
4 files changed, 303 insertions, 276 deletions
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 6f38418ff..38f40db29 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -26,29 +26,25 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import org.spongycastle.bcpg.sig.KeyFlags;
-import org.spongycastle.openpgp.PGPKeyRing;
-import org.spongycastle.openpgp.PGPObjectFactory;
-import org.spongycastle.openpgp.PGPPublicKey;
-import org.spongycastle.openpgp.PGPPublicKeyRing;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.PGPUtil;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
-import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
+import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
+import org.sufficientlysecure.keychain.pgp.UncachedSecretKey;
+import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing;
+import org.sufficientlysecure.keychain.pgp.WrappedSecretKey;
+import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
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.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.Progressable;
+import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
@@ -60,7 +56,6 @@ import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
-import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -497,7 +492,7 @@ public class KeychainIntentService extends IntentService
} else if (ACTION_SAVE_KEYRING.equals(action)) {
try {
/* Input */
- SaveKeyringParcel saveParcel = data.getParcelable(SAVE_KEYRING_PARCEL);
+ OldSaveKeyringParcel saveParcel = data.getParcelable(SAVE_KEYRING_PARCEL);
String oldPassphrase = saveParcel.oldPassphrase;
String newPassphrase = saveParcel.newPassphrase;
boolean canSign = true;
@@ -510,33 +505,36 @@ public class KeychainIntentService extends IntentService
newPassphrase = oldPassphrase;
}
- long masterKeyId = saveParcel.keys.get(0).getKeyID();
+ long masterKeyId = saveParcel.keys.get(0).getKeyId();
/* Operation */
ProviderHelper providerHelper = new ProviderHelper(this);
if (!canSign) {
- PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 50, 100));
- PGPSecretKeyRing keyRing = providerHelper.getPGPSecretKeyRing(masterKeyId);
- keyRing = keyOperations.changeSecretKeyPassphrase(keyRing,
- oldPassphrase, newPassphrase);
+ setProgress(R.string.progress_building_key, 0, 100);
+ WrappedSecretKeyRing keyRing = providerHelper.getWrappedSecretKeyRing(masterKeyId);
+ UncachedKeyRing newKeyRing =
+ keyRing.changeSecretKeyPassphrase(oldPassphrase, newPassphrase);
setProgress(R.string.progress_saving_key_ring, 50, 100);
- providerHelper.saveKeyRing(keyRing);
+ providerHelper.saveSecretKeyRing(newKeyRing);
setProgress(R.string.progress_done, 100, 100);
} else {
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100));
- PgpKeyOperation.Pair<PGPSecretKeyRing, PGPPublicKeyRing> pair;
try {
- PGPSecretKeyRing privkey = providerHelper.getPGPSecretKeyRing(masterKeyId);
- PGPPublicKeyRing pubkey = providerHelper.getPGPPublicKeyRing(masterKeyId);
+ WrappedSecretKeyRing seckey = providerHelper.getWrappedSecretKeyRing(masterKeyId);
+ WrappedPublicKeyRing pubkey = providerHelper.getWrappedPublicKeyRing(masterKeyId);
- pair = keyOperations.buildSecretKey(privkey, pubkey, saveParcel); // edit existing
+ PgpKeyOperation.Pair<UncachedKeyRing,UncachedKeyRing> pair =
+ keyOperations.buildSecretKey(seckey, pubkey, saveParcel); // edit existing
+ setProgress(R.string.progress_saving_key_ring, 90, 100);
+ providerHelper.saveKeyRing(pair.first, pair.second);
} catch (ProviderHelper.NotFoundException e) {
- pair = keyOperations.buildNewSecretKey(saveParcel); //new Keyring
+ PgpKeyOperation.Pair<UncachedKeyRing,UncachedKeyRing> pair =
+ keyOperations.buildNewSecretKey(saveParcel); //new Keyring
+ // save the pair
+ setProgress(R.string.progress_saving_key_ring, 90, 100);
+ providerHelper.saveKeyRing(pair.first, pair.second);
}
- setProgress(R.string.progress_saving_key_ring, 90, 100);
- // save the pair
- providerHelper.saveKeyRing(pair.second, pair.first);
setProgress(R.string.progress_done, 100, 100);
}
PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase);
@@ -556,13 +554,11 @@ public class KeychainIntentService extends IntentService
/* Operation */
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100));
- PGPSecretKey newKey = keyOperations.createKey(algorithm, keysize,
- passphrase, masterKey);
+ byte[] newKey = keyOperations.createKey(algorithm, keysize, passphrase, masterKey);
/* Output */
Bundle resultData = new Bundle();
- resultData.putByteArray(RESULT_NEW_KEY,
- PgpConversionHelper.PGPSecretKeyToBytes(newKey));
+ resultData.putByteArray(RESULT_NEW_KEY, newKey);
OtherHelper.logDebugBundle(resultData, "resultData");
@@ -575,7 +571,6 @@ public class KeychainIntentService extends IntentService
try {
/* Input */
String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE);
- ArrayList<PGPSecretKey> newKeys = new ArrayList<PGPSecretKey>();
ArrayList<Integer> keyUsageList = new ArrayList<Integer>();
/* Operation */
@@ -588,24 +583,28 @@ public class KeychainIntentService extends IntentService
keysTotal);
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100));
- PGPSecretKey masterKey = keyOperations.createKey(Constants.choice.algorithm.rsa,
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ byte[] buf;
+
+ buf = keyOperations.createKey(Constants.choice.algorithm.rsa,
4096, passphrase, true);
- newKeys.add(masterKey);
- keyUsageList.add(KeyFlags.CERTIFY_OTHER);
+ os.write(buf);
+ keyUsageList.add(UncachedSecretKey.CERTIFY_OTHER);
keysCreated++;
setProgress(keysCreated, keysTotal);
- PGPSecretKey subKey = keyOperations.createKey(Constants.choice.algorithm.rsa,
+ buf = keyOperations.createKey(Constants.choice.algorithm.rsa,
4096, passphrase, false);
- newKeys.add(subKey);
- keyUsageList.add(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE);
+ os.write(buf);
+ keyUsageList.add(UncachedSecretKey.ENCRYPT_COMMS | UncachedSecretKey.ENCRYPT_STORAGE);
keysCreated++;
setProgress(keysCreated, keysTotal);
- subKey = keyOperations.createKey(Constants.choice.algorithm.rsa,
+ buf = keyOperations.createKey(Constants.choice.algorithm.rsa,
4096, passphrase, false);
- newKeys.add(subKey);
- keyUsageList.add(KeyFlags.SIGN_DATA);
+ os.write(buf);
+ keyUsageList.add(UncachedSecretKey.SIGN_DATA);
keysCreated++;
setProgress(keysCreated, keysTotal);
@@ -613,10 +612,8 @@ public class KeychainIntentService extends IntentService
// for sign
/* Output */
-
Bundle resultData = new Bundle();
- resultData.putByteArray(RESULT_NEW_KEY,
- PgpConversionHelper.PGPSecretKeyArrayListToBytes(newKeys));
+ resultData.putByteArray(RESULT_NEW_KEY, os.toByteArray());
resultData.putIntegerArrayList(RESULT_KEY_USAGES, keyUsageList);
OtherHelper.logDebugBundle(resultData, "resultData");
@@ -648,12 +645,10 @@ public class KeychainIntentService extends IntentService
}
} else if (ACTION_IMPORT_KEYRING.equals(action)) {
try {
- List<ImportKeysListEntry> entries = data.getParcelableArrayList(IMPORT_KEY_LIST);
-
- Bundle resultData = new Bundle();
+ List<ParcelableKeyRing> entries = data.getParcelableArrayList(IMPORT_KEY_LIST);
PgpImportExport pgpImportExport = new PgpImportExport(this, this);
- resultData = pgpImportExport.importKeyRings(entries);
+ Bundle resultData = pgpImportExport.importKeyRings(entries);
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
@@ -727,15 +722,12 @@ public class KeychainIntentService extends IntentService
HkpKeyserver server = new HkpKeyserver(keyServer);
ProviderHelper providerHelper = new ProviderHelper(this);
- PGPPublicKeyRing keyring = (PGPPublicKeyRing) providerHelper.getPGPKeyRing(dataUri);
- if (keyring != null) {
- PgpImportExport pgpImportExport = new PgpImportExport(this, null);
-
- boolean uploaded = pgpImportExport.uploadKeyRingToServer(server,
- (PGPPublicKeyRing) keyring);
- if (!uploaded) {
- throw new PgpGeneralException("Unable to export key to selected server");
- }
+ WrappedPublicKeyRing keyring = providerHelper.getWrappedPublicKeyRing(dataUri);
+ PgpImportExport pgpImportExport = new PgpImportExport(this, null);
+
+ boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, keyring);
+ if (!uploaded) {
+ throw new PgpGeneralException("Unable to export key to selected server");
}
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
@@ -747,40 +739,21 @@ public class KeychainIntentService extends IntentService
try {
KeybaseKeyserver server = new KeybaseKeyserver();
+ ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size());
for (ImportKeysListEntry entry : entries) {
// the keybase handle is in userId(1)
String keybaseId = entry.getExtraData();
byte[] downloadedKeyBytes = server.get(keybaseId).getBytes();
- // create PGPKeyRing object based on downloaded armored key
- PGPKeyRing downloadedKey = null;
- BufferedInputStream bufferedInput =
- new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes));
- if (bufferedInput.available() > 0) {
- InputStream in = PGPUtil.getDecoderStream(bufferedInput);
- PGPObjectFactory objectFactory = new PGPObjectFactory(in);
-
- // get first object in block
- Object obj;
- if ((obj = objectFactory.nextObject()) != null) {
-
- if (obj instanceof PGPKeyRing) {
- downloadedKey = (PGPKeyRing) obj;
- } else {
- throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
- }
- }
- }
-
// save key bytes in entry object for doing the
// actual import afterwards
- entry.setBytes(downloadedKey.getEncoded());
+ keyRings.add(new ParcelableKeyRing(downloadedKeyBytes));
}
Intent importIntent = new Intent(this, KeychainIntentService.class);
importIntent.setAction(ACTION_IMPORT_KEYRING);
Bundle importData = new Bundle();
- importData.putParcelableArrayList(IMPORT_KEY_LIST, entries);
+ importData.putParcelableArrayList(IMPORT_KEY_LIST, keyRings);
importIntent.putExtra(EXTRA_DATA, importData);
importIntent.putExtra(EXTRA_MESSENGER, mMessenger);
@@ -794,11 +767,12 @@ public class KeychainIntentService extends IntentService
} else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action)) {
try {
ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST);
- String keyServer = data.getString(DOWNLOAD_KEY_SERVER);
// this downloads the keys and places them into the ImportKeysListEntry entries
+ String keyServer = data.getString(DOWNLOAD_KEY_SERVER);
HkpKeyserver server = new HkpKeyserver(keyServer);
+ ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size());
for (ImportKeysListEntry entry : entries) {
// if available use complete fingerprint for get request
byte[] downloadedKeyBytes;
@@ -808,49 +782,15 @@ public class KeychainIntentService extends IntentService
downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes();
}
- // create PGPKeyRing object based on downloaded armored key
- PGPKeyRing downloadedKey = null;
- BufferedInputStream bufferedInput =
- new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes));
- if (bufferedInput.available() > 0) {
- InputStream in = PGPUtil.getDecoderStream(bufferedInput);
- PGPObjectFactory objectFactory = new PGPObjectFactory(in);
-
- // get first object in block
- Object obj;
- if ((obj = objectFactory.nextObject()) != null) {
-
- if (obj instanceof PGPKeyRing) {
- downloadedKey = (PGPKeyRing) obj;
- } else {
- throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
- }
- }
- }
-
- // verify downloaded key by comparing fingerprints
- if (entry.getFingerprintHex() != null) {
- String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex(
- downloadedKey.getPublicKey().getFingerprint());
- if (downloadedKeyFp.equals(entry.getFingerprintHex())) {
- Log.d(Constants.TAG, "fingerprint of downloaded key is the same as " +
- "the requested fingerprint!");
- } else {
- throw new PgpGeneralException("fingerprint of downloaded key is " +
- "NOT the same as the requested fingerprint!");
- }
- }
-
// save key bytes in entry object for doing the
// actual import afterwards
- entry.setBytes(downloadedKey.getEncoded());
+ keyRings.add(new ParcelableKeyRing(downloadedKeyBytes, entry.getFingerprintHex()));
}
-
Intent importIntent = new Intent(this, KeychainIntentService.class);
importIntent.setAction(ACTION_IMPORT_KEYRING);
Bundle importData = new Bundle();
- importData.putParcelableArrayList(IMPORT_KEY_LIST, entries);
+ importData.putParcelableArrayList(IMPORT_KEY_LIST, keyRings);
importIntent.putExtra(EXTRA_DATA, importData);
importIntent.putExtra(EXTRA_MESSENGER, mMessenger);
@@ -877,29 +817,18 @@ public class KeychainIntentService extends IntentService
}
ProviderHelper providerHelper = new ProviderHelper(this);
- PgpKeyOperation keyOperation = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100));
- PGPPublicKeyRing publicRing = providerHelper.getPGPPublicKeyRing(pubKeyId);
- PGPPublicKey publicKey = publicRing.getPublicKey(pubKeyId);
- PGPSecretKeyRing secretKeyRing = null;
- try {
- secretKeyRing = providerHelper.getPGPSecretKeyRing(masterKeyId);
- } catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "key not found!", e);
- // TODO: throw exception here!
+ WrappedPublicKeyRing publicRing = providerHelper.getWrappedPublicKeyRing(pubKeyId);
+ WrappedSecretKeyRing secretKeyRing = providerHelper.getWrappedSecretKeyRing(masterKeyId);
+ WrappedSecretKey certificationKey = secretKeyRing.getSubKey();
+ if(!certificationKey.unlock(signaturePassphrase)) {
+ throw new PgpGeneralException("Error extracting key (bad passphrase?)");
}
- PGPSecretKey certificationKey = PgpKeyHelper.getFirstCertificationSubkey(secretKeyRing);
- publicKey = keyOperation.certifyKey(certificationKey, publicKey,
- userIds, signaturePassphrase);
- publicRing = PGPPublicKeyRing.insertPublicKey(publicRing, publicKey);
+ UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds);
// store the signed key in our local cache
- PgpImportExport pgpImportExport = new PgpImportExport(this, null);
- int retval = pgpImportExport.storeKeyRingInCache(publicRing);
- if (retval != PgpImportExport.RETURN_OK && retval != PgpImportExport.RETURN_UPDATED) {
- throw new PgpGeneralException("Failed to store signed key in local cache");
- }
-
+ providerHelper.savePublicKeyRing(newRing);
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
+
} catch (Exception e) {
sendErrorToHandler(e);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OldSaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OldSaveKeyringParcel.java
new file mode 100644
index 000000000..b722393ad
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OldSaveKeyringParcel.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 Ash Hughes <ashes-iontach@hotmail.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.service;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
+import org.sufficientlysecure.keychain.pgp.UncachedSecretKey;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+
+/** Class for parcelling data between ui and services.
+ * This class is outdated and scheduled for removal, pending a rewrite of the
+ * EditKeyActivity and save keyring routines.
+ */
+@Deprecated
+public class OldSaveKeyringParcel implements Parcelable {
+
+ public ArrayList<String> userIds;
+ public ArrayList<String> originalIDs;
+ public ArrayList<String> deletedIDs;
+ public boolean[] newIDs;
+ public boolean primaryIDChanged;
+ public boolean[] moddedKeys;
+ public ArrayList<UncachedSecretKey> deletedKeys;
+ public ArrayList<Calendar> keysExpiryDates;
+ public ArrayList<Integer> keysUsages;
+ public String newPassphrase;
+ public String oldPassphrase;
+ public boolean[] newKeys;
+ public ArrayList<UncachedSecretKey> keys;
+ public String originalPrimaryID;
+
+ public OldSaveKeyringParcel() {}
+
+ private OldSaveKeyringParcel(Parcel source) {
+ userIds = (ArrayList<String>) source.readSerializable();
+ originalIDs = (ArrayList<String>) source.readSerializable();
+ deletedIDs = (ArrayList<String>) source.readSerializable();
+ newIDs = source.createBooleanArray();
+ primaryIDChanged = source.readByte() != 0;
+ moddedKeys = source.createBooleanArray();
+ byte[] tmp = source.createByteArray();
+ if (tmp == null) {
+ deletedKeys = null;
+ } else {
+ deletedKeys = PgpConversionHelper.BytesToPGPSecretKeyList(tmp);
+ }
+ keysExpiryDates = (ArrayList<Calendar>) source.readSerializable();
+ keysUsages = source.readArrayList(Integer.class.getClassLoader());
+ newPassphrase = source.readString();
+ oldPassphrase = source.readString();
+ newKeys = source.createBooleanArray();
+ keys = PgpConversionHelper.BytesToPGPSecretKeyList(source.createByteArray());
+ originalPrimaryID = source.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeSerializable(userIds); //might not be the best method to store.
+ destination.writeSerializable(originalIDs);
+ destination.writeSerializable(deletedIDs);
+ destination.writeBooleanArray(newIDs);
+ destination.writeByte((byte) (primaryIDChanged ? 1 : 0));
+ destination.writeBooleanArray(moddedKeys);
+ destination.writeByteArray(encodeArrayList(deletedKeys));
+ destination.writeSerializable(keysExpiryDates);
+ destination.writeList(keysUsages);
+ destination.writeString(newPassphrase);
+ destination.writeString(oldPassphrase);
+ destination.writeBooleanArray(newKeys);
+ destination.writeByteArray(encodeArrayList(keys));
+ destination.writeString(originalPrimaryID);
+ }
+
+ public static final Creator<OldSaveKeyringParcel> CREATOR = new Creator<OldSaveKeyringParcel>() {
+ public OldSaveKeyringParcel createFromParcel(final Parcel source) {
+ return new OldSaveKeyringParcel(source);
+ }
+
+ public OldSaveKeyringParcel[] newArray(final int size) {
+ return new OldSaveKeyringParcel[size];
+ }
+ };
+
+ private static byte[] encodeArrayList(ArrayList<UncachedSecretKey> list) {
+ if(list.isEmpty()) {
+ return null;
+ }
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ for(UncachedSecretKey key : new IterableIterator<UncachedSecretKey>(list.iterator())) {
+ try {
+ key.encodeSecretKey(os);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "Error while converting ArrayList<UncachedSecretKey> to byte[]!", e);
+ }
+ }
+ return os.toByteArray();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
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 db4fecef0..d42bae67a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -34,20 +34,14 @@ import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.util.LongSparseArray;
-import org.spongycastle.openpgp.PGPException;
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openpgp.PGPSecretKeyRing;
-import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
import java.util.Date;
-import java.util.Iterator;
/**
* This service runs in its own process, but is available to all other processes as the main
@@ -163,81 +157,47 @@ public class PassphraseCacheService extends Service {
* @return
*/
private String getCachedPassphraseImpl(long keyId) {
- Log.d(TAG, "getCachedPassphraseImpl() get masterKeyId for " + keyId);
-
- // try to get master key id which is used as an identifier for cached passphrases
- long masterKeyId = keyId;
- if (masterKeyId != Constants.key.symmetric) {
- try {
- masterKeyId = new ProviderHelper(this).getMasterKeyId(
- KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)));
- } catch (ProviderHelper.NotFoundException e) {
+ // passphrase for symmetric encryption?
+ if (keyId == Constants.key.symmetric) {
+ Log.d(TAG, "getCachedPassphraseImpl() for symmetric encryption");
+ String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric);
+ if (cachedPassphrase == null) {
return null;
}
+ addCachedPassphrase(this, Constants.key.symmetric, cachedPassphrase);
+ return cachedPassphrase;
}
- Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + masterKeyId);
- // get cached passphrase
- String cachedPassphrase = mPassphraseCache.get(masterKeyId);
- if (cachedPassphrase == null) {
- // if key has no passphrase -> cache and return empty passphrase
- if (!hasPassphrase(this, masterKeyId)) {
+ // try to get master key id which is used as an identifier for cached passphrases
+ try {
+ Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + keyId);
+ WrappedSecretKeyRing key = new ProviderHelper(this).getWrappedSecretKeyRing(
+ KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId));
+ // no passphrase needed? just add empty string and return it, then
+ if (!key.hasPassphrase()) {
Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!");
- addCachedPassphrase(this, masterKeyId, "");
+ addCachedPassphrase(this, keyId, "");
return "";
- } else {
- return null;
}
- }
- // set it again to reset the cache life cycle
- Log.d(TAG, "Cache passphrase again when getting it!");
- addCachedPassphrase(this, masterKeyId, cachedPassphrase);
- return cachedPassphrase;
- }
-
- public static boolean hasPassphrase(PGPSecretKeyRing secretKeyRing) {
- PGPSecretKey secretKey = null;
- boolean foundValidKey = false;
- for (Iterator keys = secretKeyRing.getSecretKeys(); keys.hasNext(); ) {
- secretKey = (PGPSecretKey) keys.next();
- if (!secretKey.isPrivateKeyEmpty()) {
- foundValidKey = true;
- break;
+ // get cached passphrase
+ String cachedPassphrase = mPassphraseCache.get(keyId);
+ if (cachedPassphrase == null) {
+ Log.d(TAG, "Passphrase not (yet) cached, returning null");
+ // not really an error, just means the passphrase is not cached but not empty either
+ return null;
}
- }
- if(!foundValidKey) {
- return false;
- }
- try {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider("SC").build("".toCharArray());
- PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor);
- return testKey == null;
- } catch(PGPException e) {
- // this means the crc check failed -> passphrase required
- return true;
- }
- }
+ // set it again to reset the cache life cycle
+ Log.d(TAG, "Cache passphrase again when getting it!");
+ addCachedPassphrase(this, keyId, cachedPassphrase);
+ return cachedPassphrase;
- /**
- * Checks if key has a passphrase.
- *
- * @param secretKeyId
- * @return true if it has a passphrase
- */
- public static boolean hasPassphrase(Context context, long secretKeyId) {
- // check if the key has no passphrase
- try {
- PGPSecretKeyRing secRing = new ProviderHelper(context).getPGPSecretKeyRing(secretKeyId);
- return hasPassphrase(secRing);
} catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "key not found!", e);
+ Log.e(TAG, "Passphrase for unknown key was requested!");
+ return null;
}
-
- return true;
}
/**
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 3f0b37b75..3514ab2e5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
@@ -1,92 +1,101 @@
-/*
- * Copyright (C) 2014 Ash Hughes <ashes-iontach@hotmail.com>
+package org.sufficientlysecure.keychain.service;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+/** This class is a a transferable representation for a collection of changes
+ * to be done on a keyring.
*
- * 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 class should include all types of operations supported in the backend.
*
- * 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.
+ * All changes are done in a differential manner. Besides the two key
+ * identification attributes, all attributes may be null, which indicates no
+ * change to the keyring. This is also the reason why boxed values are used
+ * instead of primitives in the subclasses.
*
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * Application of operations in the backend should be fail-fast, which means an
+ * error in any included operation (for example revocation of a non-existent
+ * subkey) will cause the operation as a whole to fail.
*/
+public class SaveKeyringParcel implements Parcelable {
-package org.sufficientlysecure.keychain.service;
+ // the master key id to be edited
+ private final long mMasterKeyId;
+ // the key fingerprint, for safety
+ private final byte[] mFingerprint;
-import android.os.Parcel;
-import android.os.Parcelable;
+ public String newPassphrase;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
+ public String[] addUserIds;
+ public SubkeyAdd[] addSubKeys;
-import java.util.ArrayList;
-import java.util.Calendar;
+ public HashMap<Long, SubkeyChange> changeSubKeys;
+ public String changePrimaryUserId;
-public class SaveKeyringParcel implements Parcelable {
+ public String[] revokeUserIds;
+ public long[] revokeSubKeys;
- public ArrayList<String> userIds;
- public ArrayList<String> originalIDs;
- public ArrayList<String> deletedIDs;
- public boolean[] newIDs;
- public boolean primaryIDChanged;
- public boolean[] moddedKeys;
- public ArrayList<PGPSecretKey> deletedKeys;
- public ArrayList<Calendar> keysExpiryDates;
- public ArrayList<Integer> keysUsages;
- public String newPassphrase;
- public String oldPassphrase;
- public boolean[] newKeys;
- public ArrayList<PGPSecretKey> keys;
- public String originalPrimaryID;
-
- public SaveKeyringParcel() {}
-
- private SaveKeyringParcel(Parcel source) {
- userIds = (ArrayList<String>) source.readSerializable();
- originalIDs = (ArrayList<String>) source.readSerializable();
- deletedIDs = (ArrayList<String>) source.readSerializable();
- newIDs = source.createBooleanArray();
- primaryIDChanged = source.readByte() != 0;
- moddedKeys = source.createBooleanArray();
- byte[] tmp = source.createByteArray();
- if (tmp == null) {
- deletedKeys = null;
- } else {
- deletedKeys = PgpConversionHelper.BytesToPGPSecretKeyList(tmp);
+ public SaveKeyringParcel(long masterKeyId, byte[] fingerprint) {
+ mMasterKeyId = masterKeyId;
+ mFingerprint = fingerprint;
+ }
+
+ // performance gain for using Parcelable here would probably be negligible,
+ // use Serializable instead.
+ public static class SubkeyAdd implements Serializable {
+ public final int mAlgorithm;
+ public final int mKeysize;
+ public final int mFlags;
+ public final Long mExpiry;
+ public SubkeyAdd(int algorithm, int keysize, int flags, Long expiry) {
+ mAlgorithm = algorithm;
+ mKeysize = keysize;
+ mFlags = flags;
+ mExpiry = expiry;
+ }
+ }
+
+ public static class SubkeyChange implements Serializable {
+ public final long mKeyId;
+ public final Integer mFlags;
+ public final Long mExpiry;
+ public SubkeyChange(long keyId, Integer flags, Long expiry) {
+ mKeyId = keyId;
+ mFlags = flags;
+ mExpiry = expiry;
}
- keysExpiryDates = (ArrayList<Calendar>) source.readSerializable();
- keysUsages = source.readArrayList(Integer.class.getClassLoader());
- newPassphrase = source.readString();
- oldPassphrase = source.readString();
- newKeys = source.createBooleanArray();
- keys = PgpConversionHelper.BytesToPGPSecretKeyList(source.createByteArray());
- originalPrimaryID = source.readString();
+ }
+
+ public SaveKeyringParcel(Parcel source) {
+ mMasterKeyId = source.readLong();
+ mFingerprint = source.createByteArray();
+
+ addUserIds = source.createStringArray();
+ addSubKeys = (SubkeyAdd[]) source.readSerializable();
+
+ changeSubKeys = (HashMap<Long,SubkeyChange>) source.readSerializable();
+ changePrimaryUserId = source.readString();
+
+ revokeUserIds = source.createStringArray();
+ revokeSubKeys = source.createLongArray();
}
@Override
public void writeToParcel(Parcel destination, int flags) {
- destination.writeSerializable(userIds); //might not be the best method to store.
- destination.writeSerializable(originalIDs);
- destination.writeSerializable(deletedIDs);
- destination.writeBooleanArray(newIDs);
- destination.writeByte((byte) (primaryIDChanged ? 1 : 0));
- destination.writeBooleanArray(moddedKeys);
- byte[] tmp = null;
- if (deletedKeys.size() != 0) {
- tmp = PgpConversionHelper.PGPSecretKeyArrayListToBytes(deletedKeys);
- }
- destination.writeByteArray(tmp);
- destination.writeSerializable(keysExpiryDates);
- destination.writeList(keysUsages);
- destination.writeString(newPassphrase);
- destination.writeString(oldPassphrase);
- destination.writeBooleanArray(newKeys);
- destination.writeByteArray(PgpConversionHelper.PGPSecretKeyArrayListToBytes(keys));
- destination.writeString(originalPrimaryID);
+ destination.writeLong(mMasterKeyId);
+ destination.writeByteArray(mFingerprint);
+
+ destination.writeStringArray(addUserIds);
+ destination.writeSerializable(addSubKeys);
+
+ destination.writeSerializable(changeSubKeys);
+ destination.writeString(changePrimaryUserId);
+
+ destination.writeStringArray(revokeUserIds);
+ destination.writeLongArray(revokeSubKeys);
}
public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() {
@@ -103,4 +112,5 @@ public class SaveKeyringParcel implements Parcelable {
public int describeContents() {
return 0;
}
+
}