From 74fdbb7859e9a9b03ed1b28cdc8250683803c083 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 27 Jan 2015 12:14:56 +0100 Subject: [PATCH] Update openpgp-api-library to latest version --- .../com/fsck/k9/view/MessageOpenPgpView.java | 6 +- .../openpgp-api-library/AndroidManifest.xml | 2 +- plugins/openpgp-api-library/README.md | 21 +++ .../openpgp-api-library/project.properties | 15 ++ .../res/values-cs/strings.xml | 5 + .../res/values-de/strings.xml | 5 + .../res/values-es/strings.xml | 5 + .../res/values-et/strings.xml | 2 + .../res/values-fi/strings.xml | 2 + .../res/values-fr/strings.xml | 5 + .../res/values-is/strings.xml | 2 + .../res/values-it/strings.xml | 5 + .../res/values-ja/strings.xml | 5 + .../res/values-nl/strings.xml | 2 + .../res/values-pl/strings.xml | 2 + .../res/values-pt/strings.xml | 2 + .../res/values-ru/strings.xml | 5 + .../res/values-sl/strings.xml | 5 + .../res/values-tr/strings.xml | 2 + .../res/values-uk/strings.xml | 5 + .../res/values-zh/strings.xml | 2 + .../openintents/openpgp/OpenPgpMetadata.java | 132 +++++++++++++ .../openpgp/OpenPgpSignatureResult.java | 62 ++++-- .../openintents/openpgp/util/OpenPgpApi.java | 177 ++++++++++++------ .../openpgp/util/OpenPgpListPreference.java | 26 ++- .../util/OpenPgpServiceConnection.java | 66 +++++-- .../openpgp/util/OpenPgpUtils.java | 12 ++ .../util/ParcelFileDescriptorUtil.java | 7 +- 28 files changed, 487 insertions(+), 100 deletions(-) create mode 100644 plugins/openpgp-api-library/README.md create mode 100644 plugins/openpgp-api-library/project.properties create mode 100644 plugins/openpgp-api-library/res/values-cs/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-de/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-es/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-et/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-fi/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-fr/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-is/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-it/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-ja/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-nl/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-pl/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-pt/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-ru/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-sl/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-tr/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-uk/strings.xml create mode 100644 plugins/openpgp-api-library/res/values-zh/strings.xml create mode 100644 plugins/openpgp-api-library/src/org/openintents/openpgp/OpenPgpMetadata.java diff --git a/k9mail/src/main/java/com/fsck/k9/view/MessageOpenPgpView.java b/k9mail/src/main/java/com/fsck/k9/view/MessageOpenPgpView.java index 3c0e857da..9e09e5394 100644 --- a/k9mail/src/main/java/com/fsck/k9/view/MessageOpenPgpView.java +++ b/k9mail/src/main/java/com/fsck/k9/view/MessageOpenPgpView.java @@ -160,13 +160,13 @@ public class MessageOpenPgpView extends LinearLayout { R.color.openpgp_green)); mGetKeyButton.setVisibility(View.GONE); - mSignatureUserId.setText(signatureResult.getUserId()); + mSignatureUserId.setText(signatureResult.getPrimaryUserId()); mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); mSignatureLayout.setVisibility(View.VISIBLE); break; - case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: + case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING: if (signatureResult.isSignatureOnly()) { mText.setText(R.string.openpgp_signature_unknown_text); } @@ -194,7 +194,7 @@ public class MessageOpenPgpView extends LinearLayout { R.color.openpgp_orange)); mGetKeyButton.setVisibility(View.GONE); - mSignatureUserId.setText(signatureResult.getUserId()); + mSignatureUserId.setText(signatureResult.getPrimaryUserId()); mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); mSignatureLayout.setVisibility(View.VISIBLE); diff --git a/plugins/openpgp-api-library/AndroidManifest.xml b/plugins/openpgp-api-library/AndroidManifest.xml index c65fdfdd4..98cb89faa 100644 --- a/plugins/openpgp-api-library/AndroidManifest.xml +++ b/plugins/openpgp-api-library/AndroidManifest.xml @@ -6,7 +6,7 @@ + android:targetSdkVersion="19" /> diff --git a/plugins/openpgp-api-library/README.md b/plugins/openpgp-api-library/README.md new file mode 100644 index 000000000..aefc9ed34 --- /dev/null +++ b/plugins/openpgp-api-library/README.md @@ -0,0 +1,21 @@ +# OpenPGP API library + +The OpenPGP API provides methods to execute OpenPGP operations, such as sign, encrypt, decrypt, verify, and more without user interaction from background threads. This is done by connecting your client application to a remote service provided by [OpenKeychain](http://www.openkeychain.org) or other OpenPGP providers. + +For usage instructions, please consult our Wiki page about the [OpenPGP API](https://github.com/open-keychain/open-keychain/wiki/OpenPGP-API). + +License +======= + + 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. + diff --git a/plugins/openpgp-api-library/project.properties b/plugins/openpgp-api-library/project.properties new file mode 100644 index 000000000..91d2b0246 --- /dev/null +++ b/plugins/openpgp-api-library/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-19 +android.library=true diff --git a/plugins/openpgp-api-library/res/values-cs/strings.xml b/plugins/openpgp-api-library/res/values-cs/strings.xml new file mode 100644 index 000000000..c9fe1fab7 --- /dev/null +++ b/plugins/openpgp-api-library/res/values-cs/strings.xml @@ -0,0 +1,5 @@ + + + Žádný + Instalovat OpenKeychain pomocí %s + diff --git a/plugins/openpgp-api-library/res/values-de/strings.xml b/plugins/openpgp-api-library/res/values-de/strings.xml new file mode 100644 index 000000000..91e800adb --- /dev/null +++ b/plugins/openpgp-api-library/res/values-de/strings.xml @@ -0,0 +1,5 @@ + + + Keine Auswahl + Installiere OpenKeychain mit %s + diff --git a/plugins/openpgp-api-library/res/values-es/strings.xml b/plugins/openpgp-api-library/res/values-es/strings.xml new file mode 100644 index 000000000..da8979b45 --- /dev/null +++ b/plugins/openpgp-api-library/res/values-es/strings.xml @@ -0,0 +1,5 @@ + + + Ninguno + Instalar OpenKeychain mediante %s + diff --git a/plugins/openpgp-api-library/res/values-et/strings.xml b/plugins/openpgp-api-library/res/values-et/strings.xml new file mode 100644 index 000000000..c757504ac --- /dev/null +++ b/plugins/openpgp-api-library/res/values-et/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/openpgp-api-library/res/values-fi/strings.xml b/plugins/openpgp-api-library/res/values-fi/strings.xml new file mode 100644 index 000000000..c757504ac --- /dev/null +++ b/plugins/openpgp-api-library/res/values-fi/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/openpgp-api-library/res/values-fr/strings.xml b/plugins/openpgp-api-library/res/values-fr/strings.xml new file mode 100644 index 000000000..9b36df2df --- /dev/null +++ b/plugins/openpgp-api-library/res/values-fr/strings.xml @@ -0,0 +1,5 @@ + + + Aucun + Installer OpenKeychain par %s + diff --git a/plugins/openpgp-api-library/res/values-is/strings.xml b/plugins/openpgp-api-library/res/values-is/strings.xml new file mode 100644 index 000000000..c757504ac --- /dev/null +++ b/plugins/openpgp-api-library/res/values-is/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/openpgp-api-library/res/values-it/strings.xml b/plugins/openpgp-api-library/res/values-it/strings.xml new file mode 100644 index 000000000..23e8e8013 --- /dev/null +++ b/plugins/openpgp-api-library/res/values-it/strings.xml @@ -0,0 +1,5 @@ + + + Nessuno + Installa OpenKeychain via %s + diff --git a/plugins/openpgp-api-library/res/values-ja/strings.xml b/plugins/openpgp-api-library/res/values-ja/strings.xml new file mode 100644 index 000000000..5e337f5ab --- /dev/null +++ b/plugins/openpgp-api-library/res/values-ja/strings.xml @@ -0,0 +1,5 @@ + + + 無し + %s 経由でOpenKeychainをインストール + diff --git a/plugins/openpgp-api-library/res/values-nl/strings.xml b/plugins/openpgp-api-library/res/values-nl/strings.xml new file mode 100644 index 000000000..c757504ac --- /dev/null +++ b/plugins/openpgp-api-library/res/values-nl/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/openpgp-api-library/res/values-pl/strings.xml b/plugins/openpgp-api-library/res/values-pl/strings.xml new file mode 100644 index 000000000..c757504ac --- /dev/null +++ b/plugins/openpgp-api-library/res/values-pl/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/openpgp-api-library/res/values-pt/strings.xml b/plugins/openpgp-api-library/res/values-pt/strings.xml new file mode 100644 index 000000000..c757504ac --- /dev/null +++ b/plugins/openpgp-api-library/res/values-pt/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/openpgp-api-library/res/values-ru/strings.xml b/plugins/openpgp-api-library/res/values-ru/strings.xml new file mode 100644 index 000000000..e8fd1ddf6 --- /dev/null +++ b/plugins/openpgp-api-library/res/values-ru/strings.xml @@ -0,0 +1,5 @@ + + + Нет + Установить OpenKeychain через %s + diff --git a/plugins/openpgp-api-library/res/values-sl/strings.xml b/plugins/openpgp-api-library/res/values-sl/strings.xml new file mode 100644 index 000000000..20bf70b0a --- /dev/null +++ b/plugins/openpgp-api-library/res/values-sl/strings.xml @@ -0,0 +1,5 @@ + + + Brez + Namesti OpenKeychain prek %s + diff --git a/plugins/openpgp-api-library/res/values-tr/strings.xml b/plugins/openpgp-api-library/res/values-tr/strings.xml new file mode 100644 index 000000000..c757504ac --- /dev/null +++ b/plugins/openpgp-api-library/res/values-tr/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/openpgp-api-library/res/values-uk/strings.xml b/plugins/openpgp-api-library/res/values-uk/strings.xml new file mode 100644 index 000000000..baf600a9f --- /dev/null +++ b/plugins/openpgp-api-library/res/values-uk/strings.xml @@ -0,0 +1,5 @@ + + + Жоден + Встановити OpenKeychain через %s + diff --git a/plugins/openpgp-api-library/res/values-zh/strings.xml b/plugins/openpgp-api-library/res/values-zh/strings.xml new file mode 100644 index 000000000..c757504ac --- /dev/null +++ b/plugins/openpgp-api-library/res/values-zh/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/plugins/openpgp-api-library/src/org/openintents/openpgp/OpenPgpMetadata.java b/plugins/openpgp-api-library/src/org/openintents/openpgp/OpenPgpMetadata.java new file mode 100644 index 000000000..2a99e406f --- /dev/null +++ b/plugins/openpgp-api-library/src/org/openintents/openpgp/OpenPgpMetadata.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2014 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; + +/** + * Parcelable versioning has been copied from Dashclock Widget + * https://code.google.com/p/dashclock/source/browse/api/src/main/java/com/google/android/apps/dashclock/api/ExtensionData.java + */ +public class OpenPgpMetadata implements Parcelable { + /** + * Since there might be a case where new versions of the client using the library getting + * old versions of the protocol (and thus old versions of this class), we need a versioning + * system for the parcels sent between the clients and the providers. + */ + public static final int PARCELABLE_VERSION = 1; + + String filename; + String mimeType; + long modificationTime; + long originalSize; + + public String getFilename() { + return filename; + } + + public String getMimeType() { + return mimeType; + } + + public long getModificationTime() { + return modificationTime; + } + + public long getOriginalSize() { + return originalSize; + } + + public OpenPgpMetadata() { + } + + public OpenPgpMetadata(String filename, String mimeType, long modificationTime, + long originalSize) { + this.filename = filename; + this.mimeType = mimeType; + this.modificationTime = modificationTime; + this.originalSize = originalSize; + } + + public OpenPgpMetadata(OpenPgpMetadata b) { + this.filename = b.filename; + this.mimeType = b.mimeType; + this.modificationTime = b.modificationTime; + this.originalSize = b.originalSize; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + /** + * NOTE: When adding fields in the process of updating this API, make sure to bump + * {@link #PARCELABLE_VERSION}. + */ + dest.writeInt(PARCELABLE_VERSION); + // Inject a placeholder that will store the parcel size from this point on + // (not including the size itself). + int sizePosition = dest.dataPosition(); + dest.writeInt(0); + int startPosition = dest.dataPosition(); + // version 1 + dest.writeString(filename); + dest.writeString(mimeType); + dest.writeLong(modificationTime); + dest.writeLong(originalSize); + // Go back and write the size + int parcelableSize = dest.dataPosition() - startPosition; + dest.setDataPosition(sizePosition); + dest.writeInt(parcelableSize); + dest.setDataPosition(startPosition + parcelableSize); + } + + public static final Creator CREATOR = new Creator() { + public OpenPgpMetadata createFromParcel(final Parcel source) { + int parcelableVersion = source.readInt(); + int parcelableSize = source.readInt(); + int startPosition = source.dataPosition(); + + OpenPgpMetadata vr = new OpenPgpMetadata(); + vr.filename = source.readString(); + vr.mimeType = source.readString(); + vr.modificationTime = source.readLong(); + vr.originalSize = source.readLong(); + + // skip over all fields added in future versions of this parcel + source.setDataPosition(startPosition + parcelableSize); + + return vr; + } + + public OpenPgpMetadata[] newArray(final int size) { + return new OpenPgpMetadata[size]; + } + }; + + @Override + public String toString() { + String out = "\nfilename: " + filename; + out += "\nmimeType: " + mimeType; + out += "\nmodificationTime: " + modificationTime; + out += "\noriginalSize: " + originalSize; + return out; + } + +} diff --git a/plugins/openpgp-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java b/plugins/openpgp-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java index 157dd1aad..dbcd74b64 100644 --- a/plugins/openpgp-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java +++ b/plugins/openpgp-api-library/src/org/openintents/openpgp/OpenPgpSignatureResult.java @@ -19,6 +19,11 @@ package org.openintents.openpgp; import android.os.Parcel; import android.os.Parcelable; +import org.openintents.openpgp.util.OpenPgpUtils; + +import java.util.ArrayList; +import java.util.Locale; + /** * Parcelable versioning has been copied from Dashclock Widget * https://code.google.com/p/dashclock/source/browse/api/src/main/java/com/google/android/apps/dashclock/api/ExtensionData.java @@ -29,20 +34,25 @@ public class OpenPgpSignatureResult implements Parcelable { * old versions of the protocol (and thus old versions of this class), we need a versioning * system for the parcels sent between the clients and the providers. */ - public static final int PARCELABLE_VERSION = 1; + public static final int PARCELABLE_VERSION = 2; // generic error on signature verification public static final int SIGNATURE_ERROR = 0; - // successfully verified signature, with certified public key + // successfully verified signature, with certified key public static final int SIGNATURE_SUCCESS_CERTIFIED = 1; - // no public key was found for this signature verification - public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2; - // successfully verified signature, but with uncertified public key + // no key was found for this signature verification + public static final int SIGNATURE_KEY_MISSING = 2; + // successfully verified signature, but with uncertified key public static final int SIGNATURE_SUCCESS_UNCERTIFIED = 3; + // key has been revoked + public static final int SIGNATURE_KEY_REVOKED = 4; + // key is expired + public static final int SIGNATURE_KEY_EXPIRED = 5; int status; boolean signatureOnly; - String userId; + String primaryUserId; + ArrayList userIds; long keyId; public int getStatus() { @@ -61,12 +71,20 @@ public class OpenPgpSignatureResult implements Parcelable { this.signatureOnly = signatureOnly; } - public String getUserId() { - return userId; + public String getPrimaryUserId() { + return primaryUserId; } - public void setUserId(String userId) { - this.userId = userId; + public void setPrimaryUserId(String primaryUserId) { + this.primaryUserId = primaryUserId; + } + + public ArrayList getUserIds() { + return userIds; + } + + public void setUserIds(ArrayList userIds) { + this.userIds = userIds; } public long getKeyId() { @@ -82,18 +100,20 @@ public class OpenPgpSignatureResult implements Parcelable { } public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, - boolean signatureOnly, long keyId) { + boolean signatureOnly, long keyId, ArrayList userIds) { this.status = signatureStatus; this.signatureOnly = signatureOnly; - this.userId = signatureUserId; + this.primaryUserId = signatureUserId; this.keyId = keyId; + this.userIds = userIds; } public OpenPgpSignatureResult(OpenPgpSignatureResult b) { this.status = b.status; - this.userId = b.userId; + this.primaryUserId = b.primaryUserId; this.signatureOnly = b.signatureOnly; this.keyId = b.keyId; + this.userIds = b.userIds; } public int describeContents() { @@ -114,8 +134,10 @@ public class OpenPgpSignatureResult implements Parcelable { // version 1 dest.writeInt(status); dest.writeByte((byte) (signatureOnly ? 1 : 0)); - dest.writeString(userId); + dest.writeString(primaryUserId); dest.writeLong(keyId); + // version 2 + dest.writeStringList(userIds); // Go back and write the size int parcelableSize = dest.dataPosition() - startPosition; dest.setDataPosition(sizePosition); @@ -132,8 +154,10 @@ public class OpenPgpSignatureResult implements Parcelable { OpenPgpSignatureResult vr = new OpenPgpSignatureResult(); vr.status = source.readInt(); vr.signatureOnly = source.readByte() == 1; - vr.userId = source.readString(); + vr.primaryUserId = source.readString(); vr.keyId = source.readLong(); + vr.userIds = new ArrayList(); + source.readStringList(vr.userIds); // skip over all fields added in future versions of this parcel source.setDataPosition(startPosition + parcelableSize); @@ -148,11 +172,11 @@ public class OpenPgpSignatureResult implements Parcelable { @Override public String toString() { - String out = new String(); - out += "\nstatus: " + status; - out += "\nuserId: " + userId; + String out = "\nstatus: " + status; + out += "\nprimaryUserId: " + primaryUserId; + out += "\nuserIds: " + userIds; out += "\nsignatureOnly: " + signatureOnly; - out += "\nkeyId: " + keyId; + out += "\nkeyId: " + OpenPgpUtils.convertKeyIdToHex(keyId); return out; } diff --git a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java index 5c3c15f11..ddd5abc54 100644 --- a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java +++ b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpApi.java @@ -23,10 +23,10 @@ import android.os.AsyncTask; import android.os.Build; import android.os.ParcelFileDescriptor; import android.util.Log; + import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.OpenPgpError; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -34,9 +34,25 @@ public class OpenPgpApi { public static final String TAG = "OpenPgp API"; - public static final int API_VERSION = 3; public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; - + + /** + * Version history + * --------------- + *

+ * 3: + * - first public stable version + *

+ * 4: + * - No changes to existing methods -> backward compatible + * - Introduction of ACTION_DECRYPT_METADATA, RESULT_METADATA, EXTRA_ORIGINAL_FILENAME, and OpenPgpMetadata parcel + * - Introduction of internal NFC extras: EXTRA_NFC_SIGNED_HASH, EXTRA_NFC_SIG_CREATION_TIMESTAMP + * 5: + * - OpenPgpSignatureResult: new consts SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED + * - OpenPgpSignatureResult: ArrayList userIds + */ + public static final int API_VERSION = 5; + /** * General extras * -------------- @@ -51,75 +67,116 @@ public class OpenPgpApi { */ /** - * Sign only - * + * DEPRECATED + * Same as ACTION_CLEARTEXT_SIGN + *

* optional extras: - * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) + * boolean EXTRA_REQUEST_ASCII_ARMOR (DEPRECATED: this makes no sense here) * String EXTRA_PASSPHRASE (key passphrase) */ public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN"; + /** + * Sign text resulting in a cleartext signature + * Some magic pre-processing of the text is done to convert it to a format usable for + * cleartext signatures per RFC 4880 before the text is actually signed: + * - end cleartext with newline + * - remove whitespaces on line endings + *

+ * optional extras: + * String EXTRA_PASSPHRASE (key passphrase) + */ + public static final String ACTION_CLEARTEXT_SIGN = "org.openintents.openpgp.action.CLEARTEXT_SIGN"; + + /** + * Sign text or binary data resulting in a detached signature. + * No OutputStream for ACTION_DETACHED_SIGN (No magic pre-processing like in ACTION_CLEARTEXT_SIGN)! + * The detached signature is returned separately in RESULT_DETACHED_SIGNATURE. + *

+ * optional extras: + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for detached signature) + * String EXTRA_PASSPHRASE (key passphrase) + *

+ * returned extras: + * byte[] RESULT_DETACHED_SIGNATURE + */ + public static final String ACTION_DETACHED_SIGN = "org.openintents.openpgp.action.DETACHED_SIGN"; + /** * Encrypt - * + *

* required extras: * String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT) * or * long[] EXTRA_KEY_IDS - * + *

* optional extras: - * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output) * String EXTRA_PASSPHRASE (key passphrase) + * String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata) */ public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT"; /** * Sign and encrypt - * + *

* required extras: * String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT) * or * long[] EXTRA_KEY_IDS - * + *

* optional extras: - * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output) * String EXTRA_PASSPHRASE (key passphrase) + * String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata) */ public static final String ACTION_SIGN_AND_ENCRYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT"; /** * Decrypts and verifies given input stream. This methods handles encrypted-only, signed-and-encrypted, * and also signed-only input. - * - * If OpenPgpSignatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY + *

+ * If OpenPgpSignatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING * in addition a PendingIntent is returned via RESULT_INTENT to download missing keys. - * + *

* optional extras: - * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput) - * + * boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output) + * byte[] EXTRA_DETACHED_SIGNATURE (detached signature) + *

* returned extras: * OpenPgpSignatureResult RESULT_SIGNATURE + * OpenPgpDecryptMetadata RESULT_METADATA */ public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY"; + /** + * Decrypts the header of an encrypted file to retrieve metadata such as original filename. + *

+ * This does not decrypt the actual content of the file. + *

+ * returned extras: + * OpenPgpDecryptMetadata RESULT_METADATA + */ + public static final String ACTION_DECRYPT_METADATA = "org.openintents.openpgp.action.DECRYPT_METADATA"; + /** * Get key ids based on given user ids (=emails) - * + *

* required extras: * String[] EXTRA_USER_IDS - * + *

* returned extras: - * long[] EXTRA_KEY_IDS + * long[] RESULT_KEY_IDS */ public static final String ACTION_GET_KEY_IDS = "org.openintents.openpgp.action.GET_KEY_IDS"; /** * This action returns RESULT_CODE_SUCCESS if the OpenPGP Provider already has the key * corresponding to the given key id in its database. - * + *

* It returns RESULT_CODE_USER_INTERACTION_REQUIRED if the Provider does not have the key. * The PendingIntent from RESULT_INTENT can be used to retrieve those from a keyserver. - * + *

* required extras: * long EXTRA_KEY_ID */ @@ -130,19 +187,29 @@ public class OpenPgpApi { public static final String EXTRA_ACCOUNT_NAME = "account_name"; - // SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY + // ACTION_DETACHED_SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY // request ASCII Armor for output // OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) public static final String EXTRA_REQUEST_ASCII_ARMOR = "ascii_armor"; + // ACTION_DETACHED_SIGN + public static final String RESULT_DETACHED_SIGNATURE = "detached_signature"; + // ENCRYPT, SIGN_AND_ENCRYPT public static final String EXTRA_USER_IDS = "user_ids"; public static final String EXTRA_KEY_IDS = "key_ids"; // optional extras: public static final String EXTRA_PASSPHRASE = "passphrase"; + public static final String EXTRA_ORIGINAL_FILENAME = "original_filename"; + + // internal NFC states + public static final String EXTRA_NFC_SIGNED_HASH = "nfc_signed_hash"; + public static final String EXTRA_NFC_SIG_CREATION_TIMESTAMP = "nfc_sig_creation_timestamp"; + public static final String EXTRA_NFC_DECRYPTED_SESSION_KEY = "nfc_decrypted_session_key"; // GET_KEY public static final String EXTRA_KEY_ID = "key_id"; + public static final String RESULT_KEY_IDS = "key_ids"; /* Service Intent returns */ public static final String RESULT_CODE = "result_code"; @@ -159,7 +226,12 @@ public class OpenPgpApi { public static final String RESULT_INTENT = "intent"; // DECRYPT_VERIFY + public static final String EXTRA_DETACHED_SIGNATURE = "detached_signature"; + public static final String RESULT_SIGNATURE = "signature"; + public static final String RESULT_METADATA = "metadata"; + // This will be the charset which was specified in the headers of ascii armored input, if any + public static final String RESULT_CHARSET = "charset"; IOpenPgpService mService; Context mContext; @@ -211,17 +283,14 @@ public class OpenPgpApi { } public Intent executeApi(Intent data, InputStream is, OutputStream os) { - ParcelFileDescriptor input = null; try { data.putExtra(EXTRA_API_VERSION, OpenPgpApi.API_VERSION); - Intent result = null; + Intent result; - if (ACTION_GET_KEY_IDS.equals(data.getAction())) { - result = mService.execute(data, null, null); - return result; - } else { - // pipe the input and output + // pipe the input and output + ParcelFileDescriptor input = null; + if (is != null) { input = ParcelFileDescriptorUtil.pipeFrom(is, new ParcelFileDescriptorUtil.IThreadListener() { @@ -229,43 +298,43 @@ public class OpenPgpApi { public void onThreadFinished(Thread thread) { //Log.d(OpenPgpApi.TAG, "Copy to service finished"); } - }); - ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os, + } + ); + } + ParcelFileDescriptor output = null; + if (os != null) { + output = ParcelFileDescriptorUtil.pipeTo(os, new ParcelFileDescriptorUtil.IThreadListener() { @Override public void onThreadFinished(Thread thread) { //Log.d(OpenPgpApi.TAG, "Service finished writing!"); } - }); - - // blocks until result is ready - result = mService.execute(data, input, output); - // close() is required to halt the TransferThread - output.close(); - - // set class loader to current context to allow unparcelling - // of OpenPgpError and OpenPgpSignatureResult - // http://stackoverflow.com/a/3806769 - result.setExtrasClassLoader(mContext.getClassLoader()); - - return result; + } + ); } + + // blocks until result is ready + result = mService.execute(data, input, output); + // close() is required to halt the TransferThread + if (output != null) { + output.close(); + } + // TODO: close input? + + // set class loader to current context to allow unparcelling + // of OpenPgpError and OpenPgpSignatureResult + // http://stackoverflow.com/a/3806769 + result.setExtrasClassLoader(mContext.getClassLoader()); + + return result; } catch (Exception e) { - Log.e(OpenPgpApi.TAG, "Exception", e); + Log.e(OpenPgpApi.TAG, "Exception in executeApi call", e); Intent result = new Intent(); result.putExtra(RESULT_CODE, RESULT_CODE_ERROR); result.putExtra(RESULT_ERROR, new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage())); return result; - } finally { - if (input != null) { - try { - input.close(); - } catch (IOException e) { - Log.e(OpenPgpApi.TAG, "Failed to close input file descriptor", e); - } - } } } diff --git a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java index 3c21eaff0..cf5864620 100644 --- a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java +++ b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpListPreference.java @@ -16,9 +16,6 @@ package org.openintents.openpgp.util; -import java.util.ArrayList; -import java.util.List; - import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; @@ -34,9 +31,11 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.TextView; - import org.openintents.openpgp.R; +import java.util.ArrayList; +import java.util.List; + /** * Does not extend ListPreference, but is very similar to it! * http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/preference/ListPreference.java/?v=source @@ -47,6 +46,7 @@ public class OpenPgpListPreference extends DialogPreference { private static final Intent MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse( String.format(MARKET_INTENT_URI_BASE, OPENKEYCHAIN_PACKAGE))); + private ArrayList mLegacyList = new ArrayList(); private ArrayList mList = new ArrayList(); private String mSelectedPackage; @@ -59,6 +59,17 @@ public class OpenPgpListPreference extends DialogPreference { this(context, null); } + /** + * Public method to add new entries for legacy applications + * + * @param packageName + * @param simpleName + * @param icon + */ + public void addLegacyProvider(int position, String packageName, String simpleName, Drawable icon) { + mLegacyList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon)); + } + @Override protected void onPrepareDialogBuilder(Builder builder) { mList.clear(); @@ -66,8 +77,11 @@ public class OpenPgpListPreference extends DialogPreference { // add "none"-entry mList.add(0, new OpenPgpProviderEntry("", getContext().getString(R.string.openpgp_list_preference_none), - getContext().getResources().getDrawable(R.drawable.ic_action_cancel_launchersize_light))); - + getContext().getResources().getDrawable(R.drawable.ic_action_cancel_launchersize))); + + // add all additional (legacy) providers + mList.addAll(mLegacyList); + // search for OpenPGP providers... ArrayList providerList = new ArrayList(); Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT); diff --git a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java index c80656c52..15096d9eb 100644 --- a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java +++ b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java @@ -16,43 +16,74 @@ package org.openintents.openpgp.util; -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 org.openintents.openpgp.IOpenPgpService; + public class OpenPgpServiceConnection { + + // callback interface + public interface OnBound { + public void onBound(IOpenPgpService service); + + public void onError(Exception e); + } + private Context mApplicationContext; - private boolean mBound; private IOpenPgpService mService; private String mProviderPackageName; + private OnBound mOnBoundListener; + + /** + * Create new connection + * + * @param context + * @param providerPackageName specify package name of OpenPGP provider, + * e.g., "org.sufficientlysecure.keychain" + */ public OpenPgpServiceConnection(Context context, String providerPackageName) { this.mApplicationContext = context.getApplicationContext(); this.mProviderPackageName = providerPackageName; } + /** + * Create new connection with callback + * + * @param context + * @param providerPackageName specify package name of OpenPGP provider, + * e.g., "org.sufficientlysecure.keychain" + * @param onBoundListener callback, executed when connection to service has been established + */ + public OpenPgpServiceConnection(Context context, String providerPackageName, + OnBound onBoundListener) { + this(context, providerPackageName); + this.mOnBoundListener = onBoundListener; + } + public IOpenPgpService getService() { return mService; } public boolean isBound() { - return mBound; + return (mService != null); } private ServiceConnection mServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { mService = IOpenPgpService.Stub.asInterface(service); - mBound = true; + if (mOnBoundListener != null) { + mOnBoundListener.onBound(mService); + } } public void onServiceDisconnected(ComponentName name) { mService = null; - mBound = false; } }; @@ -61,23 +92,28 @@ public class OpenPgpServiceConnection { * * @return */ - public boolean bindToService() { + public void bindToService() { // if not already bound... - if (mService == null && !mBound) { + if (mService == null) { try { - Intent serviceIntent = new Intent(); - serviceIntent.setAction(IOpenPgpService.class.getName()); + Intent serviceIntent = new Intent(OpenPgpApi.SERVICE_INTENT); // NOTE: setPackage is very important to restrict the intent to this provider only! serviceIntent.setPackage(mProviderPackageName); - mApplicationContext.bindService(serviceIntent, mServiceConnection, + boolean connect = mApplicationContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); - - return true; + if (!connect) { + throw new Exception("bindService() returned false!"); + } } catch (Exception e) { - return false; + if (mOnBoundListener != null) { + mOnBoundListener.onError(e); + } } } else { - return true; + // already bound, but also inform client about it with callback + if (mOnBoundListener != null) { + mOnBoundListener.onBound(mService); + } } } diff --git a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpUtils.java b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpUtils.java index 67fe86291..416b2841b 100644 --- a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpUtils.java +++ b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/OpenPgpUtils.java @@ -17,6 +17,7 @@ package org.openintents.openpgp.util; import java.util.List; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -61,4 +62,15 @@ public class OpenPgpUtils { } } + public static String convertKeyIdToHex(long keyId) { + return "0x" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId); + } + + private static String convertKeyIdToHex32bit(long keyId) { + String hexString = Long.toHexString(keyId & 0xffffffffL).toLowerCase(Locale.ENGLISH); + while (hexString.length() < 8) { + hexString = "0" + hexString; + } + return hexString; + } } diff --git a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java index 58c62110d..4fd4b39a7 100644 --- a/plugins/openpgp-api-library/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java +++ b/plugins/openpgp-api-library/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 Dominik Schürmann - * 2013 Flow (http://stackoverflow.com/questions/18212152/transfer-inputstream-to-another-service-across-process-boundaries-with-parcelf) + * 2013 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +/** + * Partially based on Stackoverflow: Transfer InputStream to another Service (across process boundaries) + **/ public class ParcelFileDescriptorUtil { public interface IThreadListener { @@ -100,4 +103,4 @@ public class ParcelFileDescriptorUtil { } } } -} \ No newline at end of file +}