diff options
author | mar-v-in <github@rvin.mooo.com> | 2014-06-04 21:32:37 +0200 |
---|---|---|
committer | mar-v-in <github@rvin.mooo.com> | 2014-06-04 21:32:37 +0200 |
commit | cae0071342e746c934490298c3dd3ee230a2ee32 (patch) | |
tree | 5c540d7c8ad84b462fd3cbc87b0aea7c5513fc9c /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service | |
parent | 6a637462782b4ce57ecf154edf0974114181b8ad (diff) | |
parent | 52f1f30846ad7efa6e6ae11ed96f5b68626bfb3b (diff) | |
download | open-keychain-cae0071342e746c934490298c3dd3ee230a2ee32.tar.gz open-keychain-cae0071342e746c934490298c3dd3ee230a2ee32.tar.bz2 open-keychain-cae0071342e746c934490298c3dd3ee230a2ee32.zip |
Merge branch 'master' into automatic-contact-discovery
Conflicts:
OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service')
4 files changed, 301 insertions, 254 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 2b8745f0a..ce706c84f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -26,14 +26,6 @@ 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; @@ -41,15 +33,19 @@ import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver; -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; @@ -61,7 +57,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; @@ -498,7 +493,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; @@ -511,33 +506,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); @@ -557,13 +555,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"); @@ -576,7 +572,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 */ @@ -589,24 +584,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); @@ -614,10 +613,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"); @@ -649,12 +646,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) { @@ -728,15 +723,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); @@ -746,9 +738,11 @@ public class KeychainIntentService extends IntentService } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action) || ACTION_IMPORT_KEYBASE_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); + + ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size()); for (ImportKeysListEntry entry : entries) { Keyserver server; @@ -770,49 +764,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.equalsIgnoreCase(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); @@ -839,29 +799,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; } + } |