From 9a5707c41526f5fbcb45f72ec50c6f2efdd83056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 10 Sep 2013 23:19:34 +0200 Subject: rename api to openpgp api --- .../src/org/openintents/crypto/CryptoError.aidl | 20 - .../src/org/openintents/crypto/CryptoError.java | 79 --- .../crypto/CryptoServiceConnection.java | 91 --- .../openintents/crypto/CryptoSignatureResult.aidl | 20 - .../openintents/crypto/CryptoSignatureResult.java | 86 --- .../org/openintents/crypto/ICryptoCallback.aidl | 31 - .../src/org/openintents/crypto/ICryptoService.aidl | 80 --- .../org/openintents/openpgp/IOpenPgpCallback.aidl | 31 + .../org/openintents/openpgp/IOpenPgpService.aidl | 80 +++ .../src/org/openintents/openpgp/OpenPgpError.aidl | 20 + .../src/org/openintents/openpgp/OpenPgpError.java | 79 +++ .../openpgp/OpenPgpServiceConnection.java | 91 +++ .../openpgp/OpenPgpSignatureResult.aidl | 20 + .../openpgp/OpenPgpSignatureResult.java | 86 +++ .../keychain/remote_api/CryptoService.java | 747 --------------------- .../keychain/remote_api/CryptoServiceActivity.java | 325 --------- .../keychain/remote_api/OpenPgpService.java | 747 +++++++++++++++++++++ .../remote_api/OpenPgpServiceActivity.java | 325 +++++++++ 18 files changed, 1479 insertions(+), 1479 deletions(-) delete mode 100644 OpenPGP-Keychain/src/org/openintents/crypto/CryptoError.aidl delete mode 100644 OpenPGP-Keychain/src/org/openintents/crypto/CryptoError.java delete mode 100644 OpenPGP-Keychain/src/org/openintents/crypto/CryptoServiceConnection.java delete mode 100644 OpenPGP-Keychain/src/org/openintents/crypto/CryptoSignatureResult.aidl delete mode 100644 OpenPGP-Keychain/src/org/openintents/crypto/CryptoSignatureResult.java delete mode 100644 OpenPGP-Keychain/src/org/openintents/crypto/ICryptoCallback.aidl delete mode 100644 OpenPGP-Keychain/src/org/openintents/crypto/ICryptoService.aidl create mode 100644 OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl create mode 100644 OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl create mode 100644 OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpError.aidl create mode 100644 OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpError.java create mode 100644 OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java create mode 100644 OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.aidl create mode 100644 OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java delete mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoServiceActivity.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/OpenPgpService.java create mode 100644 OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/OpenPgpServiceActivity.java (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoError.aidl b/OpenPGP-Keychain/src/org/openintents/crypto/CryptoError.aidl deleted file mode 100644 index 7b67c8995..000000000 --- a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoError.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.crypto; - -// Declare CryptoError so AIDL can find it and knows that it implements the parcelable protocol. -parcelable CryptoError; \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoError.java b/OpenPGP-Keychain/src/org/openintents/crypto/CryptoError.java deleted file mode 100644 index 13233f70b..000000000 --- a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoError.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.crypto; - -import android.os.Parcel; -import android.os.Parcelable; - -public class CryptoError implements Parcelable { - public static final int ID_NO_OR_WRONG_PASSPHRASE = 1; - public static final int ID_NO_USER_IDS = 2; - - int errorId; - String message; - - public CryptoError() { - } - - public CryptoError(int errorId, String message) { - this.errorId = errorId; - this.message = message; - } - - public CryptoError(CryptoError b) { - this.errorId = b.errorId; - this.message = b.message; - } - - public int getErrorId() { - return errorId; - } - - public void setErrorId(int errorId) { - this.errorId = errorId; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(errorId); - dest.writeString(message); - } - - public static final Creator CREATOR = new Creator() { - public CryptoError createFromParcel(final Parcel source) { - CryptoError error = new CryptoError(); - error.errorId = source.readInt(); - error.message = source.readString(); - return error; - } - - public CryptoError[] newArray(final int size) { - return new CryptoError[size]; - } - }; -} diff --git a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoServiceConnection.java b/OpenPGP-Keychain/src/org/openintents/crypto/CryptoServiceConnection.java deleted file mode 100644 index d9e91f772..000000000 --- a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoServiceConnection.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.crypto; - -import org.openintents.crypto.ICryptoService; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.util.Log; - -public class CryptoServiceConnection { - private Context mApplicationContext; - - private ICryptoService mService; - private boolean bound; - private String cryptoProviderPackageName; - - private static final String TAG = "CryptoConnection"; - - public CryptoServiceConnection(Context context, String cryptoProviderPackageName) { - mApplicationContext = context.getApplicationContext(); - this.cryptoProviderPackageName = cryptoProviderPackageName; - } - - public ICryptoService getService() { - return mService; - } - - private ServiceConnection mCryptoServiceConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName name, IBinder service) { - mService = ICryptoService.Stub.asInterface(service); - Log.d(TAG, "connected to service"); - bound = true; - } - - public void onServiceDisconnected(ComponentName name) { - mService = null; - Log.d(TAG, "disconnected from service"); - bound = false; - } - }; - - /** - * If not already bound, bind! - * - * @return - */ - public boolean bindToService() { - if (mService == null && !bound) { // if not already connected - try { - Log.d(TAG, "not bound yet"); - - Intent serviceIntent = new Intent(); - serviceIntent.setAction("org.openintents.crypto.ICryptoService"); - serviceIntent.setPackage(cryptoProviderPackageName); - mApplicationContext.bindService(serviceIntent, mCryptoServiceConnection, - Context.BIND_AUTO_CREATE); - - return true; - } catch (Exception e) { - Log.d(TAG, "Exception", e); - return false; - } - } else { // already connected - Log.d(TAG, "already bound... "); - return true; - } - } - - public void unbindFromService() { - mApplicationContext.unbindService(mCryptoServiceConnection); - } - -} diff --git a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoSignatureResult.aidl b/OpenPGP-Keychain/src/org/openintents/crypto/CryptoSignatureResult.aidl deleted file mode 100644 index 1d39bac70..000000000 --- a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoSignatureResult.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.crypto; - -// Declare CryptoSignatureResult so AIDL can find it and knows that it implements the parcelable protocol. -parcelable CryptoSignatureResult; \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoSignatureResult.java b/OpenPGP-Keychain/src/org/openintents/crypto/CryptoSignatureResult.java deleted file mode 100644 index d3aaa52d9..000000000 --- a/OpenPGP-Keychain/src/org/openintents/crypto/CryptoSignatureResult.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.crypto; - -import android.os.Parcel; -import android.os.Parcelable; - -public class CryptoSignatureResult implements Parcelable { - String signatureUserId; - - boolean signature; - boolean signatureSuccess; - boolean signatureUnknown; - - public CryptoSignatureResult() { - - } - - public CryptoSignatureResult(String signatureUserId, boolean signature, - boolean signatureSuccess, boolean signatureUnknown) { - this.signatureUserId = signatureUserId; - - this.signature = signature; - this.signatureSuccess = signatureSuccess; - this.signatureUnknown = signatureUnknown; - } - - public CryptoSignatureResult(CryptoSignatureResult b) { - this.signatureUserId = b.signatureUserId; - - this.signature = b.signature; - this.signatureSuccess = b.signatureSuccess; - this.signatureUnknown = b.signatureUnknown; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(signatureUserId); - - dest.writeByte((byte) (signature ? 1 : 0)); - dest.writeByte((byte) (signatureSuccess ? 1 : 0)); - dest.writeByte((byte) (signatureUnknown ? 1 : 0)); - } - - public static final Creator CREATOR = new Creator() { - public CryptoSignatureResult createFromParcel(final Parcel source) { - CryptoSignatureResult vr = new CryptoSignatureResult(); - vr.signatureUserId = source.readString(); - vr.signature = source.readByte() == 1; - vr.signatureSuccess = source.readByte() == 1; - vr.signatureUnknown = source.readByte() == 1; - return vr; - } - - public CryptoSignatureResult[] newArray(final int size) { - return new CryptoSignatureResult[size]; - } - }; - - @Override - public String toString() { - String out = new String(); - out += "signature: " + signature; - out += "\nsignatureSuccess: " + signatureSuccess; - out += "\nsignatureUnknown: " + signatureUnknown; - return out; - } - -} diff --git a/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoCallback.aidl b/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoCallback.aidl deleted file mode 100644 index 31285671f..000000000 --- a/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoCallback.aidl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.crypto; - -import org.openintents.crypto.CryptoSignatureResult; -import org.openintents.crypto.CryptoError; - -interface ICryptoCallback { - - /** - * CryptoSignatureResult is only returned if the Callback was used from decryptAndVerify - * - */ - oneway void onSuccess(in byte[] outputBytes, in CryptoSignatureResult signatureResult); - - oneway void onError(in CryptoError error); -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoService.aidl b/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoService.aidl deleted file mode 100644 index 854ca0b05..000000000 --- a/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoService.aidl +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.crypto; - -import org.openintents.crypto.ICryptoCallback; - -/** - * All methods are oneway, which means they are asynchronous and non-blocking. - * Results are returned to the callback, which has to be implemented on client side. - */ -interface ICryptoService { - - /** - * Encrypt - * - * @param inputBytes - * Byte array you want to encrypt - * @param encryptionUserIds - * User Ids (emails) of recipients - * @param asciiArmor - * Encode for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param callback - * Callback where to return results - */ - oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, in ICryptoCallback callback); - - /** - * Sign - * - * @param inputBytes - * Byte array you want to encrypt - * @param asciiArmor - * Encode for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param callback - * Callback where to return results - */ - oneway void sign(in byte[] inputBytes, in boolean asciiArmor, in ICryptoCallback callback); - - /** - * Encrypt and sign - * - * @param inputBytes - * Byte array you want to encrypt - * @param encryptionUserIds - * User Ids (emails) of recipients - * @param signatureUserId - * User Ids (email) of sender - * @param asciiArmor - * Encode for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param callback - * Callback where to return results - */ - oneway void encryptAndSign(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, in ICryptoCallback callback); - - /** - * Decrypts and verifies given input bytes. If no signature is present this method - * will only decrypt. - * - * @param inputBytes - * Byte array you want to decrypt and verify - * @param callback - * Callback where to return results - */ - oneway void decryptAndVerify(in byte[] inputBytes, in ICryptoCallback callback); - -} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl new file mode 100644 index 000000000..e0ac43d22 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +import org.openintents.openpgp.OpenPgpSignatureResult; +import org.openintents.openpgp.OpenPgpError; + +interface IOpenPgpCallback { + + /** + * CryptoSignatureResult is only returned if the Callback was used from decryptAndVerify + * + */ + oneway void onSuccess(in byte[] outputBytes, in OpenPgpSignatureResult signatureResult); + + oneway void onError(in OpenPgpError error); +} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl new file mode 100644 index 000000000..1d54ac77f --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +import org.openintents.openpgp.IOpenPgpCallback; + +/** + * All methods are oneway, which means they are asynchronous and non-blocking. + * Results are returned to the callback, which has to be implemented on client side. + */ +interface IOpenPgpService { + + /** + * Encrypt + * + * @param inputBytes + * Byte array you want to encrypt + * @param encryptionUserIds + * User Ids (emails) of recipients + * @param asciiArmor + * Encode for ASCII (Radix-64, 33 percent overhead compared to binary) + * @param callback + * Callback where to return results + */ + oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, in IOpenPgpCallback callback); + + /** + * Sign + * + * @param inputBytes + * Byte array you want to encrypt + * @param asciiArmor + * Encode for ASCII (Radix-64, 33 percent overhead compared to binary) + * @param callback + * Callback where to return results + */ + oneway void sign(in byte[] inputBytes, in boolean asciiArmor, in IOpenPgpCallback callback); + + /** + * Encrypt and sign + * + * @param inputBytes + * Byte array you want to encrypt + * @param encryptionUserIds + * User Ids (emails) of recipients + * @param signatureUserId + * User Ids (email) of sender + * @param asciiArmor + * Encode for ASCII (Radix-64, 33 percent overhead compared to binary) + * @param callback + * Callback where to return results + */ + oneway void encryptAndSign(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, in IOpenPgpCallback callback); + + /** + * Decrypts and verifies given input bytes. If no signature is present this method + * will only decrypt. + * + * @param inputBytes + * Byte array you want to decrypt and verify + * @param callback + * Callback where to return results + */ + oneway void decryptAndVerify(in byte[] inputBytes, in IOpenPgpCallback callback); + +} \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpError.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpError.aidl new file mode 100644 index 000000000..7a6bed1e6 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpError.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +// Declare OpenPgpError so AIDL can find it and knows that it implements the parcelable protocol. +parcelable OpenPgpError; \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpError.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpError.java new file mode 100644 index 000000000..66f168d89 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpError.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +import android.os.Parcel; +import android.os.Parcelable; + +public class OpenPgpError implements Parcelable { + public static final int ID_NO_OR_WRONG_PASSPHRASE = 1; + public static final int ID_NO_USER_IDS = 2; + + int errorId; + String message; + + public OpenPgpError() { + } + + public OpenPgpError(int errorId, String message) { + this.errorId = errorId; + this.message = message; + } + + public OpenPgpError(OpenPgpError b) { + this.errorId = b.errorId; + this.message = b.message; + } + + public int getErrorId() { + return errorId; + } + + public void setErrorId(int errorId) { + this.errorId = errorId; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(errorId); + dest.writeString(message); + } + + public static final Creator CREATOR = new Creator() { + public OpenPgpError createFromParcel(final Parcel source) { + OpenPgpError error = new OpenPgpError(); + error.errorId = source.readInt(); + error.message = source.readString(); + return error; + } + + public OpenPgpError[] newArray(final int size) { + return new OpenPgpError[size]; + } + }; +} diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java new file mode 100644 index 000000000..9f4fec470 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +import org.openintents.openpgp.IOpenPgpService; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.util.Log; + +public class OpenPgpServiceConnection { + private Context mApplicationContext; + + private IOpenPgpService mService; + private boolean bound; + private String cryptoProviderPackageName; + + private static final String TAG = "OpenPgpServiceConnection"; + + public OpenPgpServiceConnection(Context context, String cryptoProviderPackageName) { + mApplicationContext = context.getApplicationContext(); + this.cryptoProviderPackageName = cryptoProviderPackageName; + } + + public IOpenPgpService getService() { + return mService; + } + + private ServiceConnection mCryptoServiceConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + mService = IOpenPgpService.Stub.asInterface(service); + Log.d(TAG, "connected to service"); + bound = true; + } + + public void onServiceDisconnected(ComponentName name) { + mService = null; + Log.d(TAG, "disconnected from service"); + bound = false; + } + }; + + /** + * If not already bound, bind! + * + * @return + */ + public boolean bindToService() { + if (mService == null && !bound) { // if not already connected + try { + Log.d(TAG, "not bound yet"); + + Intent serviceIntent = new Intent(); + serviceIntent.setAction(IOpenPgpService.class.getName()); + serviceIntent.setPackage(cryptoProviderPackageName); + mApplicationContext.bindService(serviceIntent, mCryptoServiceConnection, + Context.BIND_AUTO_CREATE); + + return true; + } catch (Exception e) { + Log.d(TAG, "Exception", e); + return false; + } + } else { // already connected + Log.d(TAG, "already bound... "); + return true; + } + } + + public void unbindFromService() { + mApplicationContext.unbindService(mCryptoServiceConnection); + } + +} diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.aidl new file mode 100644 index 000000000..e246792d0 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +// Declare OpenPgpSignatureResult so AIDL can find it and knows that it implements the parcelable protocol. +parcelable OpenPgpSignatureResult; \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java new file mode 100644 index 000000000..d8642664f --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openintents.openpgp; + +import android.os.Parcel; +import android.os.Parcelable; + +public class OpenPgpSignatureResult implements Parcelable { + String signatureUserId; + + boolean signature; + boolean signatureSuccess; + boolean signatureUnknown; + + public OpenPgpSignatureResult() { + + } + + public OpenPgpSignatureResult(String signatureUserId, boolean signature, + boolean signatureSuccess, boolean signatureUnknown) { + this.signatureUserId = signatureUserId; + + this.signature = signature; + this.signatureSuccess = signatureSuccess; + this.signatureUnknown = signatureUnknown; + } + + public OpenPgpSignatureResult(OpenPgpSignatureResult b) { + this.signatureUserId = b.signatureUserId; + + this.signature = b.signature; + this.signatureSuccess = b.signatureSuccess; + this.signatureUnknown = b.signatureUnknown; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(signatureUserId); + + dest.writeByte((byte) (signature ? 1 : 0)); + dest.writeByte((byte) (signatureSuccess ? 1 : 0)); + dest.writeByte((byte) (signatureUnknown ? 1 : 0)); + } + + public static final Creator CREATOR = new Creator() { + public OpenPgpSignatureResult createFromParcel(final Parcel source) { + OpenPgpSignatureResult vr = new OpenPgpSignatureResult(); + vr.signatureUserId = source.readString(); + vr.signature = source.readByte() == 1; + vr.signatureSuccess = source.readByte() == 1; + vr.signatureUnknown = source.readByte() == 1; + return vr; + } + + public OpenPgpSignatureResult[] newArray(final int size) { + return new OpenPgpSignatureResult[size]; + } + }; + + @Override + public String toString() { + String out = new String(); + out += "signature: " + signature; + out += "\nsignatureSuccess: " + signatureSuccess; + out += "\nsignatureUnknown: " + signatureUnknown; + return out; + } + +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java deleted file mode 100644 index 7f36fc2de..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java +++ /dev/null @@ -1,747 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.remote_api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; - -import org.openintents.crypto.CryptoError; -import org.openintents.crypto.CryptoSignatureResult; -import org.openintents.crypto.ICryptoCallback; -import org.openintents.crypto.ICryptoService; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.PgpMain; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; - -public class CryptoService extends Service { - Context mContext; - - final ArrayBlockingQueue mPoolQueue = new ArrayBlockingQueue(100); - // TODO: Are these parameters okay? - PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10, - TimeUnit.SECONDS, mPoolQueue); - - final Object userInputLock = new Object(); - - private class MyBaseCallback implements Handler.Callback { - public static final int OKAY = 1; - public static final int CANCEL = 0; - - @Override - public boolean handleMessage(Message msg) { - return false; - } - - } - - @Override - public void onCreate() { - super.onCreate(); - mContext = this; - Log.d(Constants.TAG, "CryptoService, onCreate()"); - } - - @Override - public void onDestroy() { - super.onDestroy(); - Log.d(Constants.TAG, "CryptoService, onDestroy()"); - } - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - private String getCachedPassphrase(long keyId) { - String passphrase = PassphraseCacheService.getCachedPassphrase(mContext, keyId); - - if (passphrase == null) { - Log.d(Constants.TAG, "No passphrase! Activity required!"); - - // start passphrase dialog - Bundle extras = new Bundle(); - extras.putLong(CryptoServiceActivity.EXTRA_SECRET_KEY_ID, keyId); - - PassphraseActivityCallback callback = new PassphraseActivityCallback(); - Messenger messenger = new Messenger(new Handler(getMainLooper(), callback)); - - pauseQueueAndStartServiceActivity(CryptoServiceActivity.ACTION_CACHE_PASSPHRASE, - messenger, extras); - - if (callback.isSuccess()) { - Log.d(Constants.TAG, "New passphrase entered!"); - - // get again after it was entered - passphrase = PassphraseCacheService.getCachedPassphrase(mContext, keyId); - } else { - Log.d(Constants.TAG, "Passphrase dialog canceled!"); - - return null; - } - - } - - return passphrase; - } - - public class PassphraseActivityCallback extends MyBaseCallback { - - private boolean success = false; - - public boolean isSuccess() { - return success; - } - - @Override - public boolean handleMessage(Message msg) { - if (msg.arg1 == OKAY) { - success = true; - } else { - success = false; - } - - // resume - synchronized (userInputLock) { - userInputLock.notifyAll(); - } - mThreadPool.resume(); - return true; - } - }; - - /** - * Search database for key ids based on emails. - * - * @param encryptionUserIds - * @return - */ - private long[] getKeyIdsFromEmails(String[] encryptionUserIds, long ownKeyId) { - // find key ids to given emails in database - ArrayList keyIds = new ArrayList(); - - boolean missingUserIdsCheck = false; - boolean dublicateUserIdsCheck = false; - ArrayList missingUserIds = new ArrayList(); - ArrayList dublicateUserIds = new ArrayList(); - - 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"); - } - } - - // also encrypt to our self (so that we can decrypt it later!) - keyIds.add(ownKeyId); - - // convert to long[] - long[] keyIdsArray = new long[keyIds.size()]; - for (int i = 0; i < keyIdsArray.length; i++) { - keyIdsArray[i] = keyIds.get(i); - } - - if (missingUserIdsCheck || dublicateUserIdsCheck) { - SelectPubKeysActivityCallback callback = new SelectPubKeysActivityCallback(); - Messenger messenger = new Messenger(new Handler(getMainLooper(), callback)); - - Bundle extras = new Bundle(); - extras.putLongArray(CryptoServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); - extras.putStringArrayList(CryptoServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); - extras.putStringArrayList(CryptoServiceActivity.EXTRA_DUBLICATE_USER_IDS, - dublicateUserIds); - - pauseQueueAndStartServiceActivity(CryptoServiceActivity.ACTION_SELECT_PUB_KEYS, - messenger, 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 (keyIdsArray.length == 0) { - return null; - } - return keyIdsArray; - } - - public class SelectPubKeysActivityCallback extends MyBaseCallback { - public static final String PUB_KEY_IDS = "pub_key_ids"; - - private boolean success = false; - private long[] pubKeyIds; - - public boolean isSuccess() { - return success; - } - - public long[] getPubKeyIds() { - return pubKeyIds; - } - - @Override - public boolean handleMessage(Message msg) { - if (msg.arg1 == OKAY) { - success = true; - pubKeyIds = msg.getData().getLongArray(PUB_KEY_IDS); - } else { - success = false; - } - - // resume - synchronized (userInputLock) { - userInputLock.notifyAll(); - } - mThreadPool.resume(); - return true; - } - }; - - private synchronized void encryptAndSignSafe(byte[] inputBytes, String[] encryptionUserIds, - boolean asciiArmor, ICryptoCallback callback, AppSettings appSettings, boolean sign) - throws RemoteException { - 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(); - - long[] keyIds = getKeyIdsFromEmails(encryptionUserIds, appSettings.getKeyId()); - if (keyIds == null) { - callback.onError(new CryptoError(CryptoError.ID_NO_USER_IDS, "No user ids!")); - return; - } - - if (sign) { - String passphrase = getCachedPassphrase(appSettings.getKeyId()); - if (passphrase == null) { - callback.onError(new CryptoError(CryptoError.ID_NO_OR_WRONG_PASSPHRASE, - "No or wrong passphrase!")); - return; - } - - PgpMain.encryptAndSign(mContext, null, inputData, outputStream, asciiArmor, - appSettings.getCompression(), keyIds, null, - appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(), - appSettings.getHashAlgorithm(), true, passphrase); - } else { - PgpMain.encryptAndSign(mContext, null, inputData, outputStream, asciiArmor, - appSettings.getCompression(), keyIds, null, - appSettings.getEncryptionAlgorithm(), Id.key.none, - appSettings.getHashAlgorithm(), true, null); - } - - outputStream.close(); - - byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); - - // return over handler on client side - callback.onSuccess(outputBytes, null); - } catch (Exception e) { - Log.e(Constants.TAG, "KeychainService, Exception!", e); - - try { - callback.onError(new CryptoError(0, e.getMessage())); - } catch (Exception t) { - Log.e(Constants.TAG, "Error returning exception to client", t); - } - } - } - - // TODO: asciiArmor?! - private void signSafe(byte[] inputBytes, ICryptoCallback callback, AppSettings appSettings) - throws RemoteException { - try { - Log.d(Constants.TAG, "current therad id: " + Thread.currentThread().getId()); - - // 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()); - if (passphrase == null) { - callback.onError(new CryptoError(CryptoError.ID_NO_OR_WRONG_PASSPHRASE, - "No or wrong passphrase!")); - return; - } - - PgpMain.signText(this, null, inputData, outputStream, appSettings.getKeyId(), - passphrase, appSettings.getHashAlgorithm(), Preferences.getPreferences(this) - .getForceV3Signatures()); - - outputStream.close(); - - byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); - - // return over handler on client side - callback.onSuccess(outputBytes, null); - } catch (Exception e) { - Log.e(Constants.TAG, "KeychainService, Exception!", e); - - try { - callback.onError(new CryptoError(0, e.getMessage())); - } catch (Exception t) { - Log.e(Constants.TAG, "Error returning exception to client", t); - } - } - } - - private synchronized void decryptAndVerifySafe(byte[] inputBytes, ICryptoCallback callback, - AppSettings appSettings) throws RemoteException { - 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 = PgpMain.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 = PgpMain.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? - // long secretKeyId = PgpMain.getDecryptionKeyId(mContext, inputStream); - // if (secretKeyId == Id.key.none) { - // throw new PgpMain.PgpGeneralException(getString(R.string.error_noSecretKeyFound)); - // } - - String passphrase = null; - boolean assumeSymmetricEncryption = false; - 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! - // TODO: we need activity to input symmetric passphrase - long secretKeyId; - try { - if (inputStream2.markSupported()) { - inputStream2.mark(200); // should probably set this to the max size of two - // pgpF - // objects, if it even needs to be anything other - // than - // 0. - } - secretKeyId = PgpMain.getDecryptionKeyId(this, inputStream2); - if (secretKeyId == Id.key.none) { - throw new PgpMain.PgpGeneralException( - getString(R.string.error_noSecretKeyFound)); - } - assumeSymmetricEncryption = false; - } catch (PgpMain.NoAsymmetricEncryptionException e) { - if (inputStream2.markSupported()) { - inputStream2.reset(); - } - secretKeyId = Id.key.symmetric; - if (!PgpMain.hasSymmetricEncryption(this, inputStream2)) { - throw new PgpMain.PgpGeneralException( - getString(R.string.error_noKnownEncryptionFound)); - } - assumeSymmetricEncryption = true; - } - - Log.d(Constants.TAG, "secretKeyId " + secretKeyId); - - passphrase = getCachedPassphrase(secretKeyId); - if (passphrase == null) { - callback.onError(new CryptoError(CryptoError.ID_NO_OR_WRONG_PASSPHRASE, - "No or wrong passphrase!")); - return; - } - } - - // 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(); - - Bundle outputBundle; - if (signedOnly) { - // TODO: download missing keys from keyserver? - outputBundle = PgpMain.verifyText(this, null, inputData, outputStream, false); - } else { - // TODO: assume symmetric: callback to enter symmetric pass - outputBundle = PgpMain.decryptAndVerify(this, null, inputData, outputStream, - passphrase, assumeSymmetricEncryption); - } - - outputStream.close(); - - byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); - - // get signature informations from bundle - boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_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); - - CryptoSignatureResult sigResult = null; - if (signature) { - sigResult = new CryptoSignatureResult(signatureUserId, signature, signatureSuccess, - signatureUnknown); - } - - // return over handler on client side - callback.onSuccess(outputBytes, sigResult); - } catch (Exception e) { - Log.e(Constants.TAG, "KeychainService, Exception!", e); - - try { - callback.onError(new CryptoError(0, e.getMessage())); - } catch (Exception t) { - Log.e(Constants.TAG, "Error returning exception to client", t); - } - } - } - - private final ICryptoService.Stub mBinder = new ICryptoService.Stub() { - - @Override - public void encrypt(final byte[] inputBytes, final String[] encryptionUserIds, - final boolean asciiArmor, final ICryptoCallback callback) throws RemoteException { - - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - - @Override - public void run() { - try { - encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, callback, - settings, false); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoService", e); - } - } - }; - - checkAndEnqueue(r); - } - - @Override - public void encryptAndSign(final byte[] inputBytes, final String[] encryptionUserIds, - final boolean asciiArmor, final ICryptoCallback callback) throws RemoteException { - - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - - @Override - public void run() { - try { - encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, callback, - settings, true); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoService", e); - } - } - }; - - checkAndEnqueue(r); - } - - @Override - public void sign(final byte[] inputBytes, boolean asciiArmor, final ICryptoCallback callback) - throws RemoteException { - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - - @Override - public void run() { - try { - signSafe(inputBytes, callback, settings); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoService", e); - } - } - }; - - checkAndEnqueue(r); - - } - - @Override - public void decryptAndVerify(final byte[] inputBytes, final ICryptoCallback callback) - throws RemoteException { - - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - - @Override - public void run() { - try { - decryptAndVerifySafe(inputBytes, callback, settings); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoService", e); - } - } - }; - - checkAndEnqueue(r); - } - - }; - - private void checkAndEnqueue(Runnable r) { - if (isCallerAllowed(false)) { - mThreadPool.execute(r); - - Log.d(Constants.TAG, "Enqueued runnable…"); - } else { - String[] callingPackages = getPackageManager() - .getPackagesForUid(Binder.getCallingUid()); - - Log.e(Constants.TAG, "Not allowed to use service! Starting activity for registration!"); - Bundle extras = new Bundle(); - // TODO: currently simply uses first entry - extras.putString(CryptoServiceActivity.EXTRA_PACKAGE_NAME, callingPackages[0]); - - RegisterActivityCallback callback = new RegisterActivityCallback(); - Messenger messenger = new Messenger(new Handler(getMainLooper(), callback)); - - pauseQueueAndStartServiceActivity(CryptoServiceActivity.ACTION_REGISTER, messenger, - extras); - - if (callback.isAllowed()) { - mThreadPool.execute(r); - Log.d(Constants.TAG, "Enqueued runnable…"); - } else { - Log.d(Constants.TAG, "User disallowed app!"); - } - } - } - - public class RegisterActivityCallback extends MyBaseCallback { - 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 - if (isPackageAllowed(packageName, false)) { - synchronized (userInputLock) { - userInputLock.notifyAll(); - } - mThreadPool.resume(); - } else { - // Should not happen! - Log.e(Constants.TAG, "Should not happen! Emergency shutdown!"); - mThreadPool.shutdownNow(); - } - } 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 - * @return true if process is allowed to use this service - */ - private boolean isCallerAllowed(boolean allowOnlySelf) { - String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); - - // is calling package allowed to use this service? - for (int i = 0; i < callingPackages.length; i++) { - String currentPkg = callingPackages[i]; - - if (isPackageAllowed(currentPkg, allowOnlySelf)) { - return true; - } - } - - Log.d(Constants.TAG, "Caller is NOT allowed!"); - return false; - } - - private AppSettings getAppSettings() { - String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); - - // is calling package allowed to use this service? - for (int i = 0; i < callingPackages.length; i++) { - String currentPkg = callingPackages[i]; - - Uri uri = KeychainContract.ApiApps.buildByPackageNameUri(currentPkg); - - AppSettings settings = ProviderHelper.getApiAppSettings(this, uri); - - return settings; - } - - return null; - } - - /** - * Checks if packageName is a registered app for the API. - * - * @param packageName - * @param allowOnlySelf - * allow only Keychain app itself - * @return - */ - private boolean isPackageAllowed(String packageName, boolean allowOnlySelf) { - Log.d(Constants.TAG, "packageName: " + packageName); - - ArrayList allowedPkgs = ProviderHelper.getRegisteredApiApps(mContext); - Log.d(Constants.TAG, "allowed: " + allowedPkgs); - - // check if package is allowed to use our service - if (allowedPkgs.contains(packageName) && (!allowOnlySelf)) { - Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); - - return true; - } else if (Constants.PACKAGE_NAME.equals(packageName)) { - Log.d(Constants.TAG, "Package is OpenPGP Keychain! -> allowed!"); - - return true; - } - - return false; - } - - private void pauseQueueAndStartServiceActivity(String action, Messenger messenger, Bundle extras) { - synchronized (userInputLock) { - mThreadPool.pause(); - - Log.d(Constants.TAG, "starting activity..."); - Intent intent = new Intent(getBaseContext(), CryptoServiceActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setAction(action); - - extras.putParcelable(CryptoServiceActivity.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); - } - } - - } -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoServiceActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoServiceActivity.java deleted file mode 100644 index a8e101dae..000000000 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoServiceActivity.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.remote_api; - -import java.util.ArrayList; - -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.helper.PgpMain; -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 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.view.View; -import android.widget.Toast; - -import com.actionbarsherlock.app.SherlockFragmentActivity; - -public class CryptoServiceActivity extends SherlockFragmentActivity { - - 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 EXTRA_MESSENGER = "messenger"; - - // passphrase action - public static final String EXTRA_SECRET_KEY_ID = "secret_key_id"; - // register action - public static final String EXTRA_PACKAGE_NAME = "package_name"; - // 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"; - - 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); - - handleActions(getIntent(), savedInstanceState); - } - - @Override - protected void onStop() { - super.onStop(); - - if (!finishHandled) { - Message msg = Message.obtain(); - msg.arg1 = CryptoService.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(); - - 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); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.api_register_allow, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Allow - - // user needs to select a key! - if (mSettingsFragment.getAppSettings().getKeyId() == Id.key.none) { - Toast.makeText(CryptoServiceActivity.this, - R.string.api_register_error_select_key, Toast.LENGTH_LONG) - .show(); - } else { - ProviderHelper.insertApiApp(CryptoServiceActivity.this, - mSettingsFragment.getAppSettings()); - - Message msg = Message.obtain(); - msg.arg1 = CryptoService.RegisterActivityCallback.OKAY; - Bundle data = new Bundle(); - data.putString(CryptoService.RegisterActivityCallback.PACKAGE_NAME, - packageName); - msg.setData(data); - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - - finishHandled = true; - finish(); - } - } - }, R.string.api_register_disallow, new View.OnClickListener() { - @Override - public void onClick(View v) { - // Disallow - - Message msg = Message.obtain(); - msg.arg1 = CryptoService.RegisterActivityCallback.CANCEL; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - - finishHandled = true; - finish(); - } - }); - - setContentView(R.layout.api_app_register_activity); - - mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_app_settings_fragment); - - AppSettings settings = new AppSettings(packageName); - mSettingsFragment.setAppSettings(settings); - } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { - long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); - - showPassphraseDialog(secretKeyId); - } else if (ACTION_SELECT_PUB_KEYS.equals(action)) { - long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); - ArrayList missingUserIds = intent - .getStringArrayListExtra(EXTRA_MISSING_USER_IDS); - ArrayList dublicateUserIds = intent - .getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS); - - String text = new String(); - text += "" + getString(R.string.api_select_pub_keys_text) + ""; - text += "

"; - if (missingUserIds != null && missingUserIds.size() > 0) { - text += getString(R.string.api_select_pub_keys_missing_text); - text += "
"; - text += "
    "; - for (String userId : missingUserIds) { - text += "
  • " + userId + "
  • "; - } - text += "
"; - text += "
"; - } - if (dublicateUserIds != null && dublicateUserIds.size() > 0) { - text += getString(R.string.api_select_pub_keys_dublicates_text); - text += "
"; - text += "
    "; - for (String userId : dublicateUserIds) { - text += "
  • " + userId + "
  • "; - } - text += "
"; - } - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // ok - - Message msg = Message.obtain(); - msg.arg1 = CryptoService.SelectPubKeysActivityCallback.OKAY; - Bundle data = new Bundle(); - data.putLongArray( - CryptoService.SelectPubKeysActivityCallback.PUB_KEY_IDS, - mSelectFragment.getSelectedMasterKeyIds()); - msg.setData(data); - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - - finishHandled = true; - finish(); - } - }, R.string.btn_doNotSave, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - - Message msg = Message.obtain(); - msg.arg1 = CryptoService.SelectPubKeysActivityCallback.CANCEL; - ; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - - finishHandled = true; - 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 { - Log.e(Constants.TAG, "Wrong action!"); - 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(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 = CryptoService.PassphraseActivityCallback.OKAY; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - } else { - Message msg = Message.obtain(); - msg.arg1 = CryptoService.PassphraseActivityCallback.CANCEL; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - } - - finishHandled = true; - 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 (PgpMain.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); - } - } -} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/OpenPgpService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/OpenPgpService.java new file mode 100644 index 000000000..0a640560a --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/OpenPgpService.java @@ -0,0 +1,747 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.remote_api; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; + +import org.openintents.openpgp.IOpenPgpCallback; +import org.openintents.openpgp.IOpenPgpService; +import org.openintents.openpgp.OpenPgpError; +import org.openintents.openpgp.OpenPgpSignatureResult; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.PgpMain; +import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; + +public class OpenPgpService extends Service { + Context mContext; + + final ArrayBlockingQueue mPoolQueue = new ArrayBlockingQueue(100); + // TODO: Are these parameters okay? + PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10, + TimeUnit.SECONDS, mPoolQueue); + + final Object userInputLock = new Object(); + + private class MyBaseCallback implements Handler.Callback { + public static final int OKAY = 1; + public static final int CANCEL = 0; + + @Override + public boolean handleMessage(Message msg) { + return false; + } + + } + + @Override + public void onCreate() { + super.onCreate(); + mContext = this; + Log.d(Constants.TAG, "CryptoService, onCreate()"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.d(Constants.TAG, "CryptoService, onDestroy()"); + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + private String getCachedPassphrase(long keyId) { + String passphrase = PassphraseCacheService.getCachedPassphrase(mContext, keyId); + + if (passphrase == null) { + Log.d(Constants.TAG, "No passphrase! Activity required!"); + + // start passphrase dialog + Bundle extras = new Bundle(); + extras.putLong(OpenPgpServiceActivity.EXTRA_SECRET_KEY_ID, keyId); + + PassphraseActivityCallback callback = new PassphraseActivityCallback(); + Messenger messenger = new Messenger(new Handler(getMainLooper(), callback)); + + pauseQueueAndStartServiceActivity(OpenPgpServiceActivity.ACTION_CACHE_PASSPHRASE, + messenger, extras); + + if (callback.isSuccess()) { + Log.d(Constants.TAG, "New passphrase entered!"); + + // get again after it was entered + passphrase = PassphraseCacheService.getCachedPassphrase(mContext, keyId); + } else { + Log.d(Constants.TAG, "Passphrase dialog canceled!"); + + return null; + } + + } + + return passphrase; + } + + public class PassphraseActivityCallback extends MyBaseCallback { + + private boolean success = false; + + public boolean isSuccess() { + return success; + } + + @Override + public boolean handleMessage(Message msg) { + if (msg.arg1 == OKAY) { + success = true; + } else { + success = false; + } + + // resume + synchronized (userInputLock) { + userInputLock.notifyAll(); + } + mThreadPool.resume(); + return true; + } + }; + + /** + * Search database for key ids based on emails. + * + * @param encryptionUserIds + * @return + */ + private long[] getKeyIdsFromEmails(String[] encryptionUserIds, long ownKeyId) { + // find key ids to given emails in database + ArrayList keyIds = new ArrayList(); + + boolean missingUserIdsCheck = false; + boolean dublicateUserIdsCheck = false; + ArrayList missingUserIds = new ArrayList(); + ArrayList dublicateUserIds = new ArrayList(); + + 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"); + } + } + + // also encrypt to our self (so that we can decrypt it later!) + keyIds.add(ownKeyId); + + // convert to long[] + long[] keyIdsArray = new long[keyIds.size()]; + for (int i = 0; i < keyIdsArray.length; i++) { + keyIdsArray[i] = keyIds.get(i); + } + + if (missingUserIdsCheck || dublicateUserIdsCheck) { + SelectPubKeysActivityCallback callback = new SelectPubKeysActivityCallback(); + Messenger messenger = new Messenger(new Handler(getMainLooper(), callback)); + + Bundle extras = new Bundle(); + extras.putLongArray(OpenPgpServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); + extras.putStringArrayList(OpenPgpServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); + extras.putStringArrayList(OpenPgpServiceActivity.EXTRA_DUBLICATE_USER_IDS, + dublicateUserIds); + + pauseQueueAndStartServiceActivity(OpenPgpServiceActivity.ACTION_SELECT_PUB_KEYS, + messenger, 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 (keyIdsArray.length == 0) { + return null; + } + return keyIdsArray; + } + + public class SelectPubKeysActivityCallback extends MyBaseCallback { + public static final String PUB_KEY_IDS = "pub_key_ids"; + + private boolean success = false; + private long[] pubKeyIds; + + public boolean isSuccess() { + return success; + } + + public long[] getPubKeyIds() { + return pubKeyIds; + } + + @Override + public boolean handleMessage(Message msg) { + if (msg.arg1 == OKAY) { + success = true; + pubKeyIds = msg.getData().getLongArray(PUB_KEY_IDS); + } else { + success = false; + } + + // resume + synchronized (userInputLock) { + userInputLock.notifyAll(); + } + mThreadPool.resume(); + return true; + } + }; + + private synchronized void encryptAndSignSafe(byte[] inputBytes, String[] encryptionUserIds, + boolean asciiArmor, IOpenPgpCallback callback, AppSettings appSettings, boolean sign) + throws RemoteException { + 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(); + + long[] keyIds = getKeyIdsFromEmails(encryptionUserIds, appSettings.getKeyId()); + if (keyIds == null) { + callback.onError(new OpenPgpError(OpenPgpError.ID_NO_USER_IDS, "No user ids!")); + return; + } + + if (sign) { + String passphrase = getCachedPassphrase(appSettings.getKeyId()); + if (passphrase == null) { + callback.onError(new OpenPgpError(OpenPgpError.ID_NO_OR_WRONG_PASSPHRASE, + "No or wrong passphrase!")); + return; + } + + PgpMain.encryptAndSign(mContext, null, inputData, outputStream, asciiArmor, + appSettings.getCompression(), keyIds, null, + appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(), + appSettings.getHashAlgorithm(), true, passphrase); + } else { + PgpMain.encryptAndSign(mContext, null, inputData, outputStream, asciiArmor, + appSettings.getCompression(), keyIds, null, + appSettings.getEncryptionAlgorithm(), Id.key.none, + appSettings.getHashAlgorithm(), true, null); + } + + outputStream.close(); + + byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); + + // return over handler on client side + callback.onSuccess(outputBytes, null); + } catch (Exception e) { + Log.e(Constants.TAG, "KeychainService, Exception!", e); + + try { + callback.onError(new OpenPgpError(0, e.getMessage())); + } catch (Exception t) { + Log.e(Constants.TAG, "Error returning exception to client", t); + } + } + } + + // TODO: asciiArmor?! + private void signSafe(byte[] inputBytes, IOpenPgpCallback callback, AppSettings appSettings) + throws RemoteException { + try { + Log.d(Constants.TAG, "current therad id: " + Thread.currentThread().getId()); + + // 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()); + if (passphrase == null) { + callback.onError(new OpenPgpError(OpenPgpError.ID_NO_OR_WRONG_PASSPHRASE, + "No or wrong passphrase!")); + return; + } + + PgpMain.signText(this, null, inputData, outputStream, appSettings.getKeyId(), + passphrase, appSettings.getHashAlgorithm(), Preferences.getPreferences(this) + .getForceV3Signatures()); + + outputStream.close(); + + byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); + + // return over handler on client side + callback.onSuccess(outputBytes, null); + } catch (Exception e) { + Log.e(Constants.TAG, "KeychainService, Exception!", e); + + try { + callback.onError(new OpenPgpError(0, e.getMessage())); + } catch (Exception t) { + Log.e(Constants.TAG, "Error returning exception to client", t); + } + } + } + + private synchronized void decryptAndVerifySafe(byte[] inputBytes, IOpenPgpCallback callback, + AppSettings appSettings) throws RemoteException { + 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 = PgpMain.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 = PgpMain.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? + // long secretKeyId = PgpMain.getDecryptionKeyId(mContext, inputStream); + // if (secretKeyId == Id.key.none) { + // throw new PgpMain.PgpGeneralException(getString(R.string.error_noSecretKeyFound)); + // } + + String passphrase = null; + boolean assumeSymmetricEncryption = false; + 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! + // TODO: we need activity to input symmetric passphrase + long secretKeyId; + try { + if (inputStream2.markSupported()) { + inputStream2.mark(200); // should probably set this to the max size of two + // pgpF + // objects, if it even needs to be anything other + // than + // 0. + } + secretKeyId = PgpMain.getDecryptionKeyId(this, inputStream2); + if (secretKeyId == Id.key.none) { + throw new PgpMain.PgpGeneralException( + getString(R.string.error_noSecretKeyFound)); + } + assumeSymmetricEncryption = false; + } catch (PgpMain.NoAsymmetricEncryptionException e) { + if (inputStream2.markSupported()) { + inputStream2.reset(); + } + secretKeyId = Id.key.symmetric; + if (!PgpMain.hasSymmetricEncryption(this, inputStream2)) { + throw new PgpMain.PgpGeneralException( + getString(R.string.error_noKnownEncryptionFound)); + } + assumeSymmetricEncryption = true; + } + + Log.d(Constants.TAG, "secretKeyId " + secretKeyId); + + passphrase = getCachedPassphrase(secretKeyId); + if (passphrase == null) { + callback.onError(new OpenPgpError(OpenPgpError.ID_NO_OR_WRONG_PASSPHRASE, + "No or wrong passphrase!")); + return; + } + } + + // 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(); + + Bundle outputBundle; + if (signedOnly) { + // TODO: download missing keys from keyserver? + outputBundle = PgpMain.verifyText(this, null, inputData, outputStream, false); + } else { + // TODO: assume symmetric: callback to enter symmetric pass + outputBundle = PgpMain.decryptAndVerify(this, null, inputData, outputStream, + passphrase, assumeSymmetricEncryption); + } + + outputStream.close(); + + byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); + + // get signature informations from bundle + boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_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); + + OpenPgpSignatureResult sigResult = null; + if (signature) { + sigResult = new OpenPgpSignatureResult(signatureUserId, signature, + signatureSuccess, signatureUnknown); + } + + // return over handler on client side + callback.onSuccess(outputBytes, sigResult); + } catch (Exception e) { + Log.e(Constants.TAG, "KeychainService, Exception!", e); + + try { + callback.onError(new OpenPgpError(0, e.getMessage())); + } catch (Exception t) { + Log.e(Constants.TAG, "Error returning exception to client", t); + } + } + } + + private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() { + + @Override + public void encrypt(final byte[] inputBytes, final String[] encryptionUserIds, + final boolean asciiArmor, final IOpenPgpCallback callback) throws RemoteException { + + final AppSettings settings = getAppSettings(); + + Runnable r = new Runnable() { + + @Override + public void run() { + try { + encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, callback, + settings, false); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoService", e); + } + } + }; + + checkAndEnqueue(r); + } + + @Override + public void encryptAndSign(final byte[] inputBytes, final String[] encryptionUserIds, + final boolean asciiArmor, final IOpenPgpCallback callback) throws RemoteException { + + final AppSettings settings = getAppSettings(); + + Runnable r = new Runnable() { + + @Override + public void run() { + try { + encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, callback, + settings, true); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoService", e); + } + } + }; + + checkAndEnqueue(r); + } + + @Override + public void sign(final byte[] inputBytes, boolean asciiArmor, + final IOpenPgpCallback callback) throws RemoteException { + final AppSettings settings = getAppSettings(); + + Runnable r = new Runnable() { + + @Override + public void run() { + try { + signSafe(inputBytes, callback, settings); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoService", e); + } + } + }; + + checkAndEnqueue(r); + + } + + @Override + public void decryptAndVerify(final byte[] inputBytes, final IOpenPgpCallback callback) + throws RemoteException { + + final AppSettings settings = getAppSettings(); + + Runnable r = new Runnable() { + + @Override + public void run() { + try { + decryptAndVerifySafe(inputBytes, callback, settings); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoService", e); + } + } + }; + + checkAndEnqueue(r); + } + + }; + + private void checkAndEnqueue(Runnable r) { + if (isCallerAllowed(false)) { + mThreadPool.execute(r); + + Log.d(Constants.TAG, "Enqueued runnable…"); + } else { + String[] callingPackages = getPackageManager() + .getPackagesForUid(Binder.getCallingUid()); + + Log.e(Constants.TAG, "Not allowed to use service! Starting activity for registration!"); + Bundle extras = new Bundle(); + // TODO: currently simply uses first entry + extras.putString(OpenPgpServiceActivity.EXTRA_PACKAGE_NAME, callingPackages[0]); + + RegisterActivityCallback callback = new RegisterActivityCallback(); + Messenger messenger = new Messenger(new Handler(getMainLooper(), callback)); + + pauseQueueAndStartServiceActivity(OpenPgpServiceActivity.ACTION_REGISTER, messenger, + extras); + + if (callback.isAllowed()) { + mThreadPool.execute(r); + Log.d(Constants.TAG, "Enqueued runnable…"); + } else { + Log.d(Constants.TAG, "User disallowed app!"); + } + } + } + + public class RegisterActivityCallback extends MyBaseCallback { + 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 + if (isPackageAllowed(packageName, false)) { + synchronized (userInputLock) { + userInputLock.notifyAll(); + } + mThreadPool.resume(); + } else { + // Should not happen! + Log.e(Constants.TAG, "Should not happen! Emergency shutdown!"); + mThreadPool.shutdownNow(); + } + } 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 + * @return true if process is allowed to use this service + */ + private boolean isCallerAllowed(boolean allowOnlySelf) { + String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); + + // is calling package allowed to use this service? + for (int i = 0; i < callingPackages.length; i++) { + String currentPkg = callingPackages[i]; + + if (isPackageAllowed(currentPkg, allowOnlySelf)) { + return true; + } + } + + Log.d(Constants.TAG, "Caller is NOT allowed!"); + return false; + } + + private AppSettings getAppSettings() { + String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); + + // is calling package allowed to use this service? + for (int i = 0; i < callingPackages.length; i++) { + String currentPkg = callingPackages[i]; + + Uri uri = KeychainContract.ApiApps.buildByPackageNameUri(currentPkg); + + AppSettings settings = ProviderHelper.getApiAppSettings(this, uri); + + return settings; + } + + return null; + } + + /** + * Checks if packageName is a registered app for the API. + * + * @param packageName + * @param allowOnlySelf + * allow only Keychain app itself + * @return + */ + private boolean isPackageAllowed(String packageName, boolean allowOnlySelf) { + Log.d(Constants.TAG, "packageName: " + packageName); + + ArrayList allowedPkgs = ProviderHelper.getRegisteredApiApps(mContext); + Log.d(Constants.TAG, "allowed: " + allowedPkgs); + + // check if package is allowed to use our service + if (allowedPkgs.contains(packageName) && (!allowOnlySelf)) { + Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); + + return true; + } else if (Constants.PACKAGE_NAME.equals(packageName)) { + Log.d(Constants.TAG, "Package is OpenPGP Keychain! -> allowed!"); + + return true; + } + + return false; + } + + private void pauseQueueAndStartServiceActivity(String action, Messenger messenger, Bundle extras) { + synchronized (userInputLock) { + mThreadPool.pause(); + + Log.d(Constants.TAG, "starting activity..."); + Intent intent = new Intent(getBaseContext(), OpenPgpServiceActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setAction(action); + + extras.putParcelable(OpenPgpServiceActivity.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); + } + } + + } +} diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/OpenPgpServiceActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/OpenPgpServiceActivity.java new file mode 100644 index 000000000..3d3d046e1 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/OpenPgpServiceActivity.java @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.remote_api; + +import java.util.ArrayList; + +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.helper.PgpMain; +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 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.view.View; +import android.widget.Toast; + +import com.actionbarsherlock.app.SherlockFragmentActivity; + +public class OpenPgpServiceActivity extends SherlockFragmentActivity { + + 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 EXTRA_MESSENGER = "messenger"; + + // passphrase action + public static final String EXTRA_SECRET_KEY_ID = "secret_key_id"; + // register action + public static final String EXTRA_PACKAGE_NAME = "package_name"; + // 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"; + + 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); + + handleActions(getIntent(), savedInstanceState); + } + + @Override + protected void onStop() { + super.onStop(); + + if (!finishHandled) { + Message msg = Message.obtain(); + msg.arg1 = OpenPgpService.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(); + + 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); + + // Inflate a "Done"/"Cancel" custom action bar view + ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.api_register_allow, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Allow + + // user needs to select a key! + if (mSettingsFragment.getAppSettings().getKeyId() == Id.key.none) { + Toast.makeText(OpenPgpServiceActivity.this, + R.string.api_register_error_select_key, Toast.LENGTH_LONG) + .show(); + } else { + ProviderHelper.insertApiApp(OpenPgpServiceActivity.this, + mSettingsFragment.getAppSettings()); + + Message msg = Message.obtain(); + msg.arg1 = OpenPgpService.RegisterActivityCallback.OKAY; + Bundle data = new Bundle(); + data.putString(OpenPgpService.RegisterActivityCallback.PACKAGE_NAME, + packageName); + msg.setData(data); + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoServiceActivity", e); + } + + finishHandled = true; + finish(); + } + } + }, R.string.api_register_disallow, new View.OnClickListener() { + @Override + public void onClick(View v) { + // Disallow + + Message msg = Message.obtain(); + msg.arg1 = OpenPgpService.RegisterActivityCallback.CANCEL; + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoServiceActivity", e); + } + + finishHandled = true; + finish(); + } + }); + + setContentView(R.layout.api_app_register_activity); + + mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( + R.id.api_app_settings_fragment); + + AppSettings settings = new AppSettings(packageName); + mSettingsFragment.setAppSettings(settings); + } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { + long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); + + showPassphraseDialog(secretKeyId); + } else if (ACTION_SELECT_PUB_KEYS.equals(action)) { + long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); + ArrayList missingUserIds = intent + .getStringArrayListExtra(EXTRA_MISSING_USER_IDS); + ArrayList dublicateUserIds = intent + .getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS); + + String text = new String(); + text += "" + getString(R.string.api_select_pub_keys_text) + ""; + text += "

"; + if (missingUserIds != null && missingUserIds.size() > 0) { + text += getString(R.string.api_select_pub_keys_missing_text); + text += "
"; + text += "
    "; + for (String userId : missingUserIds) { + text += "
  • " + userId + "
  • "; + } + text += "
"; + text += "
"; + } + if (dublicateUserIds != null && dublicateUserIds.size() > 0) { + text += getString(R.string.api_select_pub_keys_dublicates_text); + text += "
"; + text += "
    "; + for (String userId : dublicateUserIds) { + text += "
  • " + userId + "
  • "; + } + text += "
"; + } + + // Inflate a "Done"/"Cancel" custom action bar view + ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay, + 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, + mSelectFragment.getSelectedMasterKeyIds()); + msg.setData(data); + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoServiceActivity", e); + } + + finishHandled = true; + finish(); + } + }, R.string.btn_doNotSave, 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(); + } + }); + + 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 { + Log.e(Constants.TAG, "Wrong action!"); + 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(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); + } + } else { + Message msg = Message.obtain(); + msg.arg1 = OpenPgpService.PassphraseActivityCallback.CANCEL; + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoServiceActivity", e); + } + } + + finishHandled = true; + 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 (PgpMain.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); + } + } +} -- cgit v1.2.3