aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java85
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java10
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java11
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java122
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java833
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java217
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java177
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java (renamed from OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java)2
11 files changed, 564 insertions, 923 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 5e5735c88..9e517b93e 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
@@ -43,10 +43,11 @@ import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
-import org.sufficientlysecure.keychain.pgp.PgpOperation;
+import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@@ -95,7 +96,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String ACTION_UPLOAD_KEYRING = Constants.INTENT_PREFIX + "UPLOAD_KEYRING";
public static final String ACTION_DOWNLOAD_AND_IMPORT_KEYS = Constants.INTENT_PREFIX + "QUERY_KEYRING";
- public static final String ACTION_SIGN_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING";
+ public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING";
/* keys for data bundle */
@@ -119,11 +120,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String ENCRYPT_PROVIDER_URI = "provider_uri";
// decrypt/verify
- public static final String DECRYPT_SIGNED_ONLY = "signed_only";
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_LOOKUP_UNKNOWN_KEY = "lookup_unknownKey";
// save keyring
public static final String SAVE_KEYRING_NEW_PASSPHRASE = "new_passphrase";
@@ -166,8 +165,8 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String DOWNLOAD_KEY_LIST = "query_key_id";
// sign key
- public static final String SIGN_KEY_MASTER_KEY_ID = "sign_key_master_key_id";
- public static final String SIGN_KEY_PUB_KEY_ID = "sign_key_pub_key_id";
+ public static final String CERTIFY_KEY_MASTER_KEY_ID = "sign_key_master_key_id";
+ public static final String CERTIFY_KEY_PUB_KEY_ID = "sign_key_pub_key_id";
/*
* possible data keys as result send over messenger
@@ -189,10 +188,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public static final String RESULT_SIGNATURE = "signature";
public static final String RESULT_SIGNATURE_KEY_ID = "signature_key_id";
public static final String RESULT_SIGNATURE_USER_ID = "signature_user_id";
+ public static final String RESULT_CLEARTEXT_SIGNATURE_ONLY = "signature_only";
public static final String RESULT_SIGNATURE_SUCCESS = "signature_success";
public static final String RESULT_SIGNATURE_UNKNOWN = "signature_unknown";
- public static final String RESULT_SIGNATURE_LOOKUP_KEY = "lookup_key";
// import
public static final String RESULT_IMPORT_ADDED = "added";
@@ -241,7 +240,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
String action = intent.getAction();
- // execute action from extra bundle
+ // executeServiceMethod action from extra bundle
if (ACTION_ENCRYPT_SIGN.equals(action)) {
try {
/* Input */
@@ -322,27 +321,41 @@ public class KeychainIntentService extends IntentService implements ProgressDial
}
/* Operation */
- PgpOperation operation = new PgpOperation(this, this, inputData, outStream);
+ PgpSignEncrypt.Builder builder =
+ new PgpSignEncrypt.Builder(this, inputData, outStream);
+ builder.progress(this);
+
if (generateSignature) {
Log.d(Constants.TAG, "generating signature...");
- operation.generateSignature(useAsciiArmor, false, secretKeyId,
- PassphraseCacheService.getCachedPassphrase(this, secretKeyId),
- Preferences.getPreferences(this).getDefaultHashAlgorithm(), Preferences
- .getPreferences(this).getForceV3Signatures());
+ 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...");
- operation.signText(secretKeyId, PassphraseCacheService.getCachedPassphrase(
- this, secretKeyId), Preferences.getPreferences(this)
- .getDefaultHashAlgorithm(), Preferences.getPreferences(this)
- .getForceV3Signatures());
+ 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...");
- operation.signAndEncrypt(useAsciiArmor, compressionId, encryptionKeyIds,
- encryptionPassphrase, Preferences.getPreferences(this)
- .getDefaultEncryptionAlgorithm(), secretKeyId, Preferences
- .getPreferences(this).getDefaultHashAlgorithm(), Preferences
- .getPreferences(this).getForceV3Signatures(),
- PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+ 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();
}
outStream.close();
@@ -395,12 +408,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
long secretKeyId = data.getLong(ENCRYPT_SECRET_KEY_ID);
byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES);
- boolean signedOnly = data.getBoolean(DECRYPT_SIGNED_ONLY);
boolean returnBytes = data.getBoolean(DECRYPT_RETURN_BYTES);
boolean assumeSymmetricEncryption = data.getBoolean(DECRYPT_ASSUME_SYMMETRIC);
- boolean lookupUnknownKey = data.getBoolean(DECRYPT_LOOKUP_UNKNOWN_KEY);
-
InputStream inStream = null;
long inLength = -1;
InputData inputData = null;
@@ -474,14 +484,13 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// verifyText and decrypt returning additional resultData values for the
// verification of signatures
- PgpOperation operation = new PgpOperation(this, this, inputData, outStream);
- if (signedOnly) {
- resultData = operation.verifyText(lookupUnknownKey);
- } else {
- resultData = operation.decryptAndVerify(
- PassphraseCacheService.getCachedPassphrase(this, secretKeyId),
- assumeSymmetricEncryption);
- }
+ PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
+ builder.progress(this);
+
+ builder.assumeSymmetric(assumeSymmetricEncryption)
+ .passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
+
+ resultData = builder.build().execute();
outStream.close();
@@ -785,19 +794,19 @@ public class KeychainIntentService extends IntentService implements ProgressDial
} catch (Exception e) {
sendErrorToHandler(e);
}
- } else if (ACTION_SIGN_KEYRING.equals(action)) {
+ } else if (ACTION_CERTIFY_KEYRING.equals(action)) {
try {
/* Input */
- long masterKeyId = data.getLong(SIGN_KEY_MASTER_KEY_ID);
- long pubKeyId = data.getLong(SIGN_KEY_PUB_KEY_ID);
+ long masterKeyId = data.getLong(CERTIFY_KEY_MASTER_KEY_ID);
+ long pubKeyId = data.getLong(CERTIFY_KEY_PUB_KEY_ID);
/* Operation */
String signaturePassPhrase = PassphraseCacheService.getCachedPassphrase(this,
masterKeyId);
PgpKeyOperation keyOperation = new PgpKeyOperation(this, this);
- PGPPublicKeyRing signedPubKeyRing = keyOperation.signKey(masterKeyId, pubKeyId,
+ PGPPublicKeyRing signedPubKeyRing = keyOperation.certifyKey(masterKeyId, pubKeyId,
signaturePassPhrase);
// store the signed key in our local cache
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
index 5a338c757..dfea7eb04 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
@@ -25,6 +25,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
import android.widget.Toast;
public class KeychainIntentServiceHandler extends Handler {
@@ -60,7 +61,14 @@ public class KeychainIntentServiceHandler extends Handler {
}
public void showProgressDialog(FragmentActivity activity) {
- mProgressDialogFragment.show(activity.getSupportFragmentManager(), "progressDialog");
+ // TODO: This is a hack!, see http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
+ final FragmentManager manager = activity.getSupportFragmentManager();
+ Handler handler = new Handler();
+ handler.post(new Runnable() {
+ public void run() {
+ mProgressDialogFragment.show(manager, "progressDialog");
+ }
+ });
}
@Override
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java
deleted file mode 100644
index 555303238..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.sufficientlysecure.keychain.service.exception;
-
-public class NoUserIdsException extends Exception {
-
- private static final long serialVersionUID = 7009311527126696207L;
-
- public NoUserIdsException(String message) {
- super(message);
- }
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java
deleted file mode 100644
index 1152d6796..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.sufficientlysecure.keychain.service.exception;
-
-public class UserInteractionRequiredException extends Exception {
-
- private static final long serialVersionUID = -60128148603511936L;
-
- public UserInteractionRequiredException(String message) {
- super(message);
- }
-} \ No newline at end of file
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java
deleted file mode 100644
index 14b774eb5..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.sufficientlysecure.keychain.service.exception;
-
-public class WrongPassphraseException extends Exception {
-
- private static final long serialVersionUID = -5309689232853485740L;
-
- public WrongPassphraseException(String message) {
- super(message);
- }
-} \ No newline at end of file
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
index 025929cfa..64c4c5e96 100644
--- 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
@@ -109,6 +109,15 @@ public class AppSettingsFragment extends Fragment implements
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);
@@ -182,7 +191,7 @@ public class AppSettingsFragment extends Fragment implements
// 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);
+ // Animation.RELATIVE_TO_SELF, 0.0f);u
// animation2.setDuration(150);
mAdvancedSettingsButton.setOnClickListener(new OnClickListener() {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java
deleted file mode 100644
index 427e6bb8f..000000000
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java
+++ /dev/null
@@ -1,122 +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 java.io.ByteArrayOutputStream;
-import java.io.PrintWriter;
-import java.security.cert.X509Certificate;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.PasswordCallback;
-
-import org.spongycastle.openpgp.PGPPrivateKey;
-import org.spongycastle.openpgp.PGPSecretKey;
-import org.spongycastle.openssl.PEMWriter;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.pgp.PgpToX509;
-import org.sufficientlysecure.keychain.util.Log;
-
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-public class ExtendedApiService extends RemoteService {
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- private void selfSignedX509CertSafe(String subjAltNameURI, IExtendedApiCallback callback,
- AppSettings appSettings) {
-
- // TODO: for pgp keyrings with password
- CallbackHandler pgpPwdCallbackHandler = new PgpToX509.PredefinedPasswordCallbackHandler("");
-
- try {
- long keyId = appSettings.getKeyId();
- PGPSecretKey pgpSecretKey = PgpKeyHelper.getSigningKey(this, keyId);
-
- PasswordCallback pgpSecKeyPasswordCallBack = new PasswordCallback("pgp passphrase?",
- false);
- pgpPwdCallbackHandler.handle(new Callback[] { pgpSecKeyPasswordCallBack });
- PGPPrivateKey pgpPrivKey = pgpSecretKey.extractPrivateKey(
- pgpSecKeyPasswordCallBack.getPassword(), Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- pgpSecKeyPasswordCallBack.clearPassword();
-
- X509Certificate selfSignedCert = PgpToX509.createSelfSignedCert(pgpSecretKey,
- pgpPrivKey, subjAltNameURI);
-
- // Write x509cert and privKey into files
- // FileOutputStream fosCert = context.openFileOutput(CERT_FILENAME,
- // Context.MODE_PRIVATE);
- ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- PEMWriter pemWriterCert = new PEMWriter(new PrintWriter(outStream));
- pemWriterCert.writeObject(selfSignedCert);
- pemWriterCert.close();
-
- byte[] outputBytes = outStream.toByteArray();
-
- callback.onSuccess(outputBytes);
- } catch (Exception e) {
- Log.e(Constants.TAG, "ExtendedApiService", e);
- try {
- callback.onError(e.getMessage());
- } catch (RemoteException e1) {
- Log.e(Constants.TAG, "ExtendedApiService", e);
- }
- }
-
- // TODO: no private key at the moment! Don't give it to others
- // PrivateKey privKey = pgpPrivKey.getKey();
- // FileOutputStream fosKey = context.openFileOutput(PRIV_KEY_FILENAME,
- // Context.MODE_PRIVATE);
- // PEMWriter pemWriterKey = new PEMWriter(new PrintWriter(fosKey));
- // pemWriterKey.writeObject(privKey);
- // pemWriterKey.close();
- }
-
- private final IExtendedApiService.Stub mBinder = new IExtendedApiService.Stub() {
-
- @Override
- public void encrypt(byte[] inputBytes, String passphrase, IExtendedApiCallback callback)
- throws RemoteException {
- // TODO : implement
-
- }
-
- @Override
- public void selfSignedX509Cert(final String subjAltNameURI,
- final IExtendedApiCallback callback) throws RemoteException {
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- selfSignedX509CertSafe(subjAltNameURI, callback, settings);
- }
- };
-
- checkAndEnqueue(r);
- }
-
- };
-
-}
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
index 575f76a22..34213bd3b 100644
--- 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
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * 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
@@ -17,108 +17,46 @@
package org.sufficientlysecure.keychain.service.remote;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.regex.Matcher;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
-import org.openintents.openpgp.IOpenPgpCallback;
-import org.openintents.openpgp.IOpenPgpKeyIdsCallback;
import org.openintents.openpgp.IOpenPgpService;
-import org.openintents.openpgp.OpenPgpData;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
+import org.openintents.openpgp.util.OpenPgpConstants;
import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.Preferences;
-import org.sufficientlysecure.keychain.pgp.PgpHelper;
-import org.sufficientlysecure.keychain.pgp.PgpOperation;
-import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
+import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.service.exception.NoUserIdsException;
-import org.sufficientlysecure.keychain.service.exception.UserInteractionRequiredException;
-import org.sufficientlysecure.keychain.service.exception.WrongPassphraseException;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
public class OpenPgpService extends RemoteService {
- private String getCachedPassphrase(long keyId, boolean allowUserInteraction)
- throws UserInteractionRequiredException {
- String passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), keyId);
-
- if (passphrase == null) {
- if (!allowUserInteraction) {
- throw new UserInteractionRequiredException(
- "Passphrase not found in cache, please enter your passphrase!");
- }
+ private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551;
+ private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552;
- Log.d(Constants.TAG, "No passphrase! Activity required!");
-
- // start passphrase dialog
- PassphraseActivityCallback callback = new PassphraseActivityCallback();
- Bundle extras = new Bundle();
- extras.putLong(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE, callback,
- extras);
-
- if (callback.isSuccess()) {
- Log.d(Constants.TAG, "New passphrase entered!");
-
- // get again after it was entered
- passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), keyId);
- } else {
- Log.d(Constants.TAG, "Passphrase dialog canceled!");
-
- return null;
- }
-
- }
-
- return passphrase;
- }
-
- public class PassphraseActivityCallback extends UserInputCallback {
-
- private boolean success = false;
-
- public boolean isSuccess() {
- return success;
- }
-
- @Override
- public void handleUserInput(Message msg) {
- if (msg.arg1 == OKAY) {
- success = true;
- } else {
- success = false;
- }
- }
- };
/**
* Search database for key ids based on emails.
- *
+ *
* @param encryptionUserIds
* @return
*/
- private long[] getKeyIdsFromEmails(String[] encryptionUserIds, boolean allowUserInteraction)
- throws UserInteractionRequiredException {
+ private Bundle getKeyIdsFromEmails(Bundle params, String[] encryptionUserIds) {
// find key ids to given emails in database
ArrayList<Long> keyIds = new ArrayList<Long>();
@@ -152,96 +90,129 @@ public class OpenPgpService extends RemoteService {
}
// allow the user to verify pub key selection
- if (allowUserInteraction && (missingUserIdsCheck || dublicateUserIdsCheck)) {
- SelectPubKeysActivityCallback callback = new SelectPubKeysActivityCallback();
-
- Bundle extras = new Bundle();
- extras.putLongArray(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
- extras.putStringArrayList(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
- extras.putStringArrayList(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS,
- dublicateUserIds);
-
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS, callback,
- extras);
-
- if (callback.isSuccess()) {
- Log.d(Constants.TAG, "New selection of pub keys!");
- keyIdsArray = callback.getPubKeyIds();
- } else {
- Log.d(Constants.TAG, "Pub key selection canceled!");
- return null;
- }
- }
-
- // if no user interaction is allow throw exceptions on duplicate or missing pub keys
- if (!allowUserInteraction) {
- if (missingUserIdsCheck)
- throw new UserInteractionRequiredException(
- "Pub keys for these user ids are missing:" + missingUserIds.toString());
- if (dublicateUserIdsCheck)
- throw new UserInteractionRequiredException(
- "More than one pub key with these user ids exist:"
- + dublicateUserIds.toString());
+ if (missingUserIdsCheck || dublicateUserIdsCheck) {
+ // build PendingIntent for passphrase input
+ 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(OpenPgpConstants.PI_RESULT_PARAMS, params);
+
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0);
+
+ // return PendingIntent to be executed by client
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
+
+ return result;
}
if (keyIdsArray.length == 0) {
return null;
}
- return keyIdsArray;
- }
-
- public class SelectPubKeysActivityCallback extends UserInputCallback {
- public static final String PUB_KEY_IDS = "pub_key_ids";
- private boolean success = false;
- private long[] pubKeyIds;
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
+ result.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, keyIdsArray);
+ return result;
+ }
- public boolean isSuccess() {
- return success;
- }
+ private Bundle getPassphraseBundleIntent(Bundle params, 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(OpenPgpConstants.PI_RESULT_PARAMS, params);
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
+
+ // return PendingIntent to be executed by client
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
+
+ return result;
+ }
- public long[] getPubKeyIds() {
- return pubKeyIds;
- }
+ private Bundle signImpl(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output,
+ AppSettings appSettings) {
+ try {
+ boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
- @Override
- public void handleUserInput(Message msg) {
- if (msg.arg1 == OKAY) {
- success = true;
- pubKeyIds = msg.getData().getLongArray(PUB_KEY_IDS);
+ // get passphrase from cache, if key has "no" passphrase, this returns an empty String
+ String passphrase;
+ if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
+ passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
} else {
- success = false;
+ passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
+ }
+ if (passphrase == null) {
+ // get PendingIntent for passphrase input, add it to given params and return to client
+ Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
+ return passphraseBundle;
}
- }
- };
- private synchronized void getKeyIdsSafe(String[] userIds, boolean allowUserInteraction,
- IOpenPgpKeyIdsCallback callback, AppSettings appSettings) {
- try {
- long[] keyIds = getKeyIdsFromEmails(userIds, allowUserInteraction);
- if (keyIds == null) {
- throw new NoUserIdsException("No user ids!");
+ // 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();
}
- callback.onSuccess(keyIds);
- } catch (UserInteractionRequiredException e) {
- callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());
- } catch (NoUserIdsException e) {
- callbackOpenPgpError(callback, OpenPgpError.NO_USER_IDS, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
+ return result;
} catch (Exception e) {
- callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
+ return result;
}
}
- private synchronized void encryptAndSignSafe(OpenPgpData inputData,
- final OpenPgpData outputData, long[] keyIds, boolean allowUserInteraction,
- IOpenPgpCallback callback, AppSettings appSettings, boolean sign) {
+ private Bundle encryptAndSignImpl(Bundle params, ParcelFileDescriptor input,
+ ParcelFileDescriptor output, AppSettings appSettings,
+ boolean sign) {
try {
- // TODO: other options of OpenPgpData!
- byte[] inputBytes = getInput(inputData);
- boolean asciiArmor = false;
- if (outputData.getType() == OpenPgpData.TYPE_STRING) {
- asciiArmor = true;
+ boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true);
+
+ long[] keyIds;
+ if (params.containsKey(OpenPgpConstants.PARAMS_KEY_IDS)) {
+ keyIds = params.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS);
+ } else if (params.containsKey(OpenPgpConstants.PARAMS_USER_IDS)) {
+ // get key ids based on given user ids
+ String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS);
+ // give params through to activity...
+ Bundle result = getKeyIdsFromEmails(params, userIds);
+
+ if (result.getInt(OpenPgpConstants.RESULT_CODE, 0) == OpenPgpConstants.RESULT_CODE_SUCCESS) {
+ keyIds = result.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS);
+ } else {
+ // if not success -> result contains a PendingIntent for user interaction
+ return result;
+ }
+ } else {
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!"));
+ return result;
}
// add own key for encryption
@@ -249,350 +220,338 @@ public class OpenPgpService extends RemoteService {
keyIds[keyIds.length - 1] = appSettings.getKeyId();
// build InputData and write into OutputStream
- InputStream inputStream = new ByteArrayInputStream(inputBytes);
- long inputLength = inputBytes.length;
- InputData inputDt = new InputData(inputStream, inputLength);
-
- OutputStream outputStream = new ByteArrayOutputStream();
+ // 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 (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
+ passphrase = params.getString(OpenPgpConstants.PARAMS_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
+ Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
+ return passphraseBundle;
+ }
- PgpOperation operation = new PgpOperation(getContext(), null, inputDt, outputStream);
- if (sign) {
- String passphrase = getCachedPassphrase(appSettings.getKeyId(),
- allowUserInteraction);
- if (passphrase == null) {
- throw new WrongPassphraseException("No or wrong passphrase!");
+ // sign and encrypt
+ builder.signatureHashAlgorithm(appSettings.getHashAlgorithm())
+ .signatureForceV3(false)
+ .signatureKeyId(appSettings.getKeyId())
+ .signaturePassphrase(passphrase);
+ } else {
+ // encrypt only
+ builder.signatureKeyId(Id.key.none);
}
-
- operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
- appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
- appSettings.getHashAlgorithm(), true, passphrase);
- } else {
- operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
- appSettings.getEncryptionAlgorithm(), Id.key.none,
- appSettings.getHashAlgorithm(), true, null);
+ // execute PGP operation!
+ builder.build().execute();
+ } finally {
+ is.close();
+ os.close();
}
- outputStream.close();
-
- byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
-
- OpenPgpData output = null;
- if (asciiArmor) {
- output = new OpenPgpData(new String(outputBytes));
- } else {
- output = new OpenPgpData(outputBytes);
- }
-
- // return over handler on client side
- callback.onSuccess(output, null);
- } catch (UserInteractionRequiredException e) {
- callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());
- } catch (WrongPassphraseException e) {
- callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage());
- } catch (Exception e) {
- callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage());
- }
- }
-
- // TODO: asciiArmor?!
- private void signSafe(byte[] inputBytes, boolean allowUserInteraction,
- IOpenPgpCallback callback, AppSettings appSettings) {
- try {
- // build InputData and write into OutputStream
- InputStream inputStream = new ByteArrayInputStream(inputBytes);
- long inputLength = inputBytes.length;
- InputData inputData = new InputData(inputStream, inputLength);
-
- OutputStream outputStream = new ByteArrayOutputStream();
-
- String passphrase = getCachedPassphrase(appSettings.getKeyId(), allowUserInteraction);
- if (passphrase == null) {
- throw new WrongPassphraseException("No or wrong passphrase!");
- }
-
- PgpOperation operation = new PgpOperation(getContext(), null, inputData, outputStream);
- operation.signText(appSettings.getKeyId(), passphrase, appSettings.getHashAlgorithm(),
- Preferences.getPreferences(this).getForceV3Signatures());
-
- outputStream.close();
-
- byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
- OpenPgpData output = new OpenPgpData(new String(outputBytes));
-
- // return over handler on client side
- callback.onSuccess(output, null);
- } catch (UserInteractionRequiredException e) {
- callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());
- } catch (WrongPassphraseException e) {
- callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
+ return result;
} catch (Exception e) {
- callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
+ return result;
}
}
- private synchronized void decryptAndVerifySafe(byte[] inputBytes, boolean allowUserInteraction,
- IOpenPgpCallback callback, AppSettings appSettings) {
+ private Bundle decryptAndVerifyImpl(Bundle params, ParcelFileDescriptor input,
+ ParcelFileDescriptor output, AppSettings appSettings) {
try {
- // TODO: this is not really needed
- // checked if it is text with BEGIN and END tags
- String message = new String(inputBytes);
- Log.d(Constants.TAG, "in: " + message);
- boolean signedOnly = false;
- Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message);
- if (matcher.matches()) {
- Log.d(Constants.TAG, "PGP_MESSAGE matched");
- message = matcher.group(1);
- // replace non breakable spaces
- message = message.replaceAll("\\xa0", " ");
-
- // overwrite inputBytes
- inputBytes = message.getBytes();
- } else {
- matcher = PgpHelper.PGP_SIGNED_MESSAGE.matcher(message);
- if (matcher.matches()) {
- signedOnly = true;
- Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched");
- message = matcher.group(1);
- // replace non breakable spaces
- message = message.replaceAll("\\xa0", " ");
-
- // overwrite inputBytes
- inputBytes = message.getBytes();
+ // Get Input- and OutputStream from ParcelFileDescriptor
+ InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
+ OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
+ OpenPgpSignatureResult sigResult = null;
+ try {
+
+// PGPUtil.getDecoderStream(is)
+ // TODOs API 2.0:
+ // implement verify-only!
+ // fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream
+ // should we allow to decrypt everything under every key id or only the one set?
+ // TODO: instead of trying to get the passphrase before
+ // pause stream when passphrase is missing and then resume
+
+
+ // TODO: this is not really needed
+ // checked if it is text with BEGIN and END tags
+// String message = new String(inputBytes);
+// Log.d(Constants.TAG, "in: " + message);
+// boolean signedOnly = false;
+// Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message);
+// if (matcher.matches()) {
+// Log.d(Constants.TAG, "PGP_MESSAGE matched");
+// message = matcher.group(1);
+// // replace non breakable spaces
+// message = message.replaceAll("\\xa0", " ");
+//
+// // overwrite inputBytes
+// inputBytes = message.getBytes();
+// } else {
+// matcher = PgpHelper.PGP_SIGNED_MESSAGE.matcher(message);
+// if (matcher.matches()) {
+// signedOnly = true;
+// Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched");
+// message = matcher.group(1);
+// // replace non breakable spaces
+// message = message.replaceAll("\\xa0", " ");
+//
+// // overwrite inputBytes
+// inputBytes = message.getBytes();
+// } else {
+// Log.d(Constants.TAG, "Nothing matched! Binary?");
+// }
+// }
+ // END TODO
+
+// Log.d(Constants.TAG, "in: " + new String(inputBytes));
+
+ // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
+ // app, Fix this?
+
+// String passphrase = null;
+// if (!signedOnly) {
+// // BEGIN Get key
+// // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it
+// // better!
+// InputStream inputStream2 = new ByteArrayInputStream(inputBytes);
+//
+// // TODO: duplicates functions from DecryptActivity!
+// long secretKeyId;
+// try {
+// if (inputStream2.markSupported()) {
+// // should probably set this to the max size of two
+// // pgpF objects, if it even needs to be anything other
+// // than 0.
+// inputStream2.mark(200);
+// }
+// secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2);
+// if (secretKeyId == Id.key.none) {
+// throw new PgpGeneralException(getString(R.string.error_no_secret_key_found));
+// }
+// } catch (NoAsymmetricEncryptionException e) {
+// if (inputStream2.markSupported()) {
+// inputStream2.reset();
+// }
+// secretKeyId = Id.key.symmetric;
+// if (!PgpDecryptVerify.hasSymmetricEncryption(this, inputStream2)) {
+// throw new PgpGeneralException(
+// getString(R.string.error_no_known_encryption_found));
+// }
+// // we do not support symmetric decryption from the API!
+// throw new Exception("Symmetric decryption is not supported!");
+// }
+//
+// Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
+
+ // NOTE: currently this only gets the passphrase for the key set for this client
+ String passphrase;
+ if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
+ passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
} else {
- Log.d(Constants.TAG, "Nothing matched! Binary?");
+ passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
}
- }
- // END TODO
-
- Log.d(Constants.TAG, "in: " + new String(inputBytes));
-
- // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
- // app, Fix this?
-
- String passphrase = null;
- if (!signedOnly) {
- // BEGIN Get key
- // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it
- // better!
- InputStream inputStream2 = new ByteArrayInputStream(inputBytes);
-
- // TODO: duplicates functions from DecryptActivity!
- long secretKeyId;
- try {
- if (inputStream2.markSupported()) {
- // should probably set this to the max size of two
- // pgpF objects, if it even needs to be anything other
- // than 0.
- inputStream2.mark(200);
- }
- secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2);
- if (secretKeyId == Id.key.none) {
- throw new PgpGeneralException(getString(R.string.error_no_secret_key_found));
- }
- } catch (NoAsymmetricEncryptionException e) {
- if (inputStream2.markSupported()) {
- inputStream2.reset();
- }
- secretKeyId = Id.key.symmetric;
- if (!PgpOperation.hasSymmetricEncryption(this, inputStream2)) {
- throw new PgpGeneralException(
- getString(R.string.error_no_known_encryption_found));
- }
- // we do not support symmetric decryption from the API!
- throw new Exception("Symmetric decryption is not supported!");
+ if (passphrase == null) {
+ // get PendingIntent for passphrase input, add it to given params and return to client
+ Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
+ return passphraseBundle;
}
+// }
- Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
+ // build InputData and write into OutputStream
+ long inputLength = is.available();
+ InputData inputData = new InputData(is, inputLength);
- passphrase = getCachedPassphrase(secretKeyId, allowUserInteraction);
- if (passphrase == null) {
- throw new WrongPassphraseException("No or wrong passphrase!");
- }
- }
- // build InputData and write into OutputStream
- InputStream inputStream = new ByteArrayInputStream(inputBytes);
- long inputLength = inputBytes.length;
- InputData inputData = new InputData(inputStream, inputLength);
+ Bundle outputBundle;
+ PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
- OutputStream outputStream = new ByteArrayOutputStream();
+// if (signedOnly) {
+// outputBundle = builder.build().verifyText();
+// } else {
+ builder.assumeSymmetric(false)
+ .passphrase(passphrase);
- Bundle outputBundle;
- PgpOperation operation = new PgpOperation(getContext(), null, inputData, outputStream);
- if (signedOnly) {
- // TODO: download missing keys from keyserver?
- outputBundle = operation.verifyText(false);
- } else {
- outputBundle = operation.decryptAndVerify(passphrase, false);
- }
+ // Do we want to do this: instead of trying to get the passphrase before
+ // pause stream when passphrase is missing and then resume???
- outputStream.close();
+ // TODO: this also decrypts with other secret keys without passphrase!!!
+ outputBundle = builder.build().execute();
+// }
- byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
+// outputStream.close();
- // get signature informations from bundle
- boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE);
+// byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
- OpenPgpSignatureResult sigResult = null;
- if (signature) {
- long signatureKeyId = outputBundle
- .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);
- String signatureUserId = outputBundle
- .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
- boolean signatureSuccess = outputBundle
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS);
- boolean signatureUnknown = outputBundle
- .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN);
-
- int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
- if (signatureSuccess) {
- signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_TRUSTED;
- } else if (signatureUnknown) {
- signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
- }
+ // get signature informations from bundle
+ boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE, false);
- sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId,
- signedOnly, signatureKeyId);
+ if (signature) {
+ long signatureKeyId = outputBundle
+ .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, 0);
+ String signatureUserId = outputBundle
+ .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
+ boolean signatureSuccess = outputBundle
+ .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
+ boolean signatureUnknown = outputBundle
+ .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, false);
+ boolean signatureOnly = outputBundle
+ .getBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false);
+
+ int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
+ if (signatureSuccess) {
+ signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED;
+ } else if (signatureUnknown) {
+ signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
+ }
+
+ sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId,
+ signatureOnly, signatureKeyId);
+ }
+ } finally {
+ is.close();
+ os.close();
}
- OpenPgpData output = new OpenPgpData(new String(outputBytes));
-
- // return over handler on client side
- callback.onSuccess(output, sigResult);
- } catch (UserInteractionRequiredException e) {
- callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage());
- } catch (WrongPassphraseException e) {
- callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage());
+
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS);
+ result.putParcelable(OpenPgpConstants.RESULT_SIGNATURE, sigResult);
+ return result;
} catch (Exception e) {
- callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage());
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
+ return result;
}
}
+ private Bundle getKeyIdsImpl(Bundle params) {
+ // get key ids based on given user ids
+ String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS);
+ Bundle result = getKeyIdsFromEmails(params, userIds);
+ return result;
+ }
+
/**
- * Returns error to IOpenPgpCallback
- *
- * @param callback
- * @param errorId
- * @param message
+ * Check requirements:
+ * - params != null
+ * - has supported API version
+ * - is allowed to call the service (access has been granted)
+ *
+ * @param params
+ * @return null if everything is okay, or a Bundle with an error/PendingIntent
*/
- private void callbackOpenPgpError(IOpenPgpCallback callback, int errorId, String message) {
- try {
- callback.onError(new OpenPgpError(0, message));
- } catch (Exception t) {
- Log.e(Constants.TAG,
- "Exception while returning OpenPgpError to client via callback.onError()", t);
+ private Bundle checkRequirements(Bundle params) {
+ // params Bundle is required!
+ if (params == null) {
+ Bundle result = new Bundle();
+ OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!");
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error);
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ return result;
}
- }
- private void callbackOpenPgpError(IOpenPgpKeyIdsCallback callback, int errorId, String message) {
- try {
- callback.onError(new OpenPgpError(0, message));
- } catch (Exception t) {
- Log.e(Constants.TAG,
- "Exception while returning OpenPgpError to client via callback.onError()", t);
+ // version code is required and needs to correspond to version code of service!
+ if (params.getInt(OpenPgpConstants.PARAMS_API_VERSION) != OpenPgpConstants.API_VERSION) {
+ Bundle result = new Bundle();
+ OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error);
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ return result;
}
+
+ // check if caller is allowed to access openpgp keychain
+ Bundle result = isAllowed(params);
+ if (result != null) {
+ return result;
+ }
+
+ return null;
}
+ // TODO: multi-threading
private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() {
@Override
- public void encrypt(final OpenPgpData input, final OpenPgpData output, final long[] keyIds,
- final IOpenPgpCallback callback) throws RemoteException {
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- encryptAndSignSafe(input, output, keyIds, true, callback, settings, false);
- }
- };
-
- checkAndEnqueue(r);
- }
+ public Bundle sign(Bundle params, final ParcelFileDescriptor input, final ParcelFileDescriptor output) {
+ final AppSettings appSettings = getAppSettings();
- @Override
- public void signAndEncrypt(final OpenPgpData input, final OpenPgpData output,
- final long[] keyIds, final IOpenPgpCallback callback) throws RemoteException {
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- encryptAndSignSafe(input, output, keyIds, true, callback, settings, true);
- }
- };
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- checkAndEnqueue(r);
+ return signImpl(params, input, output, appSettings);
}
@Override
- public void sign(final OpenPgpData input, final OpenPgpData output,
- final IOpenPgpCallback callback) throws RemoteException {
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- signSafe(getInput(input), true, callback, settings);
- }
- };
+ public Bundle encrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
+ final AppSettings appSettings = getAppSettings();
+
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- checkAndEnqueue(r);
+ return encryptAndSignImpl(params, input, output, appSettings, false);
}
@Override
- public void decryptAndVerify(final OpenPgpData input, final OpenPgpData output,
- final IOpenPgpCallback callback) throws RemoteException {
+ public Bundle signAndEncrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
+ final AppSettings appSettings = getAppSettings();
- final AppSettings settings = getAppSettings();
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- decryptAndVerifySafe(getInput(input), true, callback, settings);
- }
- };
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- checkAndEnqueue(r);
+ return encryptAndSignImpl(params, input, output, appSettings, true);
}
@Override
- public void getKeyIds(final String[] userIds, final boolean allowUserInteraction,
- final IOpenPgpKeyIdsCallback callback) throws RemoteException {
-
- final AppSettings settings = getAppSettings();
+ public Bundle decryptAndVerify(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
+ final AppSettings appSettings = getAppSettings();
- Runnable r = new Runnable() {
- @Override
- public void run() {
- getKeyIdsSafe(userIds, allowUserInteraction, callback, settings);
- }
- };
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- checkAndEnqueue(r);
+ return decryptAndVerifyImpl(params, input, output, appSettings);
}
- };
-
- private static byte[] getInput(OpenPgpData data) {
- // TODO: support Uri and ParcelFileDescriptor
-
- byte[] inBytes = null;
- switch (data.getType()) {
- case OpenPgpData.TYPE_STRING:
- inBytes = data.getString().getBytes();
- break;
-
- case OpenPgpData.TYPE_BYTE_ARRAY:
- inBytes = data.getBytes();
- break;
+ @Override
+ public Bundle getKeyIds(Bundle params) {
+ Bundle errorResult = checkRequirements(params);
+ if (errorResult != null) {
+ return errorResult;
+ }
- default:
- Log.e(Constants.TAG, "Uri and ParcelFileDescriptor not supported right now!");
- break;
+ return getKeyIdsImpl(params);
}
- return inBytes;
- }
+ };
@Override
public IBinder onBind(Intent intent) {
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
index bc513d532..cfd2b9ec3 100644
--- 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
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * 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
@@ -19,17 +19,16 @@ package org.sufficientlysecure.keychain.service.remote;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.TimeUnit;
+import org.openintents.openpgp.OpenPgpError;
+import org.openintents.openpgp.util.OpenPgpConstants;
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.service.exception.WrongPackageSignatureException;
import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor;
+import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -50,66 +49,19 @@ import android.os.Messenger;
public abstract class RemoteService extends Service {
Context mContext;
- private final ArrayBlockingQueue<Runnable> mPoolQueue = new ArrayBlockingQueue<Runnable>(100);
- // TODO: Are these parameters okay?
- private PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10,
- TimeUnit.SECONDS, mPoolQueue);
+ private static final int PRIVATE_REQUEST_CODE_REGISTER = 651;
+ private static final int PRIVATE_REQUEST_CODE_ERROR = 652;
- private final Object userInputLock = new Object();
-
- /**
- * Override handleUserInput() to handle OKAY (1) and CANCEL (0). After handling the waiting
- * threads will be notified and the queue resumed
- */
- protected class UserInputCallback extends BaseCallback {
-
- public void handleUserInput(Message msg) {
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- handleUserInput(msg);
-
- // resume
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- return true;
- }
-
- }
-
- /**
- * Extends Handler.Callback with OKAY (1), CANCEL (0) variables
- */
- private class BaseCallback implements Handler.Callback {
- public static final int OKAY = 1;
- public static final int CANCEL = 0;
-
- @Override
- public boolean handleMessage(Message msg) {
- return false;
- }
-
- }
public Context getContext() {
return mContext;
}
- /**
- * Should be used from Stub implementations of AIDL interfaces to enqueue a runnable for
- * execution
- *
- * @param r
- */
- protected void checkAndEnqueue(Runnable r) {
+ protected Bundle isAllowed(Bundle params) {
try {
if (isCallerAllowed(false)) {
- mThreadPool.execute(r);
- Log.d(Constants.TAG, "Enqueued runnable…");
+ return null;
} else {
String[] callingPackages = getPackageManager().getPackagesForUid(
Binder.getCallingUid());
@@ -121,32 +73,46 @@ public abstract class RemoteService extends Service {
packageSignature = getPackageSignature(packageName);
} catch (NameNotFoundException e) {
Log.e(Constants.TAG, "Should not happen, returning!", e);
- return;
- }
- Log.e(Constants.TAG,
- "Not allowed to use service! Starting activity for registration!");
- Bundle extras = new Bundle();
- extras.putString(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName);
- extras.putByteArray(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature);
- RegisterActivityCallback callback = new RegisterActivityCallback();
-
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_REGISTER, callback,
- extras);
-
- if (callback.isAllowed()) {
- mThreadPool.execute(r);
- Log.d(Constants.TAG, "Enqueued runnable…");
- } else {
- Log.d(Constants.TAG, "User disallowed app!");
+ // return error
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR);
+ result.putParcelable(OpenPgpConstants.RESULT_ERRORS,
+ 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(OpenPgpConstants.PI_RESULT_PARAMS, params);
+
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0);
+
+ // return PendingIntent to be executed by client
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
+
+ return result;
}
} catch (WrongPackageSignatureException e) {
- Log.e(Constants.TAG, e.getMessage());
+ 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(OpenPgpConstants.PI_RESULT_PARAMS, params);
+
+ PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0);
+
+ // return PendingIntent to be executed by client
+ Bundle result = new Bundle();
+ result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED);
+ result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi);
- Bundle extras = new Bundle();
- extras.putString(RemoteServiceActivity.EXTRA_ERROR_MESSAGE,
- getString(R.string.api_error_wrong_signature));
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_ERROR_MESSAGE, null, extras);
+ return result;
}
}
@@ -161,40 +127,8 @@ public abstract class RemoteService extends Service {
}
/**
- * Locks current thread and pauses execution of runnables and starts activity for user input
- *
- * @param action
- * @param messenger
- * @param extras
- */
- protected void pauseAndStartUserInteraction(String action, BaseCallback callback, Bundle extras) {
- synchronized (userInputLock) {
- mThreadPool.pause();
-
- Log.d(Constants.TAG, "starting activity...");
- Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setAction(action);
-
- Messenger messenger = new Messenger(new Handler(getMainLooper(), callback));
-
- extras.putParcelable(RemoteServiceActivity.EXTRA_MESSENGER, messenger);
- intent.putExtras(extras);
-
- startActivity(intent);
-
- // lock current thread for user input
- try {
- userInputLock.wait();
- } catch (InterruptedException e) {
- Log.e(Constants.TAG, "CryptoService", e);
- }
- }
- }
-
- /**
* Retrieves AppSettings from database for the application calling this remote service
- *
+ *
* @return
*/
protected AppSettings getAppSettings() {
@@ -215,66 +149,11 @@ public abstract class RemoteService extends Service {
return null;
}
- class RegisterActivityCallback extends BaseCallback {
- public static final String PACKAGE_NAME = "package_name";
-
- private boolean allowed = false;
- private String packageName;
-
- public boolean isAllowed() {
- return allowed;
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- if (msg.arg1 == OKAY) {
- allowed = true;
- packageName = msg.getData().getString(PACKAGE_NAME);
-
- // resume threads
- try {
- if (isPackageAllowed(packageName)) {
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- } else {
- // Should not happen!
- Log.e(Constants.TAG, "Should not happen! Emergency shutdown!");
- mThreadPool.shutdownNow();
- }
- } catch (WrongPackageSignatureException e) {
- Log.e(Constants.TAG, e.getMessage());
-
- Bundle extras = new Bundle();
- extras.putString(RemoteServiceActivity.EXTRA_ERROR_MESSAGE,
- getString(R.string.api_error_wrong_signature));
- pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_ERROR_MESSAGE, null,
- extras);
- }
- } else {
- allowed = false;
-
- synchronized (userInputLock) {
- userInputLock.notifyAll();
- }
- mThreadPool.resume();
- }
- return true;
- }
-
- }
-
/**
* 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
+ *
+ * @param allowOnlySelf allow only Keychain app itself
* @return true if process is allowed to use this service
* @throws WrongPackageSignatureException
*/
@@ -308,7 +187,7 @@ public abstract class RemoteService extends Service {
/**
* Checks if packageName is a registered app for the API. Does not return true for own package!
- *
+ *
* @param packageName
* @return
* @throws WrongPackageSignatureException
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
index f1e203733..af8e3ade8 100644
--- 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
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * 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
@@ -17,8 +17,15 @@
package org.sufficientlysecure.keychain.service.remote;
-import java.util.ArrayList;
+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.OpenPgpConstants;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
@@ -30,15 +37,7 @@ import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.support.v7.app.ActionBarActivity;
-import android.view.View;
-import android.widget.Toast;
+import java.util.ArrayList;
public class RemoteServiceActivity extends ActionBarActivity {
@@ -64,17 +63,11 @@ public class RemoteServiceActivity extends ActionBarActivity {
// error message
public static final String EXTRA_ERROR_MESSAGE = "error_message";
- private Messenger mMessenger;
-
// register view
private AppSettingsFragment mSettingsFragment;
// select pub keys view
private SelectPublicKeyFragment mSelectFragment;
- // has the user clicked one of the buttons
- // or do we need to handle the callback in onStop()
- private boolean finishHandled;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -82,36 +75,12 @@ public class RemoteServiceActivity extends ActionBarActivity {
handleActions(getIntent(), savedInstanceState);
}
- @Override
- protected void onStop() {
- super.onStop();
-
- if (!finishHandled) {
- Message msg = Message.obtain();
- msg.arg1 = RemoteService.RegisterActivityCallback.CANCEL;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
- }
- }
-
protected void handleActions(Intent intent, Bundle savedInstanceState) {
- finishHandled = false;
String action = intent.getAction();
- Bundle extras = intent.getExtras();
+ final Bundle extras = intent.getExtras();
- if (extras == null) {
- extras = new Bundle();
- }
- mMessenger = extras.getParcelable(EXTRA_MESSENGER);
-
- /**
- * com.android.crypto actions
- */
if (ACTION_REGISTER.equals(action)) {
final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);
@@ -125,44 +94,27 @@ public class RemoteServiceActivity extends ActionBarActivity {
// user needs to select a key!
if (mSettingsFragment.getAppSettings().getKeyId() == Id.key.none) {
- Toast.makeText(RemoteServiceActivity.this,
- R.string.api_register_error_select_key, Toast.LENGTH_LONG)
- .show();
+ mSettingsFragment.setErrorOnSelectKeyFragment(
+ getString(R.string.api_register_error_select_key));
} else {
ProviderHelper.insertApiApp(RemoteServiceActivity.this,
mSettingsFragment.getAppSettings());
- Message msg = Message.obtain();
- msg.arg1 = RemoteService.RegisterActivityCallback.OKAY;
- Bundle data = new Bundle();
- data.putString(RemoteService.RegisterActivityCallback.PACKAGE_NAME,
- packageName);
- msg.setData(data);
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
-
- finishHandled = true;
- finish();
+ // give params through for new service call
+ Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
+
+ Intent finishIntent = new Intent();
+ finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, oldParams);
+ RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
+ RemoteServiceActivity.this.finish();
}
}
}, R.string.api_register_disallow, new View.OnClickListener() {
@Override
public void onClick(View v) {
// Disallow
-
- Message msg = Message.obtain();
- msg.arg1 = RemoteService.RegisterActivityCallback.CANCEL;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
-
- finishHandled = true;
- finish();
+ RemoteServiceActivity.this.setResult(RESULT_CANCELED);
+ RemoteServiceActivity.this.finish();
}
}
);
@@ -176,8 +128,9 @@ public class RemoteServiceActivity extends ActionBarActivity {
mSettingsFragment.setAppSettings(settings);
} else if (ACTION_CACHE_PASSPHRASE.equals(action)) {
long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);
+ Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
- showPassphraseDialog(secretKeyId);
+ showPassphraseDialog(oldParams, secretKeyId);
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
ArrayList<String> missingUserIds = intent
@@ -185,8 +138,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
ArrayList<String> dublicateUserIds = intent
.getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS);
- String text = new String();
- text += "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>";
+ // 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);
@@ -213,40 +166,22 @@ public class RemoteServiceActivity extends ActionBarActivity {
new View.OnClickListener() {
@Override
public void onClick(View v) {
- // ok
-
- Message msg = Message.obtain();
- msg.arg1 = OpenPgpService.SelectPubKeysActivityCallback.OKAY;
- Bundle data = new Bundle();
- data.putLongArray(
- OpenPgpService.SelectPubKeysActivityCallback.PUB_KEY_IDS,
+ // add key ids to params Bundle for new request
+ Bundle params = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS);
+ params.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS,
mSelectFragment.getSelectedMasterKeyIds());
- msg.setData(data);
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
- finishHandled = true;
- finish();
+ Intent finishIntent = new Intent();
+ finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+ RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
+ RemoteServiceActivity.this.finish();
}
}, R.string.btn_do_not_save, new View.OnClickListener() {
@Override
public void onClick(View v) {
// cancel
-
- Message msg = Message.obtain();
- msg.arg1 = OpenPgpService.SelectPubKeysActivityCallback.CANCEL;
- ;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
-
- finishHandled = true;
- finish();
+ RemoteServiceActivity.this.setResult(RESULT_CANCELED);
+ RemoteServiceActivity.this.finish();
}
}
);
@@ -279,8 +214,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
} else if (ACTION_ERROR_MESSAGE.equals(action)) {
String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE);
- String text = new String();
- text += "<font color=\"red\">" + errorMessage + "</font>";
+ String text = "<font color=\"red\">" + errorMessage + "</font>";
// Inflate a "Done" custom action bar view
ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_okay,
@@ -288,7 +222,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
@Override
public void onClick(View v) {
- finish();
+ RemoteServiceActivity.this.setResult(RESULT_OK);
+ RemoteServiceActivity.this.finish();
}
});
@@ -298,7 +233,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text);
textView.setHtmlFromString(text);
} else {
- Log.e(Constants.TAG, "Wrong action!");
+ Log.e(Constants.TAG, "Action does not exist!");
+ setResult(RESULT_CANCELED);
finish();
}
}
@@ -308,31 +244,21 @@ public class RemoteServiceActivity extends ActionBarActivity {
* encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
* for a symmetric passphrase
*/
- private void showPassphraseDialog(long secretKeyId) {
+ private void showPassphraseDialog(final Bundle params, 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) {
- Message msg = Message.obtain();
- msg.arg1 = OpenPgpService.PassphraseActivityCallback.OKAY;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
+ // return given params again, for calling the service method again
+ Intent finishIntent = new Intent();
+ finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+ RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
} else {
- Message msg = Message.obtain();
- msg.arg1 = OpenPgpService.PassphraseActivityCallback.CANCEL;
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "CryptoServiceActivity", e);
- }
+ RemoteServiceActivity.this.setResult(RESULT_CANCELED);
}
- finishHandled = true;
- finish();
+ RemoteServiceActivity.this.finish();
}
};
@@ -345,9 +271,12 @@ public class RemoteServiceActivity extends ActionBarActivity {
passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
} catch (PgpGeneralException e) {
- Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
- // send message to handler to start encryption directly
- returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
+ Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!");
+ // return given params again, for calling the service method again
+ Intent finishIntent = new Intent();
+ finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
+ setResult(RESULT_OK, finishIntent);
+ finish();
}
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java
index cef002265..cc08548e8 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java
@@ -1,4 +1,4 @@
-package org.sufficientlysecure.keychain.service.exception;
+package org.sufficientlysecure.keychain.service.remote;
public class WrongPackageSignatureException extends Exception {