diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2013-10-05 18:35:16 +0200 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2013-10-05 18:35:16 +0200 |
commit | bef6977aade3a901ac17ed1e31de22c8de066921 (patch) | |
tree | acf212a4fdf11391a2e380fd2795fd9573b48df4 | |
parent | c75c00f935faf02e65c1a6cb165ea6cf6b236432 (diff) | |
download | open-keychain-bef6977aade3a901ac17ed1e31de22c8de066921.tar.gz open-keychain-bef6977aade3a901ac17ed1e31de22c8de066921.tar.bz2 open-keychain-bef6977aade3a901ac17ed1e31de22c8de066921.zip |
New API version, import from clipboard
22 files changed, 928 insertions, 193 deletions
diff --git a/OpenPGP-Keychain-API-Demo/res/layout/crypto_provider_demo.xml b/OpenPGP-Keychain-API-Demo/res/layout/crypto_provider_demo.xml index 1c0717d98..9f2a0e6ee 100644 --- a/OpenPGP-Keychain-API-Demo/res/layout/crypto_provider_demo.xml +++ b/OpenPGP-Keychain-API-Demo/res/layout/crypto_provider_demo.xml @@ -26,7 +26,7 @@ <EditText android:id="@+id/crypto_provider_demo_message" android:layout_width="match_parent" - android:layout_height="150dip" + android:layout_height="100dip" android:scrollHorizontally="true" android:scrollbars="vertical" android:text="message" @@ -41,7 +41,7 @@ <EditText android:id="@+id/crypto_provider_demo_ciphertext" android:layout_width="match_parent" - android:layout_height="150dip" + android:layout_height="100dip" android:text="ciphertext" android:textAppearance="@android:style/TextAppearance.Small" /> @@ -67,19 +67,17 @@ <Button android:id="@+id/crypto_provider_demo_encrypt_and_sign" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_weight="1" - android:onClick="encryptAndSignOnClick" - android:text="Encrypt and Sign" /> - - <Button - android:id="@+id/crypto_provider_demo_decrypt_and_verify" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_weight="1" - android:onClick="decryptAndVerifyOnClick" - android:text="Decrypt and Verify" /> + android:onClick="signAndEncryptOnClick" + android:text="Sign and Encrypt" /> </LinearLayout> + <Button + android:id="@+id/crypto_provider_demo_decrypt_and_verify" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:onClick="decryptAndVerifyOnClick" + android:text="Decrypt and Verify" /> + </LinearLayout>
\ No newline at end of file diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpCallback.aidl b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpCallback.aidl index ca00c8ce1..ba41de1ba 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpCallback.aidl +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpCallback.aidl @@ -16,6 +16,7 @@ package org.openintents.openpgp; +import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpError; @@ -24,14 +25,14 @@ interface IOpenPgpCallback { /** * onSuccess returns on successful OpenPGP operations. * - * @param outputBytes - * contains resulting output bytes (decrypted content (when input was encrypted) + * @param output + * contains resulting output (decrypted content (when input was encrypted) * or content without signature (when input was signed-only)) * @param signatureResult * signatureResult is only non-null if decryptAndVerify() was called and the content * was encrypted or signed-and-encrypted. */ - oneway void onSuccess(in byte[] outputBytes, in OpenPgpSignatureResult signatureResult); + oneway void onSuccess(in OpenPgpData output, in OpenPgpSignatureResult signatureResult); /** * onError returns on errors or when allowUserInteraction was set to false, but user interaction diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl new file mode 100644 index 000000000..4ca356fad --- /dev/null +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.OpenPgpError; + +interface IOpenPgpKeyIdsCallback { + + /** + * onSuccess returns on successful getKeyIds operations. + * + * @param keyIds + * returned key ids + */ + oneway void onSuccess(in long[] keyIds); + + /** + * onError returns on errors or when allowUserInteraction was set to false, but user interaction + * was required execute an OpenPGP operation. + * + * @param error + * See OpenPgpError class for more information. + */ + oneway void onError(in OpenPgpError error); +}
\ No newline at end of file diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpService.aidl index ab7ec8b1a..69a608dc6 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpService.aidl +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/IOpenPgpService.aidl @@ -16,7 +16,9 @@ package org.openintents.openpgp; +import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.IOpenPgpCallback; +import org.openintents.openpgp.IOpenPgpKeyIdsCallback; /** * All methods are oneway, which means they are asynchronous and non-blocking. @@ -29,54 +31,76 @@ interface IOpenPgpService { * * After successful encryption, callback's onSuccess will contain the resulting output bytes. * - * @param inputBytes - * Byte array you want to encrypt - * @param encryptionUserIds - * User Ids (emails) of recipients - * @param asciiArmor - * Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param allowUserInteraction - * Allows the OpenPGP Provider to handle missing keys by showing activities + * @param input + * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri + * @param output + * Request output format by defining OpenPgpData object + * + * new OpenPgpData(OpenPgpData.TYPE_STRING) + * Returns as String + * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) + * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) + * Returns as byte[] + * new OpenPgpData(uri) + * Writes output to given Uri + * new OpenPgpData(fileDescriptor) + * Writes output to given ParcelFileDescriptor + * @param keyIds + * Key Ids of recipients. Can be retrieved with getKeyIds() * @param callback * Callback where to return results */ - oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, - in IOpenPgpCallback callback); + oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Sign * * After successful signing, callback's onSuccess will contain the resulting output bytes. * - * @param inputBytes - * Byte array you want to sign - * @param asciiArmor - * Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param allowUserInteraction - * Allows the OpenPGP Provider to handle missing keys by showing activities + * @param input + * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri + * @param output + * Request output format by defining OpenPgpData object + * + * new OpenPgpData(OpenPgpData.TYPE_STRING) + * Returns as String + * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) + * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) + * Returns as byte[] + * new OpenPgpData(uri) + * Writes output to given Uri + * new OpenPgpData(fileDescriptor) + * Writes output to given ParcelFileDescriptor * @param callback * Callback where to return results */ - oneway void sign(in byte[] inputBytes, in boolean asciiArmor, in IOpenPgpCallback callback); + oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); /** * Sign then encrypt * * After successful signing and encryption, callback's onSuccess will contain the resulting output bytes. * - * @param inputBytes - * Byte array you want to sign and encrypt - * @param encryptionUserIds - * User Ids (emails) of recipients - * @param asciiArmor - * Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param allowUserInteraction - * Allows the OpenPGP Provider to handle missing keys by showing activities + * @param input + * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri + * @param output + * Request output format by defining OpenPgpData object + * + * new OpenPgpData(OpenPgpData.TYPE_STRING) + * Returns as String + * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) + * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) + * Returns as byte[] + * new OpenPgpData(uri) + * Writes output to given Uri + * new OpenPgpData(fileDescriptor) + * Writes output to given ParcelFileDescriptor + * @param keyIds + * Key Ids of recipients. Can be retrieved with getKeyIds() * @param callback * Callback where to return results */ - oneway void signAndEncrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, - in IOpenPgpCallback callback); + oneway void signAndEncrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted, @@ -85,15 +109,35 @@ interface IOpenPgpService { * After successful decryption/verification, callback's onSuccess will contain the resulting output bytes. * The signatureResult in onSuccess is only non-null if signed-and-encrypted or signed-only inputBytes were given. * - * @param inputBytes - * Byte array you want to decrypt and verify - * @param allowUserInteraction - * Allows the OpenPGP Provider to handle missing keys by showing activities + * @param input + * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri + * @param output + * Request output format by defining OpenPgpData object + * + * new OpenPgpData(OpenPgpData.TYPE_STRING) + * Returns as String + * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) + * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) + * Returns as byte[] + * new OpenPgpData(uri) + * Writes output to given Uri + * new OpenPgpData(fileDescriptor) + * Writes output to given ParcelFileDescriptor * @param callback * Callback where to return results */ - oneway void decryptAndVerify(in byte[] inputBytes, in IOpenPgpCallback callback); + oneway void decryptAndVerify(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); - boolean isKeyAvailable(in String[] userIds); + /** + * Get available key ids based on given user ids + * + * @param ids + * User Ids (emails) of recipients OR key ids + * @param allowUserInteraction + * Enable user interaction to lookup and import unknown keys + * @param callback + * Callback where to return results (different type than callback in other functions!) + */ + oneway void getKeyIds(in String[] ids, in boolean allowUserInteraction, in IOpenPgpKeyIdsCallback callback); }
\ No newline at end of file diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpData.aidl b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpData.aidl new file mode 100644 index 000000000..3711e4fb4 --- /dev/null +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpData.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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 OpenPgpData so AIDL can find it and knows that it implements the parcelable protocol. +parcelable OpenPgpData;
\ No newline at end of file diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpData.java b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpData.java new file mode 100644 index 000000000..064df0f1e --- /dev/null +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpData.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.net.Uri; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; + +public class OpenPgpData implements Parcelable { + public static final int TYPE_STRING = 0; + public static final int TYPE_BYTE_ARRAY = 1; + public static final int TYPE_FILE_DESCRIPTOR = 2; + public static final int TYPE_URI = 3; + + int type; + + String string; + byte[] bytes = new byte[0]; + ParcelFileDescriptor fileDescriptor; + Uri uri; + + public int getType() { + return type; + } + + public String getString() { + return string; + } + + public byte[] getBytes() { + return bytes; + } + + public ParcelFileDescriptor getFileDescriptor() { + return fileDescriptor; + } + + public Uri getUri() { + return uri; + } + + public OpenPgpData() { + + } + + /** + * Not a real constructor. This can be used to define requested output type. + * + * @param type + */ + public OpenPgpData(int type) { + this.type = type; + } + + public OpenPgpData(String string) { + this.string = string; + this.type = TYPE_STRING; + } + + public OpenPgpData(byte[] bytes) { + this.bytes = bytes; + this.type = TYPE_BYTE_ARRAY; + } + + public OpenPgpData(ParcelFileDescriptor fileDescriptor) { + this.fileDescriptor = fileDescriptor; + this.type = TYPE_FILE_DESCRIPTOR; + } + + public OpenPgpData(Uri uri) { + this.uri = uri; + this.type = TYPE_URI; + } + + public OpenPgpData(OpenPgpData b) { + this.string = b.string; + this.bytes = b.bytes; + this.fileDescriptor = b.fileDescriptor; + this.uri = b.uri; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(string); + dest.writeInt(bytes.length); + dest.writeByteArray(bytes); + dest.writeParcelable(fileDescriptor, 0); + dest.writeParcelable(uri, 0); + } + + public static final Creator<OpenPgpData> CREATOR = new Creator<OpenPgpData>() { + public OpenPgpData createFromParcel(final Parcel source) { + OpenPgpData vr = new OpenPgpData(); + vr.string = source.readString(); + vr.bytes = new byte[source.readInt()]; + source.readByteArray(vr.bytes); + vr.fileDescriptor = source.readParcelable(ParcelFileDescriptor.class.getClassLoader()); + vr.fileDescriptor = source.readParcelable(Uri.class.getClassLoader()); + return vr; + } + + public OpenPgpData[] newArray(final int size) { + return new OpenPgpData[size]; + } + }; + +} diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpListPreference.java b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpListPreference.java index 4d40616dd..551401b18 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpListPreference.java +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpListPreference.java @@ -23,7 +23,9 @@ import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.graphics.drawable.Drawable; import android.preference.DialogPreference; import android.util.AttributeSet; @@ -34,15 +36,17 @@ import android.widget.ListAdapter; import android.widget.TextView; public class OpenPgpListPreference extends DialogPreference { - static final Intent intent = new Intent(IOpenPgpService.class.getName()); - ArrayList<OpenPgpProviderEntry> mProviderList = new ArrayList<OpenPgpProviderEntry>(); private String mSelectedPackage; + public static final int REQUIRED_API_VERSION = 1; + public OpenPgpListPreference(Context context, AttributeSet attrs) { super(context, attrs); - List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0); + List<ResolveInfo> resInfo = + context.getPackageManager().queryIntentServices( + new Intent(IOpenPgpService.class.getName()), PackageManager.GET_META_DATA); if (!resInfo.isEmpty()) { for (ResolveInfo resolveInfo : resInfo) { if (resolveInfo.serviceInfo == null) @@ -52,7 +56,13 @@ public class OpenPgpListPreference extends DialogPreference { String simpleName = String.valueOf(resolveInfo.serviceInfo .loadLabel(context.getPackageManager())); Drawable icon = resolveInfo.serviceInfo.loadIcon(context.getPackageManager()); - mProviderList.add(new OpenPgpProviderEntry(packageName, simpleName, icon)); + + // get api version + ServiceInfo si = resolveInfo.serviceInfo; + int apiVersion = si.metaData.getInt("api_version"); + + mProviderList.add(new OpenPgpProviderEntry(packageName, simpleName, icon, + apiVersion)); } } } @@ -68,8 +78,10 @@ public class OpenPgpListPreference extends DialogPreference { * @param simpleName * @param icon */ - public void addProvider(int position, String packageName, String simpleName, Drawable icon) { - mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon)); + public void addProvider(int position, String packageName, String simpleName, Drawable icon, + int apiVersion) { + mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon, + apiVersion)); } @Override @@ -91,13 +103,23 @@ public class OpenPgpListPreference extends DialogPreference { int dp5 = (int) (5 * getContext().getResources().getDisplayMetrics().density + 0.5f); tv.setCompoundDrawablePadding(dp5); + // disable if it has the wrong api_version + if (mProviderList.get(position).apiVersion == REQUIRED_API_VERSION) { + tv.setEnabled(true); + } else { + tv.setEnabled(false); + tv.setText(tv.getText() + " (API v" + + mProviderList.get(position).apiVersion + ", needs v" + + REQUIRED_API_VERSION + ")"); + } + return v; } }; builder.setSingleChoiceItems(adapter, getIndexOfProviderList(getValue()), new DialogInterface.OnClickListener() { - + @Override public void onClick(DialogInterface dialog, int which) { mSelectedPackage = mProviderList.get(which).packageName; @@ -167,11 +189,14 @@ public class OpenPgpListPreference extends DialogPreference { private String packageName; private String simpleName; private Drawable icon; + private int apiVersion; - public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon) { + public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon, + int apiVersion) { this.packageName = packageName; this.simpleName = simpleName; this.icon = icon; + this.apiVersion = apiVersion; } @Override diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpSignatureResult.java b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpSignatureResult.java index 4446614dd..829f8f8cf 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpSignatureResult.java +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/openpgp/OpenPgpSignatureResult.java @@ -25,40 +25,50 @@ public class OpenPgpSignatureResult implements Parcelable { // successfully verified signature, with trusted public key public static final int SIGNATURE_SUCCESS_TRUSTED = 1; // no public key was found for this signature verification + // you can retrieve the key with + // getKeys(new String[] {String.valueOf(signatureResult.getKeyId)}, true, callback) public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2; // successfully verified signature, but with untrusted public key public static final int SIGNATURE_SUCCESS_UNTRUSTED = 3; - int signatureStatus; - String signatureUserId; + int status; boolean signatureOnly; + String userId; + long keyId; - public int getSignatureStatus() { - return signatureStatus; - } - - public String getSignatureUserId() { - return signatureUserId; + public int getStatus() { + return status; } public boolean isSignatureOnly() { return signatureOnly; } + public String getUserId() { + return userId; + } + + public long getKeyId() { + return keyId; + } + public OpenPgpSignatureResult() { } - public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, boolean signatureOnly) { - this.signatureStatus = signatureStatus; - this.signatureUserId = signatureUserId; + public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, + boolean signatureOnly, long keyId) { + this.status = signatureStatus; this.signatureOnly = signatureOnly; + this.userId = signatureUserId; + this.keyId = keyId; } public OpenPgpSignatureResult(OpenPgpSignatureResult b) { - this.signatureStatus = b.signatureStatus; - this.signatureUserId = b.signatureUserId; + this.status = b.status; + this.userId = b.userId; this.signatureOnly = b.signatureOnly; + this.keyId = b.keyId; } public int describeContents() { @@ -66,17 +76,19 @@ public class OpenPgpSignatureResult implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(signatureStatus); - dest.writeString(signatureUserId); + dest.writeInt(status); dest.writeByte((byte) (signatureOnly ? 1 : 0)); + dest.writeString(userId); + dest.writeLong(keyId); } public static final Creator<OpenPgpSignatureResult> CREATOR = new Creator<OpenPgpSignatureResult>() { public OpenPgpSignatureResult createFromParcel(final Parcel source) { OpenPgpSignatureResult vr = new OpenPgpSignatureResult(); - vr.signatureStatus = source.readInt(); - vr.signatureUserId = source.readString(); + vr.status = source.readInt(); vr.signatureOnly = source.readByte() == 1; + vr.userId = source.readString(); + vr.keyId = source.readLong(); return vr; } @@ -88,9 +100,10 @@ public class OpenPgpSignatureResult implements Parcelable { @Override public String toString() { String out = new String(); - out += "\nsignatureStatus: " + signatureStatus; - out += "\nsignatureUserId: " + signatureUserId; + out += "\nstatus: " + status; + out += "\nuserId: " + userId; out += "\nsignatureOnly: " + signatureOnly; + out += "\nkeyId: " + keyId; return out; } diff --git a/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/Constants.java b/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/Constants.java index dc54fc9e7..03e76254c 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/Constants.java +++ b/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/Constants.java @@ -20,6 +20,6 @@ public final class Constants { public static final boolean DEBUG = BuildConfig.DEBUG; - public static final String TAG = "Keychain API"; + public static final String TAG = "Keychain"; } diff --git a/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java b/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java index 8f56c124a..4a96de5a1 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java +++ b/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/OpenPgpProviderActivity.java @@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.demo; import java.util.ArrayList; import java.util.List; +import org.openintents.openpgp.IOpenPgpKeyIdsCallback; +import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpServiceConnection; import org.openintents.openpgp.OpenPgpSignatureResult; @@ -66,12 +68,75 @@ public class OpenPgpProviderActivity extends Activity { } /** - * Callback from remote crypto service + * Callback from remote openpgp service */ + final IOpenPgpKeyIdsCallback.Stub getKeysEncryptCallback = new IOpenPgpKeyIdsCallback.Stub() { + + @Override + public void onSuccess(final long[] keyIds) throws RemoteException { + Log.d(Constants.TAG, "getKeysEncryptCallback keyId " + keyIds[0]); + mActivity.runOnUiThread(new Runnable() { + + @Override + public void run() { + // encrypt after getting key ids + String inputStr = mMessage.getText().toString(); + OpenPgpData input = new OpenPgpData(inputStr); + + Log.d(Constants.TAG, "getKeysEncryptCallback inputStr " + inputStr); + + try { + mCryptoServiceConnection.getService().encrypt(input, + new OpenPgpData(OpenPgpData.TYPE_STRING), keyIds, encryptCallback); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoProviderDemo", e); + } + } + }); + } + + @Override + public void onError(OpenPgpError error) throws RemoteException { + handleError(error); + } + + }; + + final IOpenPgpKeyIdsCallback.Stub getKeysSignAndEncryptCallback = new IOpenPgpKeyIdsCallback.Stub() { + + @Override + public void onSuccess(final long[] keyIds) throws RemoteException { + Log.d(Constants.TAG, "getKeysSignAndEncryptCallback keyId " + keyIds[0]); + + mActivity.runOnUiThread(new Runnable() { + + @Override + public void run() { + // encrypt after getting key ids + String inputStr = mMessage.getText().toString(); + OpenPgpData input = new OpenPgpData(inputStr); + + try { + mCryptoServiceConnection.getService().signAndEncrypt(input, + new OpenPgpData(OpenPgpData.TYPE_STRING), keyIds, encryptCallback); + } catch (RemoteException e) { + Log.e(Constants.TAG, "CryptoProviderDemo", e); + } + } + }); + } + + @Override + public void onError(OpenPgpError error) throws RemoteException { + handleError(error); + } + + }; + final IOpenPgpCallback.Stub encryptCallback = new IOpenPgpCallback.Stub() { @Override - public void onSuccess(final byte[] outputBytes, OpenPgpSignatureResult signatureResult) + public void onSuccess(final OpenPgpData output, OpenPgpSignatureResult signatureResult) throws RemoteException { Log.d(Constants.TAG, "encryptCallback"); @@ -79,7 +144,7 @@ public class OpenPgpProviderActivity extends Activity { @Override public void run() { - mCiphertext.setText(new String(outputBytes)); + mCiphertext.setText(output.getString()); } }); } @@ -94,7 +159,7 @@ public class OpenPgpProviderActivity extends Activity { final IOpenPgpCallback.Stub decryptAndVerifyCallback = new IOpenPgpCallback.Stub() { @Override - public void onSuccess(final byte[] outputBytes, final OpenPgpSignatureResult signatureResult) + public void onSuccess(final OpenPgpData output, final OpenPgpSignatureResult signatureResult) throws RemoteException { Log.d(Constants.TAG, "decryptAndVerifyCallback"); @@ -102,7 +167,7 @@ public class OpenPgpProviderActivity extends Activity { @Override public void run() { - mMessage.setText(new String(outputBytes)); + mMessage.setText(output.getString()); if (signatureResult != null) { Toast.makeText(OpenPgpProviderActivity.this, "signature result:\n" + signatureResult.toString(), @@ -135,43 +200,43 @@ public class OpenPgpProviderActivity extends Activity { } public void encryptOnClick(View view) { - byte[] inputBytes = mMessage.getText().toString().getBytes(); - try { - mCryptoServiceConnection.getService().encrypt(inputBytes, - mEncryptUserIds.getText().toString().split(","), true, encryptCallback); + mCryptoServiceConnection.getService().getKeyIds( + mEncryptUserIds.getText().toString().split(","), true, getKeysEncryptCallback); } catch (RemoteException e) { Log.e(Constants.TAG, "CryptoProviderDemo", e); } } public void signOnClick(View view) { - byte[] inputBytes = mMessage.getText().toString().getBytes(); + String inputStr = mMessage.getText().toString(); + OpenPgpData input = new OpenPgpData(inputStr); try { - mCryptoServiceConnection.getService().sign(inputBytes, true, encryptCallback); + mCryptoServiceConnection.getService().sign(input, + new OpenPgpData(OpenPgpData.TYPE_STRING), encryptCallback); } catch (RemoteException e) { Log.e(Constants.TAG, "CryptoProviderDemo", e); } } - public void encryptAndSignOnClick(View view) { - byte[] inputBytes = mMessage.getText().toString().getBytes(); - + public void signAndEncryptOnClick(View view) { try { - mCryptoServiceConnection.getService().signAndEncrypt(inputBytes, - mEncryptUserIds.getText().toString().split(","), true, encryptCallback); + mCryptoServiceConnection.getService().getKeyIds( + mEncryptUserIds.getText().toString().split(","), true, + getKeysSignAndEncryptCallback); } catch (RemoteException e) { Log.e(Constants.TAG, "CryptoProviderDemo", e); } } public void decryptAndVerifyOnClick(View view) { - byte[] inputBytes = mCiphertext.getText().toString().getBytes(); + String inputStr = mCiphertext.getText().toString(); + OpenPgpData input = new OpenPgpData(inputStr); try { - mCryptoServiceConnection.getService().decryptAndVerify(inputBytes, - decryptAndVerifyCallback); + mCryptoServiceConnection.getService().decryptAndVerify(input, + new OpenPgpData(OpenPgpData.TYPE_STRING), decryptAndVerifyCallback); } catch (RemoteException e) { Log.e(Constants.TAG, "CryptoProviderDemo", e); } diff --git a/OpenPGP-Keychain/res/layout/import_keys_clipboard_fragment.xml b/OpenPGP-Keychain/res/layout/import_keys_clipboard_fragment.xml new file mode 100644 index 000000000..bb3b8a1cb --- /dev/null +++ b/OpenPGP-Keychain/res/layout/import_keys_clipboard_fragment.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <Button + android:id="@+id/import_clipboard_button" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/import_from_clipboard" /> + +</LinearLayout>
\ No newline at end of file diff --git a/OpenPGP-Keychain/res/values/arrays.xml b/OpenPGP-Keychain/res/values/arrays.xml index dc9de0f38..aca70c488 100644 --- a/OpenPGP-Keychain/res/values/arrays.xml +++ b/OpenPGP-Keychain/res/values/arrays.xml @@ -53,6 +53,7 @@ <item>@string/menu_importFromFile</item> <item>@string/menu_keyServer</item> <item>@string/menu_importFromQrCode</item> + <item>@string/import_from_clipboard</item> <item>@string/menu_importFromNfc</item> </string-array> diff --git a/OpenPGP-Keychain/res/values/strings.xml b/OpenPGP-Keychain/res/values/strings.xml index f8d1f6216..fb799cd14 100644 --- a/OpenPGP-Keychain/res/values/strings.xml +++ b/OpenPGP-Keychain/res/values/strings.xml @@ -351,6 +351,7 @@ <string name="import_import">Import selected keys</string> <string name="import_sign_and_upload">Import, Sign, and upload selected keys</string> <string name="import_finish">Finish</string> + <string name="import_from_clipboard">Import from Clipboard</string> <!-- Intent labels --> <string name="intent_decrypt_file">OpenPGP: Decrypt File</string> diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl index ca00c8ce1..ba41de1ba 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpCallback.aidl @@ -16,6 +16,7 @@ package org.openintents.openpgp; +import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpError; @@ -24,14 +25,14 @@ interface IOpenPgpCallback { /** * onSuccess returns on successful OpenPGP operations. * - * @param outputBytes - * contains resulting output bytes (decrypted content (when input was encrypted) + * @param output + * contains resulting output (decrypted content (when input was encrypted) * or content without signature (when input was signed-only)) * @param signatureResult * signatureResult is only non-null if decryptAndVerify() was called and the content * was encrypted or signed-and-encrypted. */ - oneway void onSuccess(in byte[] outputBytes, in OpenPgpSignatureResult signatureResult); + oneway void onSuccess(in OpenPgpData output, in OpenPgpSignatureResult signatureResult); /** * onError returns on errors or when allowUserInteraction was set to false, but user interaction diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl new file mode 100644 index 000000000..4ca356fad --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpKeyIdsCallback.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.OpenPgpError; + +interface IOpenPgpKeyIdsCallback { + + /** + * onSuccess returns on successful getKeyIds operations. + * + * @param keyIds + * returned key ids + */ + oneway void onSuccess(in long[] keyIds); + + /** + * onError returns on errors or when allowUserInteraction was set to false, but user interaction + * was required execute an OpenPGP operation. + * + * @param error + * See OpenPgpError class for more information. + */ + 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 index ab7ec8b1a..69a608dc6 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl @@ -16,7 +16,9 @@ package org.openintents.openpgp; +import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.IOpenPgpCallback; +import org.openintents.openpgp.IOpenPgpKeyIdsCallback; /** * All methods are oneway, which means they are asynchronous and non-blocking. @@ -29,54 +31,76 @@ interface IOpenPgpService { * * After successful encryption, callback's onSuccess will contain the resulting output bytes. * - * @param inputBytes - * Byte array you want to encrypt - * @param encryptionUserIds - * User Ids (emails) of recipients - * @param asciiArmor - * Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param allowUserInteraction - * Allows the OpenPGP Provider to handle missing keys by showing activities + * @param input + * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri + * @param output + * Request output format by defining OpenPgpData object + * + * new OpenPgpData(OpenPgpData.TYPE_STRING) + * Returns as String + * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) + * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) + * Returns as byte[] + * new OpenPgpData(uri) + * Writes output to given Uri + * new OpenPgpData(fileDescriptor) + * Writes output to given ParcelFileDescriptor + * @param keyIds + * Key Ids of recipients. Can be retrieved with getKeyIds() * @param callback * Callback where to return results */ - oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, - in IOpenPgpCallback callback); + oneway void encrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Sign * * After successful signing, callback's onSuccess will contain the resulting output bytes. * - * @param inputBytes - * Byte array you want to sign - * @param asciiArmor - * Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param allowUserInteraction - * Allows the OpenPGP Provider to handle missing keys by showing activities + * @param input + * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri + * @param output + * Request output format by defining OpenPgpData object + * + * new OpenPgpData(OpenPgpData.TYPE_STRING) + * Returns as String + * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) + * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) + * Returns as byte[] + * new OpenPgpData(uri) + * Writes output to given Uri + * new OpenPgpData(fileDescriptor) + * Writes output to given ParcelFileDescriptor * @param callback * Callback where to return results */ - oneway void sign(in byte[] inputBytes, in boolean asciiArmor, in IOpenPgpCallback callback); + oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); /** * Sign then encrypt * * After successful signing and encryption, callback's onSuccess will contain the resulting output bytes. * - * @param inputBytes - * Byte array you want to sign and encrypt - * @param encryptionUserIds - * User Ids (emails) of recipients - * @param asciiArmor - * Encode result for ASCII (Radix-64, 33 percent overhead compared to binary) - * @param allowUserInteraction - * Allows the OpenPGP Provider to handle missing keys by showing activities + * @param input + * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri + * @param output + * Request output format by defining OpenPgpData object + * + * new OpenPgpData(OpenPgpData.TYPE_STRING) + * Returns as String + * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) + * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) + * Returns as byte[] + * new OpenPgpData(uri) + * Writes output to given Uri + * new OpenPgpData(fileDescriptor) + * Writes output to given ParcelFileDescriptor + * @param keyIds + * Key Ids of recipients. Can be retrieved with getKeyIds() * @param callback * Callback where to return results */ - oneway void signAndEncrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, - in IOpenPgpCallback callback); + oneway void signAndEncrypt(in OpenPgpData input, in OpenPgpData output, in long[] keyIds, in IOpenPgpCallback callback); /** * Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted, @@ -85,15 +109,35 @@ interface IOpenPgpService { * After successful decryption/verification, callback's onSuccess will contain the resulting output bytes. * The signatureResult in onSuccess is only non-null if signed-and-encrypted or signed-only inputBytes were given. * - * @param inputBytes - * Byte array you want to decrypt and verify - * @param allowUserInteraction - * Allows the OpenPGP Provider to handle missing keys by showing activities + * @param input + * OpenPgpData object containing String, byte[], ParcelFileDescriptor, or Uri + * @param output + * Request output format by defining OpenPgpData object + * + * new OpenPgpData(OpenPgpData.TYPE_STRING) + * Returns as String + * (OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) + * new OpenPgpData(OpenPgpData.TYPE_BYTE_ARRAY) + * Returns as byte[] + * new OpenPgpData(uri) + * Writes output to given Uri + * new OpenPgpData(fileDescriptor) + * Writes output to given ParcelFileDescriptor * @param callback * Callback where to return results */ - oneway void decryptAndVerify(in byte[] inputBytes, in IOpenPgpCallback callback); + oneway void decryptAndVerify(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); - boolean isKeyAvailable(in String[] userIds); + /** + * Get available key ids based on given user ids + * + * @param ids + * User Ids (emails) of recipients OR key ids + * @param allowUserInteraction + * Enable user interaction to lookup and import unknown keys + * @param callback + * Callback where to return results (different type than callback in other functions!) + */ + oneway void getKeyIds(in String[] ids, in boolean allowUserInteraction, in IOpenPgpKeyIdsCallback callback); }
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.aidl new file mode 100644 index 000000000..3711e4fb4 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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 OpenPgpData so AIDL can find it and knows that it implements the parcelable protocol. +parcelable OpenPgpData;
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.java new file mode 100644 index 000000000..064df0f1e --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpData.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.net.Uri; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; + +public class OpenPgpData implements Parcelable { + public static final int TYPE_STRING = 0; + public static final int TYPE_BYTE_ARRAY = 1; + public static final int TYPE_FILE_DESCRIPTOR = 2; + public static final int TYPE_URI = 3; + + int type; + + String string; + byte[] bytes = new byte[0]; + ParcelFileDescriptor fileDescriptor; + Uri uri; + + public int getType() { + return type; + } + + public String getString() { + return string; + } + + public byte[] getBytes() { + return bytes; + } + + public ParcelFileDescriptor getFileDescriptor() { + return fileDescriptor; + } + + public Uri getUri() { + return uri; + } + + public OpenPgpData() { + + } + + /** + * Not a real constructor. This can be used to define requested output type. + * + * @param type + */ + public OpenPgpData(int type) { + this.type = type; + } + + public OpenPgpData(String string) { + this.string = string; + this.type = TYPE_STRING; + } + + public OpenPgpData(byte[] bytes) { + this.bytes = bytes; + this.type = TYPE_BYTE_ARRAY; + } + + public OpenPgpData(ParcelFileDescriptor fileDescriptor) { + this.fileDescriptor = fileDescriptor; + this.type = TYPE_FILE_DESCRIPTOR; + } + + public OpenPgpData(Uri uri) { + this.uri = uri; + this.type = TYPE_URI; + } + + public OpenPgpData(OpenPgpData b) { + this.string = b.string; + this.bytes = b.bytes; + this.fileDescriptor = b.fileDescriptor; + this.uri = b.uri; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(string); + dest.writeInt(bytes.length); + dest.writeByteArray(bytes); + dest.writeParcelable(fileDescriptor, 0); + dest.writeParcelable(uri, 0); + } + + public static final Creator<OpenPgpData> CREATOR = new Creator<OpenPgpData>() { + public OpenPgpData createFromParcel(final Parcel source) { + OpenPgpData vr = new OpenPgpData(); + vr.string = source.readString(); + vr.bytes = new byte[source.readInt()]; + source.readByteArray(vr.bytes); + vr.fileDescriptor = source.readParcelable(ParcelFileDescriptor.class.getClassLoader()); + vr.fileDescriptor = source.readParcelable(Uri.class.getClassLoader()); + return vr; + } + + public OpenPgpData[] newArray(final int size) { + return new OpenPgpData[size]; + } + }; + +} diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java index 4446614dd..829f8f8cf 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpSignatureResult.java @@ -25,40 +25,50 @@ public class OpenPgpSignatureResult implements Parcelable { // successfully verified signature, with trusted public key public static final int SIGNATURE_SUCCESS_TRUSTED = 1; // no public key was found for this signature verification + // you can retrieve the key with + // getKeys(new String[] {String.valueOf(signatureResult.getKeyId)}, true, callback) public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2; // successfully verified signature, but with untrusted public key public static final int SIGNATURE_SUCCESS_UNTRUSTED = 3; - int signatureStatus; - String signatureUserId; + int status; boolean signatureOnly; + String userId; + long keyId; - public int getSignatureStatus() { - return signatureStatus; - } - - public String getSignatureUserId() { - return signatureUserId; + public int getStatus() { + return status; } public boolean isSignatureOnly() { return signatureOnly; } + public String getUserId() { + return userId; + } + + public long getKeyId() { + return keyId; + } + public OpenPgpSignatureResult() { } - public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, boolean signatureOnly) { - this.signatureStatus = signatureStatus; - this.signatureUserId = signatureUserId; + public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, + boolean signatureOnly, long keyId) { + this.status = signatureStatus; this.signatureOnly = signatureOnly; + this.userId = signatureUserId; + this.keyId = keyId; } public OpenPgpSignatureResult(OpenPgpSignatureResult b) { - this.signatureStatus = b.signatureStatus; - this.signatureUserId = b.signatureUserId; + this.status = b.status; + this.userId = b.userId; this.signatureOnly = b.signatureOnly; + this.keyId = b.keyId; } public int describeContents() { @@ -66,17 +76,19 @@ public class OpenPgpSignatureResult implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(signatureStatus); - dest.writeString(signatureUserId); + dest.writeInt(status); dest.writeByte((byte) (signatureOnly ? 1 : 0)); + dest.writeString(userId); + dest.writeLong(keyId); } public static final Creator<OpenPgpSignatureResult> CREATOR = new Creator<OpenPgpSignatureResult>() { public OpenPgpSignatureResult createFromParcel(final Parcel source) { OpenPgpSignatureResult vr = new OpenPgpSignatureResult(); - vr.signatureStatus = source.readInt(); - vr.signatureUserId = source.readString(); + vr.status = source.readInt(); vr.signatureOnly = source.readByte() == 1; + vr.userId = source.readString(); + vr.keyId = source.readLong(); return vr; } @@ -88,9 +100,10 @@ public class OpenPgpSignatureResult implements Parcelable { @Override public String toString() { String out = new String(); - out += "\nsignatureStatus: " + signatureStatus; - out += "\nsignatureUserId: " + signatureUserId; + out += "\nstatus: " + status; + out += "\nuserId: " + userId; out += "\nsignatureOnly: " + signatureOnly; + out += "\nkeyId: " + keyId; return out; } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java index 50e49a2ab..9f302459c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java @@ -25,9 +25,12 @@ import java.util.ArrayList; import java.util.regex.Matcher; import org.openintents.openpgp.IOpenPgpCallback; +import org.openintents.openpgp.IOpenPgpKeyIdsCallback; import org.openintents.openpgp.IOpenPgpService; +import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; +import org.spongycastle.util.Arrays; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; @@ -114,8 +117,8 @@ public class OpenPgpService extends RemoteService { * @param encryptionUserIds * @return */ - private long[] getKeyIdsFromEmails(String[] encryptionUserIds, long ownKeyId, - boolean allowUserInteraction) throws UserInteractionRequiredException { + private long[] getKeyIdsFromEmails(String[] encryptionUserIds, boolean allowUserInteraction) + throws UserInteractionRequiredException { // find key ids to given emails in database ArrayList<Long> keyIds = new ArrayList<Long>(); @@ -142,9 +145,6 @@ public class OpenPgpService extends RemoteService { } } - // 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++) { @@ -215,24 +215,47 @@ public class OpenPgpService extends RemoteService { } }; - private synchronized void encryptAndSignSafe(byte[] inputBytes, String[] encryptionUserIds, - boolean asciiArmor, boolean allowUserInteraction, IOpenPgpCallback callback, - AppSettings appSettings, boolean sign) { + private synchronized void getKeyIdsSafe(String[] userIds, boolean allowUserInteraction, + IOpenPgpKeyIdsCallback callback, AppSettings appSettings) { try { + long[] keyIds = getKeyIdsFromEmails(userIds, allowUserInteraction); + if (keyIds == null) { + throw new NoUserIdsException("No user ids!"); + } + + callback.onSuccess(keyIds); + } catch (UserInteractionRequiredException e) { + callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); + } catch (NoUserIdsException e) { + callbackOpenPgpError(callback, OpenPgpError.NO_USER_IDS, e.getMessage()); + } catch (Exception e) { + callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage()); + } + } + + private synchronized void encryptAndSignSafe(OpenPgpData inputData, + final OpenPgpData outputData, long[] keyIds, boolean allowUserInteraction, + IOpenPgpCallback callback, AppSettings appSettings, boolean sign) { + try { + // TODO: other options of OpenPgpData! + byte[] inputBytes = getInput(inputData); + boolean asciiArmor = false; + if (outputData.getType() == OpenPgpData.TYPE_STRING) { + asciiArmor = true; + } + + // add own key for encryption + keyIds = Arrays.copyOf(keyIds, keyIds.length + 1); + keyIds[keyIds.length - 1] = appSettings.getKeyId(); + // build InputData and write into OutputStream InputStream inputStream = new ByteArrayInputStream(inputBytes); long inputLength = inputBytes.length; - InputData inputData = new InputData(inputStream, inputLength); + InputData inputDt = new InputData(inputStream, inputLength); OutputStream outputStream = new ByteArrayOutputStream(); - long[] keyIds = getKeyIdsFromEmails(encryptionUserIds, appSettings.getKeyId(), - allowUserInteraction); - if (keyIds == null) { - throw new NoUserIdsException("No user ids!"); - } - - PgpOperation operation = new PgpOperation(getContext(), null, inputData, outputStream); + PgpOperation operation = new PgpOperation(getContext(), null, inputDt, outputStream); if (sign) { String passphrase = getCachedPassphrase(appSettings.getKeyId(), allowUserInteraction); @@ -253,12 +276,17 @@ public class OpenPgpService extends RemoteService { byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); + OpenPgpData output = null; + if (asciiArmor) { + output = new OpenPgpData(new String(outputBytes)); + } else { + output = new OpenPgpData(outputBytes); + } + // return over handler on client side - callback.onSuccess(outputBytes, null); + callback.onSuccess(output, null); } catch (UserInteractionRequiredException e) { callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); - } catch (NoUserIdsException e) { - callbackOpenPgpError(callback, OpenPgpError.NO_USER_IDS, e.getMessage()); } catch (WrongPassphraseException e) { callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage()); } catch (Exception e) { @@ -289,9 +317,10 @@ public class OpenPgpService extends RemoteService { outputStream.close(); byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); + OpenPgpData output = new OpenPgpData(new String(outputBytes)); // return over handler on client side - callback.onSuccess(outputBytes, null); + callback.onSuccess(output, null); } catch (UserInteractionRequiredException e) { callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); } catch (WrongPassphraseException e) { @@ -406,8 +435,8 @@ public class OpenPgpService extends RemoteService { OpenPgpSignatureResult sigResult = null; if (signature) { - // long signatureKeyId = outputBundle - // .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); + long signatureKeyId = outputBundle + .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); String signatureUserId = outputBundle .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); boolean signatureSuccess = outputBundle @@ -422,11 +451,13 @@ public class OpenPgpService extends RemoteService { signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY; } - sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId, signedOnly); + sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId, + signedOnly, signatureKeyId); } + OpenPgpData output = new OpenPgpData(new String(outputBytes)); // return over handler on client side - callback.onSuccess(outputBytes, sigResult); + callback.onSuccess(output, sigResult); } catch (UserInteractionRequiredException e) { callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); } catch (WrongPassphraseException e) { @@ -452,18 +483,26 @@ public class OpenPgpService extends RemoteService { } } + private void callbackOpenPgpError(IOpenPgpKeyIdsCallback callback, int errorId, String message) { + try { + callback.onError(new OpenPgpError(0, message)); + } catch (Exception t) { + Log.e(Constants.TAG, + "Exception while returning OpenPgpError to client via callback.onError()", t); + } + } + 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 { + public void encrypt(final OpenPgpData input, final OpenPgpData output, final long[] keyIds, + final IOpenPgpCallback callback) throws RemoteException { final AppSettings settings = getAppSettings(); Runnable r = new Runnable() { @Override public void run() { - encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, true, callback, - settings, false); + encryptAndSignSafe(input, output, keyIds, true, callback, settings, false); } }; @@ -471,15 +510,14 @@ public class OpenPgpService extends RemoteService { } @Override - public void signAndEncrypt(final byte[] inputBytes, final String[] encryptionUserIds, - final boolean asciiArmor, final IOpenPgpCallback callback) throws RemoteException { + public void signAndEncrypt(final OpenPgpData input, final OpenPgpData output, + final long[] keyIds, final IOpenPgpCallback callback) throws RemoteException { final AppSettings settings = getAppSettings(); Runnable r = new Runnable() { @Override public void run() { - encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, true, callback, - settings, true); + encryptAndSignSafe(input, output, keyIds, true, callback, settings, true); } }; @@ -487,14 +525,14 @@ public class OpenPgpService extends RemoteService { } @Override - public void sign(final byte[] inputBytes, boolean asciiArmor, + public void sign(final OpenPgpData input, final OpenPgpData output, final IOpenPgpCallback callback) throws RemoteException { final AppSettings settings = getAppSettings(); Runnable r = new Runnable() { @Override public void run() { - signSafe(inputBytes, true, callback, settings); + signSafe(getInput(input), true, callback, settings); } }; @@ -502,15 +540,15 @@ public class OpenPgpService extends RemoteService { } @Override - public void decryptAndVerify(final byte[] inputBytes, final IOpenPgpCallback callback) - throws RemoteException { + public void decryptAndVerify(final OpenPgpData input, final OpenPgpData output, + final IOpenPgpCallback callback) throws RemoteException { final AppSettings settings = getAppSettings(); Runnable r = new Runnable() { @Override public void run() { - decryptAndVerifySafe(inputBytes, true, callback, settings); + decryptAndVerifySafe(getInput(input), true, callback, settings); } }; @@ -518,13 +556,44 @@ public class OpenPgpService extends RemoteService { } @Override - public boolean isKeyAvailable(String[] userIds) throws RemoteException { - // TODO - return false; + public void getKeyIds(final String[] userIds, final boolean allowUserInteraction, + final IOpenPgpKeyIdsCallback callback) throws RemoteException { + + final AppSettings settings = getAppSettings(); + + Runnable r = new Runnable() { + @Override + public void run() { + getKeyIdsSafe(userIds, allowUserInteraction, callback, settings); + } + }; + + checkAndEnqueue(r); } }; + private static byte[] getInput(OpenPgpData data) { + // TODO: support Uri and ParcelFileDescriptor + + byte[] inBytes = null; + switch (data.getType()) { + case OpenPgpData.TYPE_STRING: + inBytes = data.getString().getBytes(); + break; + + case OpenPgpData.TYPE_BYTE_ARRAY: + inBytes = data.getBytes(); + break; + + default: + Log.e(Constants.TAG, "Uri and ParcelFileDescriptor not supported right now!"); + break; + } + + return inBytes; + } + @Override public IBinder onBind(Intent intent) { return mBinder; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 132e644bc..b9348cdaf 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -166,7 +166,7 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa mListFragment = ImportKeysListFragment.newInstance(bytes, filename); // Add the fragment to the 'fragment_container' FrameLayout - // NOTE: We use commitAllowingStateLoss() to prevent wierd crashes! + // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! getSupportFragmentManager().beginTransaction() .replace(R.id.import_keys_list_container, mListFragment) .commitAllowingStateLoss(); @@ -189,6 +189,9 @@ public class ImportKeysActivity extends SherlockFragmentActivity implements OnNa loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[itemPosition]); break; case 3: + loadFragment(ImportKeysClipboardFragment.class, null, mNavigationStrings[itemPosition]); + break; + case 4: loadFragment(ImportKeysNFCFragment.class, null, mNavigationStrings[itemPosition]); break; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java new file mode 100644 index 000000000..dcb7dbcc6 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.Button; + +public class ImportKeysClipboardFragment extends Fragment { + + private ImportKeysActivity mImportActivity; + private Button mButton; + + /** + * Creates new instance of this fragment + */ + public static ImportKeysClipboardFragment newInstance() { + ImportKeysClipboardFragment frag = new ImportKeysClipboardFragment(); + + Bundle args = new Bundle(); + frag.setArguments(args); + + return frag; + } + + /** + * Inflate the layout for this fragment + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.import_keys_clipboard_fragment, container, false); + + mButton = (Button) view.findViewById(R.id.import_clipboard_button); + mButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); + + mImportActivity.loadCallback(clipboardText.toString().getBytes(), null); + } + }); + + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mImportActivity = (ImportKeysActivity) getActivity(); + } + +} |