Merge pull request #534 from k9mail/openpgp_api_library_update

Update openpgp-api-library to latest version
This commit is contained in:
cketti 2015-01-27 12:42:47 +01:00
commit 74820a40db
28 changed files with 487 additions and 100 deletions

View File

@ -160,13 +160,13 @@ public class MessageOpenPgpView extends LinearLayout {
R.color.openpgp_green)); R.color.openpgp_green));
mGetKeyButton.setVisibility(View.GONE); mGetKeyButton.setVisibility(View.GONE);
mSignatureUserId.setText(signatureResult.getUserId()); mSignatureUserId.setText(signatureResult.getPrimaryUserId());
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
mSignatureLayout.setVisibility(View.VISIBLE); mSignatureLayout.setVisibility(View.VISIBLE);
break; break;
case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: case OpenPgpSignatureResult.SIGNATURE_KEY_MISSING:
if (signatureResult.isSignatureOnly()) { if (signatureResult.isSignatureOnly()) {
mText.setText(R.string.openpgp_signature_unknown_text); mText.setText(R.string.openpgp_signature_unknown_text);
} }
@ -194,7 +194,7 @@ public class MessageOpenPgpView extends LinearLayout {
R.color.openpgp_orange)); R.color.openpgp_orange));
mGetKeyButton.setVisibility(View.GONE); mGetKeyButton.setVisibility(View.GONE);
mSignatureUserId.setText(signatureResult.getUserId()); mSignatureUserId.setText(signatureResult.getPrimaryUserId());
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
mSignatureLayout.setVisibility(View.VISIBLE); mSignatureLayout.setVisibility(View.VISIBLE);

View File

@ -6,7 +6,7 @@
<uses-sdk <uses-sdk
android:minSdkVersion="9" android:minSdkVersion="9"
android:targetSdkVersion="17" /> android:targetSdkVersion="19" />
<application/> <application/>

View File

@ -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.

View File

@ -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

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Žádný</string>
<string name="openpgp_install_openkeychain_via">Instalovat OpenKeychain pomocí %s</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Keine Auswahl</string>
<string name="openpgp_install_openkeychain_via">Installiere OpenKeychain mit %s</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Ninguno</string>
<string name="openpgp_install_openkeychain_via">Instalar OpenKeychain mediante %s</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Aucun</string>
<string name="openpgp_install_openkeychain_via">Installer OpenKeychain par %s</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Nessuno</string>
<string name="openpgp_install_openkeychain_via">Installa OpenKeychain via %s</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">無し</string>
<string name="openpgp_install_openkeychain_via">%s 経由でOpenKeychainをインストール</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Нет</string>
<string name="openpgp_install_openkeychain_via">Установить OpenKeychain через %s</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Brez</string>
<string name="openpgp_install_openkeychain_via">Namesti OpenKeychain prek %s</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Жоден</string>
<string name="openpgp_install_openkeychain_via">Встановити OpenKeychain через %s</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2014 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.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<OpenPgpMetadata> CREATOR = new Creator<OpenPgpMetadata>() {
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;
}
}

View File

@ -19,6 +19,11 @@ package org.openintents.openpgp;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; 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 * 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 * 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 * 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. * 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 // generic error on signature verification
public static final int SIGNATURE_ERROR = 0; 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; public static final int SIGNATURE_SUCCESS_CERTIFIED = 1;
// no public key was found for this signature verification // no key was found for this signature verification
public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2; public static final int SIGNATURE_KEY_MISSING = 2;
// successfully verified signature, but with uncertified public key // successfully verified signature, but with uncertified key
public static final int SIGNATURE_SUCCESS_UNCERTIFIED = 3; 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; int status;
boolean signatureOnly; boolean signatureOnly;
String userId; String primaryUserId;
ArrayList<String> userIds;
long keyId; long keyId;
public int getStatus() { public int getStatus() {
@ -61,12 +71,20 @@ public class OpenPgpSignatureResult implements Parcelable {
this.signatureOnly = signatureOnly; this.signatureOnly = signatureOnly;
} }
public String getUserId() { public String getPrimaryUserId() {
return userId; return primaryUserId;
} }
public void setUserId(String userId) { public void setPrimaryUserId(String primaryUserId) {
this.userId = userId; this.primaryUserId = primaryUserId;
}
public ArrayList<String> getUserIds() {
return userIds;
}
public void setUserIds(ArrayList<String> userIds) {
this.userIds = userIds;
} }
public long getKeyId() { public long getKeyId() {
@ -82,18 +100,20 @@ public class OpenPgpSignatureResult implements Parcelable {
} }
public OpenPgpSignatureResult(int signatureStatus, String signatureUserId, public OpenPgpSignatureResult(int signatureStatus, String signatureUserId,
boolean signatureOnly, long keyId) { boolean signatureOnly, long keyId, ArrayList<String> userIds) {
this.status = signatureStatus; this.status = signatureStatus;
this.signatureOnly = signatureOnly; this.signatureOnly = signatureOnly;
this.userId = signatureUserId; this.primaryUserId = signatureUserId;
this.keyId = keyId; this.keyId = keyId;
this.userIds = userIds;
} }
public OpenPgpSignatureResult(OpenPgpSignatureResult b) { public OpenPgpSignatureResult(OpenPgpSignatureResult b) {
this.status = b.status; this.status = b.status;
this.userId = b.userId; this.primaryUserId = b.primaryUserId;
this.signatureOnly = b.signatureOnly; this.signatureOnly = b.signatureOnly;
this.keyId = b.keyId; this.keyId = b.keyId;
this.userIds = b.userIds;
} }
public int describeContents() { public int describeContents() {
@ -114,8 +134,10 @@ public class OpenPgpSignatureResult implements Parcelable {
// version 1 // version 1
dest.writeInt(status); dest.writeInt(status);
dest.writeByte((byte) (signatureOnly ? 1 : 0)); dest.writeByte((byte) (signatureOnly ? 1 : 0));
dest.writeString(userId); dest.writeString(primaryUserId);
dest.writeLong(keyId); dest.writeLong(keyId);
// version 2
dest.writeStringList(userIds);
// Go back and write the size // Go back and write the size
int parcelableSize = dest.dataPosition() - startPosition; int parcelableSize = dest.dataPosition() - startPosition;
dest.setDataPosition(sizePosition); dest.setDataPosition(sizePosition);
@ -132,8 +154,10 @@ public class OpenPgpSignatureResult implements Parcelable {
OpenPgpSignatureResult vr = new OpenPgpSignatureResult(); OpenPgpSignatureResult vr = new OpenPgpSignatureResult();
vr.status = source.readInt(); vr.status = source.readInt();
vr.signatureOnly = source.readByte() == 1; vr.signatureOnly = source.readByte() == 1;
vr.userId = source.readString(); vr.primaryUserId = source.readString();
vr.keyId = source.readLong(); vr.keyId = source.readLong();
vr.userIds = new ArrayList<String>();
source.readStringList(vr.userIds);
// skip over all fields added in future versions of this parcel // skip over all fields added in future versions of this parcel
source.setDataPosition(startPosition + parcelableSize); source.setDataPosition(startPosition + parcelableSize);
@ -148,11 +172,11 @@ public class OpenPgpSignatureResult implements Parcelable {
@Override @Override
public String toString() { public String toString() {
String out = new String(); String out = "\nstatus: " + status;
out += "\nstatus: " + status; out += "\nprimaryUserId: " + primaryUserId;
out += "\nuserId: " + userId; out += "\nuserIds: " + userIds;
out += "\nsignatureOnly: " + signatureOnly; out += "\nsignatureOnly: " + signatureOnly;
out += "\nkeyId: " + keyId; out += "\nkeyId: " + OpenPgpUtils.convertKeyIdToHex(keyId);
return out; return out;
} }

View File

@ -23,10 +23,10 @@ import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Log; import android.util.Log;
import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpError;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -34,9 +34,25 @@ public class OpenPgpApi {
public static final String TAG = "OpenPgp API"; public static final String TAG = "OpenPgp API";
public static final int API_VERSION = 3;
public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService";
/**
* Version history
* ---------------
* <p/>
* 3:
* - first public stable version
* <p/>
* 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<String> userIds
*/
public static final int API_VERSION = 5;
/** /**
* General extras * General extras
* -------------- * --------------
@ -51,75 +67,116 @@ public class OpenPgpApi {
*/ */
/** /**
* Sign only * DEPRECATED
* * Same as ACTION_CLEARTEXT_SIGN
* <p/>
* optional extras: * 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) * String EXTRA_PASSPHRASE (key passphrase)
*/ */
public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN"; 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
* <p/>
* 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.
* <p/>
* optional extras:
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for detached signature)
* String EXTRA_PASSPHRASE (key passphrase)
* <p/>
* returned extras:
* byte[] RESULT_DETACHED_SIGNATURE
*/
public static final String ACTION_DETACHED_SIGN = "org.openintents.openpgp.action.DETACHED_SIGN";
/** /**
* Encrypt * Encrypt
* * <p/>
* required extras: * 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) * String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
* or * or
* long[] EXTRA_KEY_IDS * long[] EXTRA_KEY_IDS
* * <p/>
* optional extras: * 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_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"; public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT";
/** /**
* Sign and encrypt * Sign and encrypt
* * <p/>
* required extras: * 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) * String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
* or * or
* long[] EXTRA_KEY_IDS * long[] EXTRA_KEY_IDS
* * <p/>
* optional extras: * 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_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"; 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, * Decrypts and verifies given input stream. This methods handles encrypted-only, signed-and-encrypted,
* and also signed-only input. * and also signed-only input.
* * <p/>
* 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. * in addition a PendingIntent is returned via RESULT_INTENT to download missing keys.
* * <p/>
* optional extras: * 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)
* <p/>
* returned extras: * returned extras:
* OpenPgpSignatureResult RESULT_SIGNATURE * OpenPgpSignatureResult RESULT_SIGNATURE
* OpenPgpDecryptMetadata RESULT_METADATA
*/ */
public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY"; 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.
* <p/>
* This does not decrypt the actual content of the file.
* <p/>
* 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) * Get key ids based on given user ids (=emails)
* * <p/>
* required extras: * required extras:
* String[] EXTRA_USER_IDS * String[] EXTRA_USER_IDS
* * <p/>
* returned extras: * 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"; 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 * This action returns RESULT_CODE_SUCCESS if the OpenPGP Provider already has the key
* corresponding to the given key id in its database. * corresponding to the given key id in its database.
* * <p/>
* It returns RESULT_CODE_USER_INTERACTION_REQUIRED if the Provider does not have the key. * 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. * The PendingIntent from RESULT_INTENT can be used to retrieve those from a keyserver.
* * <p/>
* required extras: * required extras:
* long EXTRA_KEY_ID * long EXTRA_KEY_ID
*/ */
@ -130,19 +187,29 @@ public class OpenPgpApi {
public static final String EXTRA_ACCOUNT_NAME = "account_name"; 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 // request ASCII Armor for output
// OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53) // 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"; 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 // ENCRYPT, SIGN_AND_ENCRYPT
public static final String EXTRA_USER_IDS = "user_ids"; public static final String EXTRA_USER_IDS = "user_ids";
public static final String EXTRA_KEY_IDS = "key_ids"; public static final String EXTRA_KEY_IDS = "key_ids";
// optional extras: // optional extras:
public static final String EXTRA_PASSPHRASE = "passphrase"; 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 // GET_KEY
public static final String EXTRA_KEY_ID = "key_id"; public static final String EXTRA_KEY_ID = "key_id";
public static final String RESULT_KEY_IDS = "key_ids";
/* Service Intent returns */ /* Service Intent returns */
public static final String RESULT_CODE = "result_code"; public static final String RESULT_CODE = "result_code";
@ -159,7 +226,12 @@ public class OpenPgpApi {
public static final String RESULT_INTENT = "intent"; public static final String RESULT_INTENT = "intent";
// DECRYPT_VERIFY // DECRYPT_VERIFY
public static final String EXTRA_DETACHED_SIGNATURE = "detached_signature";
public static final String RESULT_SIGNATURE = "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; IOpenPgpService mService;
Context mContext; Context mContext;
@ -211,17 +283,14 @@ public class OpenPgpApi {
} }
public Intent executeApi(Intent data, InputStream is, OutputStream os) { public Intent executeApi(Intent data, InputStream is, OutputStream os) {
ParcelFileDescriptor input = null;
try { try {
data.putExtra(EXTRA_API_VERSION, OpenPgpApi.API_VERSION); data.putExtra(EXTRA_API_VERSION, OpenPgpApi.API_VERSION);
Intent result = null; Intent result;
if (ACTION_GET_KEY_IDS.equals(data.getAction())) { // pipe the input and output
result = mService.execute(data, null, null); ParcelFileDescriptor input = null;
return result; if (is != null) {
} else {
// pipe the input and output
input = ParcelFileDescriptorUtil.pipeFrom(is, input = ParcelFileDescriptorUtil.pipeFrom(is,
new ParcelFileDescriptorUtil.IThreadListener() { new ParcelFileDescriptorUtil.IThreadListener() {
@ -229,43 +298,43 @@ public class OpenPgpApi {
public void onThreadFinished(Thread thread) { public void onThreadFinished(Thread thread) {
//Log.d(OpenPgpApi.TAG, "Copy to service finished"); //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() { new ParcelFileDescriptorUtil.IThreadListener() {
@Override @Override
public void onThreadFinished(Thread thread) { public void onThreadFinished(Thread thread) {
//Log.d(OpenPgpApi.TAG, "Service finished writing!"); //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) { } catch (Exception e) {
Log.e(OpenPgpApi.TAG, "Exception", e); Log.e(OpenPgpApi.TAG, "Exception in executeApi call", e);
Intent result = new Intent(); Intent result = new Intent();
result.putExtra(RESULT_CODE, RESULT_CODE_ERROR); result.putExtra(RESULT_CODE, RESULT_CODE_ERROR);
result.putExtra(RESULT_ERROR, result.putExtra(RESULT_ERROR,
new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage())); new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage()));
return result; return result;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
Log.e(OpenPgpApi.TAG, "Failed to close input file descriptor", e);
}
}
} }
} }

View File

@ -16,9 +16,6 @@
package org.openintents.openpgp.util; package org.openintents.openpgp.util;
import java.util.ArrayList;
import java.util.List;
import android.app.AlertDialog.Builder; import android.app.AlertDialog.Builder;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -34,9 +31,11 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ListAdapter; import android.widget.ListAdapter;
import android.widget.TextView; import android.widget.TextView;
import org.openintents.openpgp.R; import org.openintents.openpgp.R;
import java.util.ArrayList;
import java.util.List;
/** /**
* Does not extend ListPreference, but is very similar to it! * 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 * 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( private static final Intent MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse(
String.format(MARKET_INTENT_URI_BASE, OPENKEYCHAIN_PACKAGE))); String.format(MARKET_INTENT_URI_BASE, OPENKEYCHAIN_PACKAGE)));
private ArrayList<OpenPgpProviderEntry> mLegacyList = new ArrayList<OpenPgpProviderEntry>();
private ArrayList<OpenPgpProviderEntry> mList = new ArrayList<OpenPgpProviderEntry>(); private ArrayList<OpenPgpProviderEntry> mList = new ArrayList<OpenPgpProviderEntry>();
private String mSelectedPackage; private String mSelectedPackage;
@ -59,6 +59,17 @@ public class OpenPgpListPreference extends DialogPreference {
this(context, null); 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 @Override
protected void onPrepareDialogBuilder(Builder builder) { protected void onPrepareDialogBuilder(Builder builder) {
mList.clear(); mList.clear();
@ -66,8 +77,11 @@ public class OpenPgpListPreference extends DialogPreference {
// add "none"-entry // add "none"-entry
mList.add(0, new OpenPgpProviderEntry("", mList.add(0, new OpenPgpProviderEntry("",
getContext().getString(R.string.openpgp_list_preference_none), 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... // search for OpenPGP providers...
ArrayList<OpenPgpProviderEntry> providerList = new ArrayList<OpenPgpProviderEntry>(); ArrayList<OpenPgpProviderEntry> providerList = new ArrayList<OpenPgpProviderEntry>();
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT); Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT);

View File

@ -16,43 +16,74 @@
package org.openintents.openpgp.util; package org.openintents.openpgp.util;
import org.openintents.openpgp.IOpenPgpService;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import org.openintents.openpgp.IOpenPgpService;
public class OpenPgpServiceConnection { public class OpenPgpServiceConnection {
// callback interface
public interface OnBound {
public void onBound(IOpenPgpService service);
public void onError(Exception e);
}
private Context mApplicationContext; private Context mApplicationContext;
private boolean mBound;
private IOpenPgpService mService; private IOpenPgpService mService;
private String mProviderPackageName; 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) { public OpenPgpServiceConnection(Context context, String providerPackageName) {
this.mApplicationContext = context.getApplicationContext(); this.mApplicationContext = context.getApplicationContext();
this.mProviderPackageName = providerPackageName; 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() { public IOpenPgpService getService() {
return mService; return mService;
} }
public boolean isBound() { public boolean isBound() {
return mBound; return (mService != null);
} }
private ServiceConnection mServiceConnection = new ServiceConnection() { private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
mService = IOpenPgpService.Stub.asInterface(service); mService = IOpenPgpService.Stub.asInterface(service);
mBound = true; if (mOnBoundListener != null) {
mOnBoundListener.onBound(mService);
}
} }
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
mService = null; mService = null;
mBound = false;
} }
}; };
@ -61,23 +92,28 @@ public class OpenPgpServiceConnection {
* *
* @return * @return
*/ */
public boolean bindToService() { public void bindToService() {
// if not already bound... // if not already bound...
if (mService == null && !mBound) { if (mService == null) {
try { try {
Intent serviceIntent = new Intent(); Intent serviceIntent = new Intent(OpenPgpApi.SERVICE_INTENT);
serviceIntent.setAction(IOpenPgpService.class.getName());
// NOTE: setPackage is very important to restrict the intent to this provider only! // NOTE: setPackage is very important to restrict the intent to this provider only!
serviceIntent.setPackage(mProviderPackageName); serviceIntent.setPackage(mProviderPackageName);
mApplicationContext.bindService(serviceIntent, mServiceConnection, boolean connect = mApplicationContext.bindService(serviceIntent, mServiceConnection,
Context.BIND_AUTO_CREATE); Context.BIND_AUTO_CREATE);
if (!connect) {
return true; throw new Exception("bindService() returned false!");
}
} catch (Exception e) { } catch (Exception e) {
return false; if (mOnBoundListener != null) {
mOnBoundListener.onError(e);
}
} }
} else { } else {
return true; // already bound, but also inform client about it with callback
if (mOnBoundListener != null) {
mOnBoundListener.onBound(mService);
}
} }
} }

View File

@ -17,6 +17,7 @@
package org.openintents.openpgp.util; package org.openintents.openpgp.util;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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;
}
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* 2013 Flow (http://stackoverflow.com/questions/18212152/transfer-inputstream-to-another-service-across-process-boundaries-with-parcelf) * 2013 Florian Schmaus <flo@geekplace.eu>
* *
* Licensed under the Apache License, Version 2.0 (the "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 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.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
/**
* Partially based on <a href="http://stackoverflow.com/questions/18212152/">Stackoverflow: Transfer InputStream to another Service (across process boundaries)</a>
**/
public class ParcelFileDescriptorUtil { public class ParcelFileDescriptorUtil {
public interface IThreadListener { public interface IThreadListener {
@ -100,4 +103,4 @@ public class ParcelFileDescriptorUtil {
} }
} }
} }
} }