diff options
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service')
13 files changed, 393 insertions, 1931 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index daaff5d54..1c6aa7971 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -18,30 +18,61 @@ package org.sufficientlysecure.keychain.service; import android.app.IntentService; -import android.content.Context; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; -import org.spongycastle.openpgp.*; + +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.Id; 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.pgp.*; +import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; +import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.pgp.PgpImportExport; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; +import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import org.sufficientlysecure.keychain.util.*; - -import java.io.*; +import org.sufficientlysecure.keychain.util.HkpKeyServer; +import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.KeychainServiceListener; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; +import org.sufficientlysecure.keychain.util.ProgressScaler; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; -import java.util.GregorianCalendar; import java.util.List; /** @@ -84,35 +115,26 @@ public class KeychainIntentService extends IntentService // possible targets: public static final int TARGET_BYTES = 1; public static final int TARGET_URI = 2; - public static final int TARGET_STREAM = 3; // encrypt - public static final String ENCRYPT_SECRET_KEY_ID = "secret_key_id"; + public static final String ENCRYPT_SIGNATURE_KEY_ID = "secret_key_id"; public static final String ENCRYPT_USE_ASCII_ARMOR = "use_ascii_armor"; public static final String ENCRYPT_ENCRYPTION_KEYS_IDS = "encryption_keys_ids"; public static final String ENCRYPT_COMPRESSION_ID = "compression_id"; - public static final String ENCRYPT_GENERATE_SIGNATURE = "generate_signature"; - public static final String ENCRYPT_SIGN_ONLY = "sign_only"; public static final String ENCRYPT_MESSAGE_BYTES = "message_bytes"; public static final String ENCRYPT_INPUT_FILE = "input_file"; public static final String ENCRYPT_OUTPUT_FILE = "output_file"; - public static final String ENCRYPT_PROVIDER_URI = "provider_uri"; + public static final String ENCRYPT_SYMMETRIC_PASSPHRASE = "passphrase"; // decrypt/verify - public static final String DECRYPT_RETURN_BYTES = "return_binary"; public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes"; - public static final String DECRYPT_ASSUME_SYMMETRIC = "assume_symmetric"; + public static final String DECRYPT_PASSPHRASE = "passphrase"; // save keyring - public static final String SAVE_KEYRING_NEW_PASSPHRASE = "new_passphrase"; - public static final String SAVE_KEYRING_CURRENT_PASSPHRASE = "current_passphrase"; - public static final String SAVE_KEYRING_USER_IDS = "user_ids"; - public static final String SAVE_KEYRING_KEYS = "keys"; - public static final String SAVE_KEYRING_KEYS_USAGES = "keys_usages"; - public static final String SAVE_KEYRING_KEYS_EXPIRY_DATES = "keys_expiry_dates"; - public static final String SAVE_KEYRING_MASTER_KEY_ID = "master_key_id"; + public static final String SAVE_KEYRING_PARCEL = "save_parcel"; public static final String SAVE_KEYRING_CAN_SIGN = "can_sign"; + // generate key public static final String GENERATE_KEY_ALGORITHM = "algorithm"; public static final String GENERATE_KEY_KEY_SIZE = "key_size"; @@ -128,10 +150,9 @@ public class KeychainIntentService extends IntentService // export key public static final String EXPORT_OUTPUT_STREAM = "export_output_stream"; public static final String EXPORT_FILENAME = "export_filename"; - public static final String EXPORT_KEY_TYPE = "export_key_type"; + public static final String EXPORT_SECRET = "export_secret"; public static final String EXPORT_ALL = "export_all"; public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id"; - public static final String EXPORT_KEY_RING_ROW_ID = "export_key_rind_row_id"; // upload key public static final String UPLOAD_KEY_SERVER = "upload_key_server"; @@ -150,17 +171,12 @@ public class KeychainIntentService extends IntentService */ // keys public static final String RESULT_NEW_KEY = "new_key"; - public static final String RESULT_NEW_KEY2 = "new_key2"; + public static final String RESULT_KEY_USAGES = "new_key_usages"; // encrypt - public static final String RESULT_SIGNATURE_BYTES = "signature_data"; - public static final String RESULT_SIGNATURE_STRING = "signature_text"; - public static final String RESULT_ENCRYPTED_STRING = "encrypted_message"; - public static final String RESULT_ENCRYPTED_BYTES = "encrypted_data"; - public static final String RESULT_URI = "result_uri"; + public static final String RESULT_BYTES = "encrypted_data"; // decrypt/verify - public static final String RESULT_DECRYPTED_STRING = "decrypted_message"; public static final String RESULT_DECRYPTED_BYTES = "decrypted_data"; public static final String RESULT_DECRYPT_VERIFY_RESULT = "signature"; @@ -172,10 +188,6 @@ public class KeychainIntentService extends IntentService // export public static final String RESULT_EXPORT = "exported"; - // query - public static final String RESULT_QUERY_KEY_DATA = "query_key_data"; - public static final String RESULT_QUERY_KEY_SEARCH_RESULT = "query_key_search_result"; - Messenger mMessenger; private boolean mIsCanceled; @@ -225,20 +237,17 @@ public class KeychainIntentService extends IntentService /* Input */ int target = data.getInt(TARGET); - long secretKeyId = data.getLong(ENCRYPT_SECRET_KEY_ID); - String encryptionPassphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE); + long signatureKeyId = data.getLong(ENCRYPT_SIGNATURE_KEY_ID); + String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); - boolean generateSignature = data.getBoolean(ENCRYPT_GENERATE_SIGNATURE); - boolean signOnly = data.getBoolean(ENCRYPT_SIGN_ONLY); - - InputStream inStream = null; - long inLength = -1; - InputData inputData = null; - OutputStream outStream = null; - String streamFilename = null; + InputStream inStream; + long inLength; + InputData inputData; + OutputStream outStream; +// String streamFilename = null; switch (target) { case TARGET_BYTES: /* encrypting bytes directly */ byte[] bytes = data.getByteArray(ENCRYPT_MESSAGE_BYTES); @@ -270,29 +279,30 @@ public class KeychainIntentService extends IntentService break; - case TARGET_STREAM: /* Encrypting stream from content uri */ - Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI); - - // InputStream - InputStream in = getContentResolver().openInputStream(providerUri); - inLength = PgpHelper.getLengthOfStream(in); - inputData = new InputData(in, inLength); - - // OutputStream - try { - while (true) { - streamFilename = PgpHelper.generateRandomFilename(32); - if (streamFilename == null) { - throw new PgpGeneralException("couldn't generate random file name"); - } - openFileInput(streamFilename).close(); - } - } catch (FileNotFoundException e) { - // found a name that isn't used yet - } - outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE); - - break; + // TODO: not used currently +// case TARGET_STREAM: /* Encrypting stream from content uri */ +// Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI); +// +// // InputStream +// InputStream in = getContentResolver().openInputStream(providerUri); +// inLength = PgpHelper.getLengthOfStream(in); +// inputData = new InputData(in, inLength); +// +// // OutputStream +// try { +// while (true) { +// streamFilename = PgpHelper.generateRandomFilename(32); +// if (streamFilename == null) { +// throw new PgpGeneralException("couldn't generate random file name"); +// } +// openFileInput(streamFilename).close(); +// } +// } catch (FileNotFoundException e) { +// // found a name that isn't used yet +// } +// outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE); +// +// break; default: throw new PgpGeneralException("No target choosen!"); @@ -304,45 +314,20 @@ public class KeychainIntentService extends IntentService new PgpSignEncrypt.Builder(this, inputData, outStream); builder.progress(this); - if (generateSignature) { - Log.d(Constants.TAG, "generating signature..."); - builder.enableAsciiArmorOutput(useAsciiArmor) - .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures()) - .signatureKeyId(secretKeyId) - .signatureHashAlgorithm( - Preferences.getPreferences(this).getDefaultHashAlgorithm()) - .signaturePassphrase( - PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); - - builder.build().generateSignature(); - } else if (signOnly) { - Log.d(Constants.TAG, "sign only..."); - builder.enableAsciiArmorOutput(useAsciiArmor) - .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures()) - .signatureKeyId(secretKeyId) - .signatureHashAlgorithm( - Preferences.getPreferences(this).getDefaultHashAlgorithm()) - .signaturePassphrase( - PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); - - builder.build().execute(); - } else { - Log.d(Constants.TAG, "encrypt..."); - builder.enableAsciiArmorOutput(useAsciiArmor) - .compressionId(compressionId) - .symmetricEncryptionAlgorithm( - Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) - .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures()) - .encryptionKeyIds(encryptionKeyIds) - .encryptionPassphrase(encryptionPassphrase) - .signatureKeyId(secretKeyId) - .signatureHashAlgorithm( - Preferences.getPreferences(this).getDefaultHashAlgorithm()) - .signaturePassphrase( - PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); - - builder.build().execute(); - } + builder.enableAsciiArmorOutput(useAsciiArmor) + .compressionId(compressionId) + .symmetricEncryptionAlgorithm( + Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) + .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures()) + .encryptionKeyIds(encryptionKeyIds) + .symmetricPassphrase(symmetricPassphrase) + .signatureKeyId(signatureKeyId) + .signatureHashAlgorithm( + Preferences.getPreferences(this).getDefaultHashAlgorithm()) + .signaturePassphrase( + PassphraseCacheService.getCachedPassphrase(this, signatureKeyId)); + + builder.build().execute(); outStream.close(); @@ -352,33 +337,20 @@ public class KeychainIntentService extends IntentService switch (target) { case TARGET_BYTES: - if (useAsciiArmor) { - String output = new String( - ((ByteArrayOutputStream) outStream).toByteArray()); - if (generateSignature) { - resultData.putString(RESULT_SIGNATURE_STRING, output); - } else { - resultData.putString(RESULT_ENCRYPTED_STRING, output); - } - } else { - byte output[] = ((ByteArrayOutputStream) outStream).toByteArray(); - if (generateSignature) { - resultData.putByteArray(RESULT_SIGNATURE_BYTES, output); - } else { - resultData.putByteArray(RESULT_ENCRYPTED_BYTES, output); - } - } + byte output[] = ((ByteArrayOutputStream) outStream).toByteArray(); + + resultData.putByteArray(RESULT_BYTES, output); break; case TARGET_URI: // nothing, file was written, just send okay break; - case TARGET_STREAM: - String uri = DataStream.buildDataStreamUri(streamFilename).toString(); - resultData.putString(RESULT_URI, uri); - - break; +// case TARGET_STREAM: +// String uri = DataStream.buildDataStreamUri(streamFilename).toString(); +// resultData.putString(RESULT_URI, uri); +// +// break; } OtherHelper.logDebugBundle(resultData, "resultData"); @@ -392,15 +364,13 @@ public class KeychainIntentService extends IntentService /* Input */ int target = data.getInt(TARGET); - long secretKeyId = data.getLong(ENCRYPT_SECRET_KEY_ID); byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES); - boolean returnBytes = data.getBoolean(DECRYPT_RETURN_BYTES); - boolean assumeSymmetricEncryption = data.getBoolean(DECRYPT_ASSUME_SYMMETRIC); + String passphrase = data.getString(DECRYPT_PASSPHRASE); - InputStream inStream = null; - long inLength = -1; - InputData inputData = null; - OutputStream outStream = null; + InputStream inStream; + long inLength; + InputData inputData; + OutputStream outStream; String streamFilename = null; switch (target) { case TARGET_BYTES: /* decrypting bytes directly */ @@ -435,29 +405,30 @@ public class KeychainIntentService extends IntentService break; - case TARGET_STREAM: /* decrypting stream from content uri */ - Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI); - - // InputStream - InputStream in = getContentResolver().openInputStream(providerUri); - inLength = PgpHelper.getLengthOfStream(in); - inputData = new InputData(in, inLength); - - // OutputStream - try { - while (true) { - streamFilename = PgpHelper.generateRandomFilename(32); - if (streamFilename == null) { - throw new PgpGeneralException("couldn't generate random file name"); - } - openFileInput(streamFilename).close(); - } - } catch (FileNotFoundException e) { - // found a name that isn't used yet - } - outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE); - - break; + // TODO: not used, maybe contains code useful for new decrypt method for files? +// case TARGET_STREAM: /* decrypting stream from content uri */ +// Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI); +// +// // InputStream +// InputStream in = getContentResolver().openInputStream(providerUri); +// inLength = PgpHelper.getLengthOfStream(in); +// inputData = new InputData(in, inLength); +// +// // OutputStream +// try { +// while (true) { +// streamFilename = PgpHelper.generateRandomFilename(32); +// if (streamFilename == null) { +// throw new PgpGeneralException("couldn't generate random file name"); +// } +// openFileInput(streamFilename).close(); +// } +// } catch (FileNotFoundException e) { +// // found a name that isn't used yet +// } +// outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE); +// +// break; default: throw new PgpGeneralException("No target choosen!"); @@ -473,8 +444,8 @@ public class KeychainIntentService extends IntentService PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream); builder.progressDialogUpdater(this); - builder.assumeSymmetric(assumeSymmetricEncryption) - .passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); + builder.allowSymmetricDecryption(true) + .passphrase(passphrase); PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); @@ -486,25 +457,18 @@ public class KeychainIntentService extends IntentService switch (target) { case TARGET_BYTES: - if (returnBytes) { - byte output[] = ((ByteArrayOutputStream) outStream).toByteArray(); - resultData.putByteArray(RESULT_DECRYPTED_BYTES, output); - } else { - String output = new String( - ((ByteArrayOutputStream) outStream).toByteArray()); - resultData.putString(RESULT_DECRYPTED_STRING, output); - } - + byte output[] = ((ByteArrayOutputStream) outStream).toByteArray(); + resultData.putByteArray(RESULT_DECRYPTED_BYTES, output); break; case TARGET_URI: // nothing, file was written, just send okay and verification bundle break; - case TARGET_STREAM: - String uri = DataStream.buildDataStreamUri(streamFilename).toString(); - resultData.putString(RESULT_URI, uri); - - break; +// case TARGET_STREAM: +// String uri = DataStream.buildDataStreamUri(streamFilename).toString(); +// resultData.putString(RESULT_URI, uri); +// +// break; } OtherHelper.logDebugBundle(resultData, "resultData"); @@ -516,38 +480,42 @@ public class KeychainIntentService extends IntentService } else if (ACTION_SAVE_KEYRING.equals(action)) { try { /* Input */ - String oldPassPhrase = data.getString(SAVE_KEYRING_CURRENT_PASSPHRASE); - String newPassPhrase = data.getString(SAVE_KEYRING_NEW_PASSPHRASE); + SaveKeyringParcel saveParams = data.getParcelable(SAVE_KEYRING_PARCEL); + String oldPassphrase = saveParams.oldPassphrase; + String newPassphrase = saveParams.newPassphrase; boolean canSign = true; if (data.containsKey(SAVE_KEYRING_CAN_SIGN)) { canSign = data.getBoolean(SAVE_KEYRING_CAN_SIGN); } - if (newPassPhrase == null) { - newPassPhrase = oldPassPhrase; + if (newPassphrase == null) { + newPassphrase = oldPassphrase; } - ArrayList<String> userIds = data.getStringArrayList(SAVE_KEYRING_USER_IDS); - ArrayList<PGPSecretKey> keys = PgpConversionHelper.BytesToPGPSecretKeyList(data - .getByteArray(SAVE_KEYRING_KEYS)); - ArrayList<Integer> keysUsages = data.getIntegerArrayList(SAVE_KEYRING_KEYS_USAGES); - ArrayList<GregorianCalendar> keysExpiryDates = - (ArrayList<GregorianCalendar>) data.getSerializable(SAVE_KEYRING_KEYS_EXPIRY_DATES); - long masterKeyId = data.getLong(SAVE_KEYRING_MASTER_KEY_ID); + long masterKeyId = saveParams.keys.get(0).getKeyID(); - PgpKeyOperation keyOperations = new PgpKeyOperation(this, this); /* Operation */ if (!canSign) { - keyOperations.changeSecretKeyPassphrase( - ProviderHelper.getPGPSecretKeyRingByKeyId(this, masterKeyId), - oldPassPhrase, newPassPhrase); + PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 50, 100)); + PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId); + keyRing = keyOperations.changeSecretKeyPassphrase(keyRing, + oldPassphrase, newPassphrase); + setProgress(R.string.progress_saving_key_ring, 50, 100); + ProviderHelper.saveKeyRing(this, keyRing); + setProgress(R.string.progress_done, 100, 100); } else { - PGPPublicKey pubkey = ProviderHelper.getPGPPublicKeyByKeyId(this, masterKeyId); - keyOperations.buildSecretKey(userIds, keys, keysUsages, keysExpiryDates, - pubkey, oldPassPhrase, newPassPhrase); + PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100)); + PGPSecretKeyRing privkey = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId); + PGPPublicKeyRing pubkey = ProviderHelper.getPGPPublicKeyRing(this, masterKeyId); + PgpKeyOperation.Pair<PGPSecretKeyRing,PGPPublicKeyRing> pair = + keyOperations.buildSecretKey(privkey, pubkey, saveParams); + setProgress(R.string.progress_saving_key_ring, 90, 100); + // save the pair + ProviderHelper.saveKeyRing(this, pair.second, pair.first); + setProgress(R.string.progress_done, 100, 100); } - PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassPhrase); + PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase); /* Output */ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); @@ -563,7 +531,7 @@ public class KeychainIntentService extends IntentService boolean masterKey = data.getBoolean(GENERATE_KEY_MASTER_KEY); /* Operation */ - PgpKeyOperation keyOperations = new PgpKeyOperation(this, this); + PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); PGPSecretKey newKey = keyOperations.createKey(algorithm, keysize, passphrase, masterKey); @@ -583,24 +551,37 @@ 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 */ - int keysTotal = 2; + int keysTotal = 3; int keysCreated = 0; setProgress( getApplicationContext().getResources(). getQuantityString(R.plurals.progress_generating, keysTotal), keysCreated, keysTotal); - PgpKeyOperation keyOperations = new PgpKeyOperation(this, this); + PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); PGPSecretKey masterKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, true); + newKeys.add(masterKey); + keyUsageList.add(KeyFlags.CERTIFY_OTHER); keysCreated++; setProgress(keysCreated, keysTotal); PGPSecretKey subKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, false); + newKeys.add(subKey); + keyUsageList.add(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE); + keysCreated++; + setProgress(keysCreated, keysTotal); + + subKey = keyOperations.createKey(Id.choice.algorithm.rsa, + 4096, passphrase, false); + newKeys.add(subKey); + keyUsageList.add(KeyFlags.SIGN_DATA); keysCreated++; setProgress(keysCreated, keysTotal); @@ -608,11 +589,11 @@ public class KeychainIntentService extends IntentService // for sign /* Output */ + Bundle resultData = new Bundle(); resultData.putByteArray(RESULT_NEW_KEY, - PgpConversionHelper.PGPSecretKeyToBytes(masterKey)); - resultData.putByteArray(RESULT_NEW_KEY2, - PgpConversionHelper.PGPSecretKeyToBytes(subKey)); + PgpConversionHelper.PGPSecretKeyArrayListToBytes(newKeys)); + resultData.putIntegerArrayList(RESULT_KEY_USAGES, keyUsageList); OtherHelper.logDebugBundle(resultData, "resultData"); @@ -657,53 +638,50 @@ public class KeychainIntentService extends IntentService } else if (ACTION_EXPORT_KEYRING.equals(action)) { try { - /* Input */ - int keyType = Id.type.public_key; - if (data.containsKey(EXPORT_KEY_TYPE)) { - keyType = data.getInt(EXPORT_KEY_TYPE); - } - + boolean exportSecret = data.getBoolean(EXPORT_SECRET, false); + long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); String outputFile = data.getString(EXPORT_FILENAME); - long[] rowIds = new long[0]; - - // If not exporting all keys get the rowIds of the keys to export from the intent + // If not exporting all keys get the masterKeyIds of the keys to export from the intent boolean exportAll = data.getBoolean(EXPORT_ALL); - if (!exportAll) { - rowIds = data.getLongArray(EXPORT_KEY_RING_ROW_ID); - } - - /* Operation */ // check if storage is ready if (!FileHelper.isStorageMounted(outputFile)) { throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready)); } - // OutputStream - FileOutputStream outStream = new FileOutputStream(outputFile); - - ArrayList<Long> keyRingRowIds = new ArrayList<Long>(); - if (exportAll) { + ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>(); + ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>(); - // get all key ring row ids based on export type - if (keyType == Id.type.public_key) { - keyRingRowIds = ProviderHelper.getPublicKeyRingsRowIds(this); - } else { - keyRingRowIds = ProviderHelper.getSecretKeyRingsRowIds(this); - } - } else { - for (long rowId : rowIds) { - keyRingRowIds.add(rowId); + String selection = null; + if(!exportAll) { + selection = KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN( "; + for(long l : masterKeyIds) { + selection += Long.toString(l) + ","; } + selection = selection.substring(0, selection.length()-1) + " )"; } - Bundle resultData; + Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(), + new String[]{ KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET }, + selection, null, null); + try { + cursor.moveToFirst(); + do { + // export public either way + publicMasterKeyIds.add(cursor.getLong(0)); + // add secret if available (and requested) + if(exportSecret && cursor.getInt(1) != 0) + secretMasterKeyIds.add(cursor.getLong(0)); + } while(cursor.moveToNext()); + } finally { + cursor.close(); + } PgpImportExport pgpImportExport = new PgpImportExport(this, this, this); - - resultData = pgpImportExport - .exportKeyRings(keyRingRowIds, keyType, outStream); + Bundle resultData = pgpImportExport + .exportKeyRings(publicMasterKeyIds, secretMasterKeyIds, + new FileOutputStream(outputFile)); if (mIsCanceled) { boolean isDeleted = new File(outputFile).delete(); @@ -747,45 +725,54 @@ public class KeychainIntentService extends IntentService HkpKeyServer server = new HkpKeyServer(keyServer); for (ImportKeysListEntry entry : entries) { - byte[] downloadedKey = server.get(entry.getKeyId()).getBytes(); - - /** - * TODO: copied from ImportKeysListLoader - * - * - * this parses the downloaded key - */ - // need to have access to the bufferedInput, so we can reuse it for the possible - // PGPObject chunks after the first one, e.g. files with several consecutive ASCII - // armor blocks + // if available use complete fingerprint for get request + byte[] downloadedKeyBytes; + if (entry.getFingerPrintHex() != null) { + downloadedKeyBytes = server.get("0x" + entry.getFingerPrintHex()).getBytes(); + } else { + downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); + } + + // create PGPKeyRing object based on downloaded armored key + PGPKeyRing downloadedKey = null; BufferedInputStream bufferedInput = - new BufferedInputStream(new ByteArrayInputStream(downloadedKey)); - try { - - // read all available blocks... (asc files can contain many blocks with BEGIN END) - while (bufferedInput.available() > 0) { - InputStream in = PGPUtil.getDecoderStream(bufferedInput); - PGPObjectFactory objectFactory = new PGPObjectFactory(in); - - // go through all objects in this block - Object obj; - while ((obj = objectFactory.nextObject()) != null) { - Log.d(Constants.TAG, "Found class: " + obj.getClass()); - - if (obj instanceof PGPKeyRing) { - PGPKeyRing newKeyring = (PGPKeyRing) obj; - - entry.setBytes(newKeyring.getEncoded()); - } else { - Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); - } + 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) { + Log.d(Constants.TAG, "Found class: " + obj.getClass()); + + if (obj instanceof PGPKeyRing) { + downloadedKey = (PGPKeyRing) obj; + } else { + throw new PgpGeneralException("Object not recognized as PGPKeyRing!"); } } - } catch (Exception e) { - Log.e(Constants.TAG, "Exception on parsing key file!", e); } + + // 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()); } + Intent importIntent = new Intent(this, KeychainIntentService.class); importIntent.setAction(ACTION_IMPORT_KEYRING); Bundle importData = new Bundle(); @@ -809,16 +796,24 @@ public class KeychainIntentService extends IntentService ArrayList<String> userIds = data.getStringArrayList(CERTIFY_KEY_UIDS); /* Operation */ - String signaturePassPhrase = PassphraseCacheService.getCachedPassphrase(this, + String signaturePassphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId); + if (signaturePassphrase == null) { + throw new PgpGeneralException("Unable to obtain passphrase"); + } - PgpKeyOperation keyOperation = new PgpKeyOperation(this, this); - PGPPublicKeyRing signedPubKeyRing = keyOperation.certifyKey(masterKeyId, pubKeyId, - userIds, signaturePassPhrase); + PgpKeyOperation keyOperation = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); + PGPPublicKeyRing publicRing = ProviderHelper.getPGPPublicKeyRing(this, pubKeyId); + PGPPublicKey publicKey = publicRing.getPublicKey(pubKeyId); + PGPSecretKey certificationKey = PgpKeyHelper.getCertificationKey(this, + masterKeyId); + publicKey = keyOperation.certifyKey(certificationKey, publicKey, + userIds, signaturePassphrase); + publicRing = PGPPublicKeyRing.insertPublicKey(publicRing, publicKey); // store the signed key in our local cache PgpImportExport pgpImportExport = new PgpImportExport(this, null); - int retval = pgpImportExport.storeKeyRingInCache(signedPubKeyRing); + int retval = pgpImportExport.storeKeyRingInCache(publicRing); if (retval != Id.return_value.ok && retval != Id.return_value.updated) { throw new PgpGeneralException("Failed to store signed key in local cache"); } @@ -835,6 +830,10 @@ public class KeychainIntentService extends IntentService if (this.mIsCanceled) { return; } + // contextualize the exception, if necessary + if (e instanceof PgpGeneralMsgIdException) { + e = ((PgpGeneralMsgIdException) e).getContextualized(this); + } Log.e(Constants.TAG, "ApgService Exception: ", e); e.printStackTrace(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index 176d09c1a..962b304c7 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -24,19 +24,29 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.os.*; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.support.v4.util.LongSparseArray; import android.util.Log; -import android.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.Id; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import java.util.Date; @@ -86,7 +96,7 @@ public class PassphraseCacheService extends Service { Intent intent = new Intent(context, PassphraseCacheService.class); intent.setAction(ACTION_PASSPHRASE_CACHE_ADD); - intent.putExtra(EXTRA_TTL, Preferences.getPreferences(context).getPassPhraseCacheTtl()); + intent.putExtra(EXTRA_TTL, Preferences.getPreferences(context).getPassphraseCacheTtl()); intent.putExtra(EXTRA_PASSPHRASE, passphrase); intent.putExtra(EXTRA_KEY_ID, keyId); @@ -161,15 +171,11 @@ public class PassphraseCacheService extends Service { // try to get master key id which is used as an identifier for cached passphrases long masterKeyId = keyId; if (masterKeyId != Id.key.symmetric) { - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(this, keyId); - if (keyRing == null) { + masterKeyId = ProviderHelper.getMasterKeyId(this, + KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId))); + // Failure + if(masterKeyId == 0) return null; - } - PGPSecretKey masterKey = PgpKeyHelper.getMasterKey(keyRing); - if (masterKey == null) { - return null; - } - masterKeyId = masterKey.getKeyID(); } Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + masterKeyId); @@ -202,8 +208,7 @@ public class PassphraseCacheService extends Service { public static boolean hasPassphrase(Context context, long secretKeyId) { // check if the key has no passphrase try { - PGPSecretKeyRing secRing = ProviderHelper - .getPGPSecretKeyRingByKeyId(context, secretKeyId); + PGPSecretKeyRing secRing = ProviderHelper.getPGPSecretKeyRing(context, secretKeyId); PGPSecretKey secretKey = null; boolean foundValidKey = false; for (Iterator keys = secRing.getSecretKeys(); keys.hasNext(); ) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java new file mode 100644 index 000000000..7c2dcf2c1 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -0,0 +1,107 @@ +/* + * 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.spongycastle.openpgp.PGPSecretKey; +import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; + +import java.util.ArrayList; +import java.util.GregorianCalendar; + +public class SaveKeyringParcel 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<PGPSecretKey> deletedKeys; + public ArrayList<GregorianCalendar> 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); + } + keysExpiryDates = (ArrayList<GregorianCalendar>) 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); + 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); + } + + public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() { + public SaveKeyringParcel createFromParcel(final Parcel source) { + return new SaveKeyringParcel(source); + } + + public SaveKeyringParcel[] newArray(final int size) { + return new SaveKeyringParcel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettings.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettings.java deleted file mode 100644 index 6f2d67efb..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettings.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2013 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.remote; - -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.openpgp.PGPEncryptedData; -import org.sufficientlysecure.keychain.Id; - -public class AppSettings { - private String mPackageName; - private byte[] mPackageSignature; - private long mKeyId = Id.key.none; - private int mEncryptionAlgorithm; - private int mHashAlgorithm; - private int mCompression; - - public AppSettings() { - - } - - public AppSettings(String packageName, byte[] packageSignature) { - super(); - this.mPackageName = packageName; - this.mPackageSignature = packageSignature; - // defaults: - this.mEncryptionAlgorithm = PGPEncryptedData.AES_256; - this.mHashAlgorithm = HashAlgorithmTags.SHA512; - this.mCompression = Id.choice.compression.zlib; - } - - public String getPackageName() { - return mPackageName; - } - - public void setPackageName(String packageName) { - this.mPackageName = packageName; - } - - public byte[] getPackageSignature() { - return mPackageSignature; - } - - public void setPackageSignature(byte[] packageSignature) { - this.mPackageSignature = packageSignature; - } - - public long getKeyId() { - return mKeyId; - } - - public void setKeyId(long scretKeyId) { - this.mKeyId = scretKeyId; - } - - public int getEncryptionAlgorithm() { - return mEncryptionAlgorithm; - } - - public void setEncryptionAlgorithm(int encryptionAlgorithm) { - this.mEncryptionAlgorithm = encryptionAlgorithm; - } - - public int getHashAlgorithm() { - return mHashAlgorithm; - } - - public void setHashAlgorithm(int hashAlgorithm) { - this.mHashAlgorithm = hashAlgorithm; - } - - public int getCompression() { - return mCompression; - } - - public void setCompression(int compression) { - this.mCompression = compression; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java deleted file mode 100644 index 2ef170dec..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsActivity.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2013 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.remote; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; - -public class AppSettingsActivity extends ActionBarActivity { - private Uri mAppUri; - - private AppSettingsFragment mSettingsFragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // "Done" - save(); - } - }); - - setContentView(R.layout.api_app_settings_activity); - - mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_app_settings_fragment); - - Intent intent = getIntent(); - mAppUri = intent.getData(); - if (mAppUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!"); - finish(); - return; - } else { - Log.d(Constants.TAG, "uri: " + mAppUri); - loadData(mAppUri); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.api_app_settings, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_api_settings_revoke: - revokeAccess(); - return true; - case R.id.menu_api_settings_cancel: - finish(); - return true; - } - return super.onOptionsItemSelected(item); - } - - private void loadData(Uri appUri) { - AppSettings settings = ProviderHelper.getApiAppSettings(this, appUri); - mSettingsFragment.setAppSettings(settings); - } - - private void revokeAccess() { - if (getContentResolver().delete(mAppUri, null, null) <= 0) { - throw new RuntimeException(); - } - finish(); - } - - private void save() { - ProviderHelper.updateApiApp(this, mSettingsFragment.getAppSettings(), mAppUri); - - finish(); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java deleted file mode 100644 index 837295018..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2013-2014 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.remote; - -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.widget.*; -import android.widget.AdapterView.OnItemSelectedListener; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment; -import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter; -import org.sufficientlysecure.keychain.util.AlgorithmNames; -import org.sufficientlysecure.keychain.util.Log; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class AppSettingsFragment extends Fragment implements - SelectSecretKeyLayoutFragment.SelectSecretKeyCallback { - - // model - private AppSettings mAppSettings; - - // view - private LinearLayout mAdvancedSettingsContainer; - private BootstrapButton mAdvancedSettingsButton; - private TextView mAppNameView; - private ImageView mAppIconView; - private Spinner mEncryptionAlgorithm; - private Spinner mHashAlgorithm; - private Spinner mCompression; - private TextView mPackageName; - private TextView mPackageSignature; - - private SelectSecretKeyLayoutFragment mSelectKeyFragment; - - KeyValueSpinnerAdapter mEncryptionAdapter; - KeyValueSpinnerAdapter mHashAdapter; - KeyValueSpinnerAdapter mCompressionAdapter; - - public AppSettings getAppSettings() { - return mAppSettings; - } - - public void setAppSettings(AppSettings appSettings) { - this.mAppSettings = appSettings; - setPackage(appSettings.getPackageName()); - mPackageName.setText(appSettings.getPackageName()); - - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(appSettings.getPackageSignature()); - byte[] digest = md.digest(); - String signature = new String(Hex.encode(digest)); - - mPackageSignature.setText(signature); - } catch (NoSuchAlgorithmException e) { - Log.e(Constants.TAG, "Should not happen!", e); - } - - mSelectKeyFragment.selectKey(appSettings.getKeyId()); - mEncryptionAlgorithm.setSelection(mEncryptionAdapter.getPosition(appSettings - .getEncryptionAlgorithm())); - mHashAlgorithm.setSelection(mHashAdapter.getPosition(appSettings.getHashAlgorithm())); - mCompression.setSelection(mCompressionAdapter.getPosition(appSettings.getCompression())); - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.api_app_settings_fragment, container, false); - initView(view); - return view; - } - - /** - * Set error String on key selection - * - * @param error - */ - public void setErrorOnSelectKeyFragment(String error) { - mSelectKeyFragment.setError(error); - } - - private void initView(View view) { - mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getFragmentManager().findFragmentById( - R.id.api_app_settings_select_key_fragment); - mSelectKeyFragment.setCallback(this); - - mAdvancedSettingsButton = (BootstrapButton) view - .findViewById(R.id.api_app_settings_advanced_button); - mAdvancedSettingsContainer = (LinearLayout) view - .findViewById(R.id.api_app_settings_advanced); - - mAppNameView = (TextView) view.findViewById(R.id.api_app_settings_app_name); - mAppIconView = (ImageView) view.findViewById(R.id.api_app_settings_app_icon); - mEncryptionAlgorithm = (Spinner) view - .findViewById(R.id.api_app_settings_encryption_algorithm); - mHashAlgorithm = (Spinner) view.findViewById(R.id.api_app_settings_hash_algorithm); - mCompression = (Spinner) view.findViewById(R.id.api_app_settings_compression); - mPackageName = (TextView) view.findViewById(R.id.api_app_settings_package_name); - mPackageSignature = (TextView) view.findViewById(R.id.api_app_settings_package_signature); - - AlgorithmNames algorithmNames = new AlgorithmNames(getActivity()); - - mEncryptionAdapter = new KeyValueSpinnerAdapter(getActivity(), - algorithmNames.getEncryptionNames()); - mEncryptionAlgorithm.setAdapter(mEncryptionAdapter); - mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - mAppSettings.setEncryptionAlgorithm((int) id); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - } - }); - - mHashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames()); - mHashAlgorithm.setAdapter(mHashAdapter); - mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - mAppSettings.setHashAlgorithm((int) id); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - } - }); - - mCompressionAdapter = new KeyValueSpinnerAdapter(getActivity(), - algorithmNames.getCompressionNames()); - mCompression.setAdapter(mCompressionAdapter); - mCompression.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - mAppSettings.setCompression((int) id); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - } - }); - - final Animation visibleAnimation = new AlphaAnimation(0.0f, 1.0f); - visibleAnimation.setDuration(250); - final Animation invisibleAnimation = new AlphaAnimation(1.0f, 0.0f); - invisibleAnimation.setDuration(250); - - // TODO: Better: collapse/expand animation - // final Animation animation2 = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, - // Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f, - // Animation.RELATIVE_TO_SELF, 0.0f);u - // animation2.setDuration(150); - - mAdvancedSettingsButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (mAdvancedSettingsContainer.getVisibility() == View.VISIBLE) { - mAdvancedSettingsContainer.startAnimation(invisibleAnimation); - mAdvancedSettingsContainer.setVisibility(View.GONE); - mAdvancedSettingsButton.setText(getString(R.string.api_settings_show_advanced)); - mAdvancedSettingsButton.setLeftIcon("fa-caret-up"); - } else { - mAdvancedSettingsContainer.startAnimation(visibleAnimation); - mAdvancedSettingsContainer.setVisibility(View.VISIBLE); - mAdvancedSettingsButton.setText(getString(R.string.api_settings_hide_advanced)); - mAdvancedSettingsButton.setLeftIcon("fa-caret-down"); - } - } - }); - } - - private void setPackage(String packageName) { - PackageManager pm = getActivity().getApplicationContext().getPackageManager(); - - // get application name and icon from package manager - String appName = null; - Drawable appIcon = null; - try { - ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); - - appName = (String) pm.getApplicationLabel(ai); - appIcon = pm.getApplicationIcon(ai); - } catch (final NameNotFoundException e) { - // fallback - appName = packageName; - } - mAppNameView.setText(appName); - mAppIconView.setImageDrawable(appIcon); - } - - /** - * callback from select secret key fragment - */ - @Override - public void onKeySelected(long secretKeyId) { - mAppSettings.setKeyId(secretKeyId); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java deleted file mode 100644 index 95dc897f0..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (C) 2013-2014 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.remote; - -import android.app.PendingIntent; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import org.openintents.openpgp.IOpenPgpService; -import org.openintents.openpgp.OpenPgpError; -import org.openintents.openpgp.OpenPgpSignatureResult; -import org.openintents.openpgp.util.OpenPgpApi; -import org.spongycastle.util.Arrays; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; -import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; - -public class OpenPgpService extends RemoteService { - - private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551; - private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552; - private static final int PRIVATE_REQUEST_CODE_GET_KEYS = 553; - - /** - * Search database for key ids based on emails. - * - * @param encryptionUserIds - * @return - */ - private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) { - // find key ids to given emails in database - ArrayList<Long> keyIds = new ArrayList<Long>(); - - boolean missingUserIdsCheck = false; - boolean dublicateUserIdsCheck = false; - ArrayList<String> missingUserIds = new ArrayList<String>(); - ArrayList<String> dublicateUserIds = new ArrayList<String>(); - - for (String email : encryptionUserIds) { - Uri uri = KeychainContract.KeyRings.buildPublicKeyRingsByEmailsUri(email); - Cursor cur = getContentResolver().query(uri, null, null, null, null); - if (cur.moveToFirst()) { - long id = cur.getLong(cur.getColumnIndex(KeychainContract.KeyRings.MASTER_KEY_ID)); - keyIds.add(id); - } else { - missingUserIdsCheck = true; - missingUserIds.add(email); - Log.d(Constants.TAG, "user id missing"); - } - if (cur.moveToNext()) { - dublicateUserIdsCheck = true; - dublicateUserIds.add(email); - Log.d(Constants.TAG, "more than one user id with the same email"); - } - } - - // convert to long[] - long[] keyIdsArray = new long[keyIds.size()]; - for (int i = 0; i < keyIdsArray.length; i++) { - keyIdsArray[i] = keyIds.get(i); - } - - // allow the user to verify pub key selection - if (missingUserIdsCheck || dublicateUserIdsCheck) { - // build PendingIntent - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS); - intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); - intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); - intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity - (getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } - - if (keyIdsArray.length == 0) { - return null; - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keyIdsArray); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } - - private Intent getPassphraseBundleIntent(Intent data, long keyId) { - // build PendingIntent for passphrase input - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE); - intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId); - // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - PendingIntent pi = PendingIntent.getActivity - (getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } - - private Intent signImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AppSettings appSettings) { - try { - boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); - - // get passphrase from cache, if key has "no" passphrase, this returns an empty String - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId()); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId()); - return passphraseBundle; - } - - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - try { - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - // sign-only - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os); - builder.enableAsciiArmorOutput(asciiArmor) - .signatureHashAlgorithm(appSettings.getHashAlgorithm()) - .signatureForceV3(false) - .signatureKeyId(appSettings.getKeyId()) - .signaturePassphrase(passphrase); - builder.build().execute(); - } finally { - is.close(); - os.close(); - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AppSettings appSettings, boolean sign) { - try { - boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); - - long[] keyIds; - if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) { - keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); - } else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) { - // get key ids based on given user ids - String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); - // give params through to activity... - Intent result = getKeyIdsFromEmails(data, userIds); - - if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) { - keyIds = result.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); - } else { - // if not success -> result contains a PendingIntent for user interaction - return result; - } - } else { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, - "Missing parameter user_ids or key_ids!")); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // add own key for encryption - keyIds = Arrays.copyOf(keyIds, keyIds.length + 1); - keyIds[keyIds.length - 1] = appSettings.getKeyId(); - - // build InputData and write into OutputStream - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - try { - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os); - builder.enableAsciiArmorOutput(asciiArmor) - .compressionId(appSettings.getCompression()) - .symmetricEncryptionAlgorithm(appSettings.getEncryptionAlgorithm()) - .encryptionKeyIds(keyIds); - - if (sign) { - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), - appSettings.getKeyId()); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId()); - return passphraseBundle; - } - - // sign and encrypt - builder.signatureHashAlgorithm(appSettings.getHashAlgorithm()) - .signatureForceV3(false) - .signatureKeyId(appSettings.getKeyId()) - .signaturePassphrase(passphrase); - } else { - // encrypt only - builder.signatureKeyId(Id.key.none); - } - // execute PGP operation! - builder.build().execute(); - } finally { - is.close(); - os.close(); - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AppSettings appSettings) { - try { - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - - Intent result = new Intent(); - try { - - String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os); - builder.assumeSymmetric(false) // no support for symmetric encryption - // allow only the private key for this app for decryption - .enforcedKeyId(appSettings.getKeyId()) - .passphrase(passphrase); - - // TODO: currently does not support binary signed-only content - PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); - - if (decryptVerifyResult.isKeyPassphraseNeeded()) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId()); - return passphraseBundle; - } else if (decryptVerifyResult.isSymmetricPassphraseNeeded()) { - throw new PgpGeneralException("Decryption of symmetric content not supported by API!"); - } - - OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); - if (signatureResult != null) { - if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY) { - // If signature is unknown we return an _additional_ PendingIntent - // to retrieve the missing key - // TODO!!! - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); - intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo"); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), - PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0); - - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - } - - result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); - } - - } finally { - is.close(); - os.close(); - } - - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent getKeyImpl(Intent data) { - try { - long keyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0); - - if (ProviderHelper.getPGPPublicKeyByKeyId(this, keyId) == null) { - Intent result = new Intent(); - - // If keys are not in db we return an additional PendingIntent - // to retrieve the missing key - // TODO!!! - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); - intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo"); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), - PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0); - - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } else { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent getKeyIdsImpl(Intent data) { - // get key ids based on given user ids - String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); - Intent result = getKeyIdsFromEmails(data, userIds); - return result; - } - - /** - * Check requirements: - * - params != null - * - has supported API version - * - is allowed to call the service (access has been granted) - * - * @param data - * @return null if everything is okay, or a Bundle with an error/PendingIntent - */ - private Intent checkRequirements(Intent data) { - // params Bundle is required! - if (data == null) { - Intent result = new Intent(); - OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!"); - result.putExtra(OpenPgpApi.RESULT_ERROR, error); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // version code is required and needs to correspond to version code of service! - if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) { - Intent result = new Intent(); - OpenPgpError error = new OpenPgpError - (OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); - result.putExtra(OpenPgpApi.RESULT_ERROR, error); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // check if caller is allowed to access openpgp keychain - Intent result = isAllowed(data); - if (result != null) { - return result; - } - - return null; - } - - // TODO: multi-threading - private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() { - - @Override - public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) { - Intent errorResult = checkRequirements(data); - if (errorResult != null) { - return errorResult; - } - - final AppSettings appSettings = getAppSettings(); - - String action = data.getAction(); - if (OpenPgpApi.ACTION_SIGN.equals(action)) { - return signImpl(data, input, output, appSettings); - } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, appSettings, false); - } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, appSettings, true); - } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { - return decryptAndVerifyImpl(data, input, output, appSettings); - } else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) { - return getKeyImpl(data); - } else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) { - return getKeyIdsImpl(data); - } else { - return null; - } - } - - }; - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsAdapter.java deleted file mode 100644 index e0dc4162f..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsAdapter.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2013 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.remote; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.database.Cursor; -import android.support.v4.widget.CursorAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; - -public class RegisteredAppsAdapter extends CursorAdapter { - - private LayoutInflater mInflater; - private PackageManager mPM; - - public RegisteredAppsAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - mPM = context.getApplicationContext().getPackageManager(); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - TextView text = (TextView) view.findViewById(R.id.api_apps_adapter_item_name); - ImageView icon = (ImageView) view.findViewById(R.id.api_apps_adapter_item_icon); - - String packageName = cursor.getString(cursor.getColumnIndex(ApiApps.PACKAGE_NAME)); - if (packageName != null) { - // get application name - try { - ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0); - - text.setText(mPM.getApplicationLabel(ai)); - icon.setImageDrawable(mPM.getApplicationIcon(ai)); - } catch (final NameNotFoundException e) { - // fallback - text.setText(packageName); - } - } else { - // fallback - text.setText(packageName); - } - - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.api_apps_adapter_list_item, null); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java deleted file mode 100644 index f6f216efd..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListActivity.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2013 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.remote; - -import android.os.Bundle; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.DrawerActivity; - -public class RegisteredAppsListActivity extends DrawerActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.api_apps_list_activity); - - setupDrawerNavigation(savedInstanceState); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java deleted file mode 100644 index 25d0c7593..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RegisteredAppsListFragment.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2013 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.remote; - -import android.content.ContentUris; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.ListFragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; - -public class RegisteredAppsListFragment extends ListFragment implements - LoaderManager.LoaderCallbacks<Cursor> { - - // This is the Adapter being used to display the list's data. - RegisteredAppsAdapter mAdapter; - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - getListView().setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { - // edit app settings - Intent intent = new Intent(getActivity(), AppSettingsActivity.class); - intent.setData(ContentUris.withAppendedId(KeychainContract.ApiApps.CONTENT_URI, id)); - startActivity(intent); - } - }); - - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText(getString(R.string.api_no_apps)); - - // We have a menu item to show in action bar. - setHasOptionsMenu(true); - - // Create an empty adapter we will use to display the loaded data. - mAdapter = new RegisteredAppsAdapter(getActivity(), null, 0); - setListAdapter(mAdapter); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getLoaderManager().initLoader(0, null, this); - } - - // These are the Contacts rows that we will retrieve. - static final String[] PROJECTION = new String[]{ApiApps._ID, ApiApps.PACKAGE_NAME}; - - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - // This is called when a new Loader needs to be created. This - // sample only has one Loader, so we don't care about the ID. - // First, pick the base URI to use depending on whether we are - // currently filtering. - Uri baseUri = ApiApps.CONTENT_URI; - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, - ApiApps.PACKAGE_NAME + " COLLATE LOCALIZED ASC"); - } - - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.swapCursor(data); - } - - public void onLoaderReset(Loader<Cursor> loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java deleted file mode 100644 index 6a883316a..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2013-2014 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.remote; - -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.Signature; -import android.net.Uri; -import android.os.Binder; -import org.openintents.openpgp.OpenPgpError; -import org.openintents.openpgp.util.OpenPgpApi; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Abstract service class for remote APIs that handle app registration and user input. - */ -public abstract class RemoteService extends Service { - Context mContext; - - private static final int PRIVATE_REQUEST_CODE_REGISTER = 651; - private static final int PRIVATE_REQUEST_CODE_ERROR = 652; - - - public Context getContext() { - return mContext; - } - - protected Intent isAllowed(Intent data) { - try { - if (isCallerAllowed(false)) { - - return null; - } else { - String[] callingPackages = getPackageManager().getPackagesForUid( - Binder.getCallingUid()); - // TODO: currently simply uses first entry - String packageName = callingPackages[0]; - - byte[] packageSignature; - try { - packageSignature = getPackageSignature(packageName); - } catch (NameNotFoundException e) { - Log.e(Constants.TAG, "Should not happen, returning!", e); - // return error - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - return result; - } - Log.e(Constants.TAG, "Not allowed to use service! return PendingIntent for registration!"); - - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_REGISTER); - intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); - intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), - PRIVATE_REQUEST_CODE_REGISTER, intent, 0); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - - return result; - } - } catch (WrongPackageSignatureException e) { - Log.e(Constants.TAG, "wrong signature!", e); - - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); - intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, - getString(R.string.api_error_wrong_signature)); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), - PRIVATE_REQUEST_CODE_ERROR, intent, 0); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - - return result; - } - } - - private byte[] getPackageSignature(String packageName) throws NameNotFoundException { - PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName, - PackageManager.GET_SIGNATURES); - Signature[] signatures = pkgInfo.signatures; - // TODO: Only first signature?! - byte[] packageSignature = signatures[0].toByteArray(); - - return packageSignature; - } - - /** - * Retrieves AppSettings from database for the application calling this remote service - * - * @return - */ - protected AppSettings getAppSettings() { - String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); - - // get app settings for this package - for (int i = 0; i < callingPackages.length; i++) { - String currentPkg = callingPackages[i]; - - Uri uri = KeychainContract.ApiApps.buildByPackageNameUri(currentPkg); - - AppSettings settings = ProviderHelper.getApiAppSettings(this, uri); - - if (settings != null) { - return settings; - } - } - - return null; - } - - /** - * Checks if process that binds to this service (i.e. the package name corresponding to the - * process) is in the list of allowed package names. - * - * @param allowOnlySelf allow only Keychain app itself - * @return true if process is allowed to use this service - * @throws WrongPackageSignatureException - */ - private boolean isCallerAllowed(boolean allowOnlySelf) throws WrongPackageSignatureException { - return isUidAllowed(Binder.getCallingUid(), allowOnlySelf); - } - - private boolean isUidAllowed(int uid, boolean allowOnlySelf) - throws WrongPackageSignatureException { - if (android.os.Process.myUid() == uid) { - return true; - } - if (allowOnlySelf) { // barrier - return false; - } - - String[] callingPackages = getPackageManager().getPackagesForUid(uid); - - // is calling package allowed to use this service? - for (int i = 0; i < callingPackages.length; i++) { - String currentPkg = callingPackages[i]; - - if (isPackageAllowed(currentPkg)) { - return true; - } - } - - Log.d(Constants.TAG, "Caller is NOT allowed!"); - return false; - } - - /** - * Checks if packageName is a registered app for the API. Does not return true for own package! - * - * @param packageName - * @return - * @throws WrongPackageSignatureException - */ - private boolean isPackageAllowed(String packageName) throws WrongPackageSignatureException { - Log.d(Constants.TAG, "packageName: " + packageName); - - ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(this); - Log.d(Constants.TAG, "allowed: " + allowedPkgs); - - // check if package is allowed to use our service - if (allowedPkgs.contains(packageName)) { - Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); - - // check package signature - byte[] currentSig; - try { - currentSig = getPackageSignature(packageName); - } catch (NameNotFoundException e) { - throw new WrongPackageSignatureException(e.getMessage()); - } - - byte[] storedSig = ProviderHelper.getApiAppSignature(this, packageName); - if (Arrays.equals(currentSig, storedSig)) { - Log.d(Constants.TAG, - "Package signature is correct! (equals signature from database)"); - return true; - } else { - throw new WrongPackageSignatureException( - "PACKAGE NOT ALLOWED! Signature wrong! (Signature not equals signature from database)"); - } - } - - return false; - } - - @Override - public void onCreate() { - super.onCreate(); - mContext = this; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java deleted file mode 100644 index e20114853..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2013-2014 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.remote; - -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.support.v7.app.ActionBarActivity; -import android.view.View; -import org.openintents.openpgp.util.OpenPgpApi; -import org.sufficientlysecure.htmltextview.HtmlTextView; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; - -public class RemoteServiceActivity extends ActionBarActivity { - - public static final String ACTION_REGISTER = Constants.INTENT_PREFIX + "API_ACTIVITY_REGISTER"; - public static final String ACTION_CACHE_PASSPHRASE = Constants.INTENT_PREFIX - + "API_ACTIVITY_CACHE_PASSPHRASE"; - public static final String ACTION_SELECT_PUB_KEYS = Constants.INTENT_PREFIX - + "API_ACTIVITY_SELECT_PUB_KEYS"; - public static final String ACTION_ERROR_MESSAGE = Constants.INTENT_PREFIX - + "API_ACTIVITY_ERROR_MESSAGE"; - - public static final String EXTRA_MESSENGER = "messenger"; - - public static final String EXTRA_DATA = "data"; - - // passphrase action - public static final String EXTRA_SECRET_KEY_ID = "secret_key_id"; - // register action - public static final String EXTRA_PACKAGE_NAME = "package_name"; - public static final String EXTRA_PACKAGE_SIGNATURE = "package_signature"; - // select pub keys action - public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids"; - public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids"; - public static final String EXTRA_DUBLICATE_USER_IDS = "dublicate_user_ids"; - // error message - public static final String EXTRA_ERROR_MESSAGE = "error_message"; - - // register view - private AppSettingsFragment mSettingsFragment; - // select pub keys view - private SelectPublicKeyFragment mSelectFragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - handleActions(getIntent(), savedInstanceState); - } - - protected void handleActions(Intent intent, Bundle savedInstanceState) { - - String action = intent.getAction(); - final Bundle extras = intent.getExtras(); - - - if (ACTION_REGISTER.equals(action)) { - final String packageName = extras.getString(EXTRA_PACKAGE_NAME); - final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_register_allow, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Allow - - // user needs to select a key! - if (mSettingsFragment.getAppSettings().getKeyId() == Id.key.none) { - mSettingsFragment.setErrorOnSelectKeyFragment( - getString(R.string.api_register_error_select_key)); - } else { - ProviderHelper.insertApiApp(RemoteServiceActivity.this, - mSettingsFragment.getAppSettings()); - - // give data through for new service call - Intent resultData = extras.getParcelable(EXTRA_DATA); - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - } - }, R.string.api_register_disallow, R.drawable.ic_action_cancel, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Disallow - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } - } - ); - - setContentView(R.layout.api_app_register_activity); - - mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_app_settings_fragment); - - AppSettings settings = new AppSettings(packageName, packageSignature); - mSettingsFragment.setAppSettings(settings); - } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { - long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); - Intent resultData = extras.getParcelable(EXTRA_DATA); - - showPassphraseDialog(resultData, secretKeyId); - } else if (ACTION_SELECT_PUB_KEYS.equals(action)) { - long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); - ArrayList<String> missingUserIds = intent - .getStringArrayListExtra(EXTRA_MISSING_USER_IDS); - ArrayList<String> dublicateUserIds = intent - .getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS); - - // TODO: do this with spannable instead of HTML to prevent parsing failures with weird user ids - String text = "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>"; - text += "<br/><br/>"; - if (missingUserIds != null && missingUserIds.size() > 0) { - text += getString(R.string.api_select_pub_keys_missing_text); - text += "<br/>"; - text += "<ul>"; - for (String userId : missingUserIds) { - text += "<li>" + userId + "</li>"; - } - text += "</ul>"; - text += "<br/>"; - } - if (dublicateUserIds != null && dublicateUserIds.size() > 0) { - text += getString(R.string.api_select_pub_keys_dublicates_text); - text += "<br/>"; - text += "<ul>"; - for (String userId : dublicateUserIds) { - text += "<li>" + userId + "</li>"; - } - text += "</ul>"; - } - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // add key ids to params Bundle for new request - Intent resultData = extras.getParcelable(EXTRA_DATA); - resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS, - mSelectFragment.getSelectedMasterKeyIds()); - - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } - } - ); - - setContentView(R.layout.api_app_select_pub_keys_activity); - - // set text on view - HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_select_pub_keys_text); - textView.setHtmlFromString(text); - - /* Load select pub keys fragment */ - // Check that the activity is using the layout version with - // the fragment_container FrameLayout - if (findViewById(R.id.api_select_pub_keys_fragment_container) != null) { - - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } - - // Create an instance of the fragment - mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds); - - // Add the fragment to the 'fragment_container' FrameLayout - getSupportFragmentManager().beginTransaction() - .add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit(); - } - } else if (ACTION_ERROR_MESSAGE.equals(action)) { - String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE); - - String text = "<font color=\"red\">" + errorMessage + "</font>"; - - // Inflate a "Done" custom action bar view - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - - @Override - public void onClick(View v) { - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } - }); - - setContentView(R.layout.api_app_error_message); - - // set text on view - HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text); - textView.setHtmlFromString(text); - } else { - Log.e(Constants.TAG, "Action does not exist!"); - setResult(RESULT_CANCELED); - finish(); - } - } - - /** - * Shows passphrase dialog to cache a new passphrase the user enters for using it later for - * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks - * for a symmetric passphrase - */ - private void showPassphraseDialog(final Intent data, long secretKeyId) { - // Message is received after passphrase is cached - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - // return given params again, for calling the service method again - RemoteServiceActivity.this.setResult(RESULT_OK, data); - } else { - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - } - - RemoteServiceActivity.this.finish(); - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - try { - PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(this, - messenger, secretKeyId); - - passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog"); - } catch (PgpGeneralException e) { - Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!"); - // return given params again, for calling the service method again - setResult(RESULT_OK, data); - finish(); - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java deleted file mode 100644 index 0b642086a..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2013 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.remote; - -public class WrongPackageSignatureException extends Exception { - - private static final long serialVersionUID = -8294642703122196028L; - - public WrongPackageSignatureException(String message) { - super(message); - } -} |