diff options
author | Dominik <dominik@dominikschuermann.de> | 2012-11-19 17:56:58 +0100 |
---|---|---|
committer | Dominik <dominik@dominikschuermann.de> | 2012-11-19 17:56:58 +0100 |
commit | be569984b893e8cb412b9cc2b3826c92fd4c9d81 (patch) | |
tree | 150dc6b112aecde5d34b5d0cc23f4bb35b7fcb3f /APG-API-Lib | |
parent | e8ec4d280c75dc1aa5eb58dfaf49b35c9b6c8776 (diff) | |
download | open-keychain-be569984b893e8cb412b9cc2b3826c92fd4c9d81.tar.gz open-keychain-be569984b893e8cb412b9cc2b3826c92fd4c9d81.tar.bz2 open-keychain-be569984b893e8cb412b9cc2b3826c92fd4c9d81.zip |
rename main folders
Diffstat (limited to 'APG-API-Lib')
16 files changed, 1119 insertions, 0 deletions
diff --git a/APG-API-Lib/.gitignore b/APG-API-Lib/.gitignore new file mode 100644 index 000000000..2e423e1a3 --- /dev/null +++ b/APG-API-Lib/.gitignore @@ -0,0 +1,23 @@ +#Android generated +bin +gen +obj +libs/armeabi +lint.xml +local.properties + +#Eclipse +.project +.classpath +.settings + +#IntelliJ IDEA +.idea +*.iml + +#Maven +target +release.properties + +#Mac +.DS_Store
\ No newline at end of file diff --git a/APG-API-Lib/AndroidManifest.xml b/APG-API-Lib/AndroidManifest.xml new file mode 100644 index 000000000..3d99ae603 --- /dev/null +++ b/APG-API-Lib/AndroidManifest.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.thialfihar.android.apg.integration" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="7" + android:targetSdkVersion="14" /> + +</manifest>
\ No newline at end of file diff --git a/APG-API-Lib/build.xml b/APG-API-Lib/build.xml new file mode 100644 index 000000000..895594080 --- /dev/null +++ b/APG-API-Lib/build.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="apg_integration_lib" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + <property file="local.properties" /> + + <!-- The ant.properties file can be created by you. It is only edited by the + 'android' tool to add properties to it. + This is the place to change some Ant specific build properties. + Here are some properties you may want to change/update: + + source.dir + The name of the source directory. Default is 'src'. + out.dir + The name of the output directory. Default is 'bin'. + + For other overridable properties, look at the beginning of the rules + files in the SDK, at tools/ant/build.xml + + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. + + --> + <property file="ant.properties" /> + + <!-- The project.properties file is created and updated by the 'android' + tool, as well as ADT. + + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + <loadproperties srcFile="project.properties" /> + + <!-- quick check on sdk.dir --> + <fail + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" + unless="sdk.dir" + /> + + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> + + <!-- Import the actual build file. + + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <import> task. + - customize it to your needs. + - Customize the whole content of build.xml + - copy/paste the content of the rules files (minus the top node) + into this file, replacing the <import> task. + - customize to your needs. + + *********************** + ****** IMPORTANT ****** + *********************** + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, + in order to avoid having your file be overridden by tools such as "android update project" + --> + <!-- version-tag: 1 --> + <import file="${sdk.dir}/tools/ant/build.xml" /> + +</project> diff --git a/APG-API-Lib/proguard-project.txt b/APG-API-Lib/proguard-project.txt new file mode 100644 index 000000000..f2fe1559a --- /dev/null +++ b/APG-API-Lib/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/APG-API-Lib/project.properties b/APG-API-Lib/project.properties new file mode 100644 index 000000000..36f15941e --- /dev/null +++ b/APG-API-Lib/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-15 +android.library=true diff --git a/APG-API-Lib/res/.readme b/APG-API-Lib/res/.readme new file mode 100644 index 000000000..97473e05c --- /dev/null +++ b/APG-API-Lib/res/.readme @@ -0,0 +1 @@ +Directory must be empty. Then Android will build a jar instead of an apk!
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgData.java b/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgData.java new file mode 100644 index 000000000..5ef20bfbb --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgData.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2010-2011 K-9 Mail Contributors + * + * 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.thialfihar.android.apg.integration; + +import java.io.Serializable; +import java.util.Arrays; + +public class ApgData implements Serializable { + private static final long serialVersionUID = 6314045536270848410L; + protected long mEncryptionKeyIds[] = null; + protected long mSignatureKeyId = 0; + protected String mSignatureUserId = null; + protected boolean mSignatureSuccess = false; + protected boolean mSignatureUnknown = false; + protected String mDecryptedData = null; + protected String mEncryptedData = null; + + public void setSignatureKeyId(long keyId) { + mSignatureKeyId = keyId; + } + + public long getSignatureKeyId() { + return mSignatureKeyId; + } + + public void setEncryptionKeys(long keyIds[]) { + mEncryptionKeyIds = keyIds; + } + + public long[] getEncryptionKeys() { + return mEncryptionKeyIds; + } + + public boolean hasSignatureKey() { + return mSignatureKeyId != 0; + } + + public boolean hasEncryptionKeys() { + return (mEncryptionKeyIds != null) && (mEncryptionKeyIds.length > 0); + } + + public String getEncryptedData() { + return mEncryptedData; + } + + public void setEncryptedData(String data) { + mEncryptedData = data; + } + + public String getDecryptedData() { + return mDecryptedData; + } + + public void setDecryptedData(String data) { + mDecryptedData = data; + } + + public void setSignatureUserId(String userId) { + mSignatureUserId = userId; + } + + public String getSignatureUserId() { + return mSignatureUserId; + } + + public boolean getSignatureSuccess() { + return mSignatureSuccess; + } + + public void setSignatureSuccess(boolean success) { + mSignatureSuccess = success; + } + + public boolean getSignatureUnknown() { + return mSignatureUnknown; + } + + public void setSignatureUnknown(boolean unknown) { + mSignatureUnknown = unknown; + } + + @Override + public String toString() { + String output = "mEncryptionKeyIds: " + Arrays.toString(mEncryptionKeyIds) + + "\nmSignatureKeyId: " + mSignatureKeyId + "\nmSignatureUserId: " + + mSignatureUserId + "\nmSignatureSuccess: " + mSignatureSuccess + + "\nmSignatureUnknown: " + mSignatureUnknown + "\nmDecryptedData: " + + mDecryptedData + "\nmEncryptedData: " + mEncryptedData; + + return output; + } +}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgIntentHelper.java b/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgIntentHelper.java new file mode 100644 index 000000000..77d1ebd42 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgIntentHelper.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2010-2011 K-9 Mail Contributors + * + * 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.thialfihar.android.apg.integration; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.widget.Toast; + +public class ApgIntentHelper { + + public static final String APG_INTENT_PREFIX = "org.thialfihar.android.apg.intent."; + + // Intents + public static final String ACTION_DECRYPT = APG_INTENT_PREFIX + "DECRYPT"; + public static final String ACTION_ENCRYPT = APG_INTENT_PREFIX + "ENCRYPT"; + public static final String ACTION_DECRYPT_FILE = APG_INTENT_PREFIX + "DECRYPT_FILE"; + public static final String ACTION_ENCRYPT_FILE = APG_INTENT_PREFIX + "ENCRYPT_FILE"; + public static final String ACTION_DECRYPT_AND_RETURN = APG_INTENT_PREFIX + "DECRYPT_AND_RETURN"; + public static final String ACTION_ENCRYPT_AND_RETURN = APG_INTENT_PREFIX + "ENCRYPT_AND_RETURN"; + public static final String ACTION_SELECT_PUBLIC_KEYS = APG_INTENT_PREFIX + "SELECT_PUBLIC_KEYS"; + public static final String ACTION_SELECT_SECRET_KEY = APG_INTENT_PREFIX + "SELECT_SECRET_KEY"; + public static final String ACTION_CREATE_KEY = APG_INTENT_PREFIX + "CREATE_KEY"; + public static final String ACTION_EDIT_KEY = APG_INTENT_PREFIX + "EDIT_KEY"; + + public static final String EXTRA_TEXT = "text"; + public static final String EXTRA_DATA = "data"; + public static final String EXTRA_ERROR = "error"; + public static final String EXTRA_DECRYPTED_MESSAGE = "decryptedMessage"; + public static final String EXTRA_ENCRYPTED_MESSAGE = "encryptedMessage"; + public static final String EXTRA_SIGNATURE = "signature"; + public static final String EXTRA_SIGNATURE_KEY_ID = "signatureKeyId"; + public static final String EXTRA_SIGNATURE_USER_ID = "signatureUserId"; + public static final String EXTRA_SIGNATURE_SUCCESS = "signatureSuccess"; + public static final String EXTRA_SIGNATURE_UNKNOWN = "signatureUnknown"; + public static final String EXTRA_USER_ID = "userId"; + public static final String EXTRA_USER_IDS = "userIds"; + public static final String EXTRA_KEY_ID = "keyId"; + public static final String EXTRA_ENCRYPTION_KEY_IDS = "encryptionKeyIds"; + public static final String EXTRA_SELECTION = "selection"; + public static final String EXTRA_MESSAGE = "message"; + public static final String EXTRA_NO_PASSPHRASE = "noPassphrase"; + public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generateDefaultKeys"; + public static final String EXTRA_INTENT_VERSION = "intentVersion"; + + public static final String RESULT_EXTRA_MASTER_KEY_IDS = "masterKeyIds"; + public static final String RESULT_EXTRA_USER_IDS = "userIds"; + + public static final String INTENT_VERSION = "1"; + + public static final int DECRYPT_MESSAGE = 0x21070001; + public static final int ENCRYPT_MESSAGE = 0x21070002; + public static final int SELECT_PUBLIC_KEYS = 0x21070003; + public static final int SELECT_SECRET_KEY = 0x21070004; + public static final int CREATE_KEY = 0x21070005; + public static final int EDIT_KEY = 0x21070006; + + private Activity activity; + + public ApgIntentHelper(Activity activity) { + this.activity = activity; + } + + /** + * Opens APG activity to create new key + * + * @param userIds + * value to specify prefilled values for user that should be created + * @return true when activity was found and executed successfully + */ + public boolean createNewKey(String userIds, boolean noPassphrase, boolean generateDefaultKeys) { + Intent intent = new Intent(ACTION_CREATE_KEY); + if (userIds != null) { + intent.putExtra(EXTRA_USER_IDS, userIds); + } + intent.putExtra(EXTRA_NO_PASSPHRASE, noPassphrase); + intent.putExtra(EXTRA_GENERATE_DEFAULT_KEYS, generateDefaultKeys); + + intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION); + try { + activity.startActivityForResult(intent, CREATE_KEY); + return true; + } catch (ActivityNotFoundException e) { + activityNotFound(); + return false; + } + } + + /** + * Opens APG activity to create new key + * + * @return true when activity was found and executed successfully + */ + public boolean createNewKey() { + return createNewKey(null, false, false); + } + + /** + * Opens APG activity to edit already existing key based on keyId + * + * @param keyId + * @return true when activity was found and executed successfully + */ + public boolean editKey(long keyId) { + Intent intent = new Intent(ACTION_EDIT_KEY); + intent.putExtra(EXTRA_KEY_ID, keyId); + intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION); + try { + activity.startActivityForResult(intent, EDIT_KEY); + return true; + } catch (ActivityNotFoundException e) { + activityNotFound(); + return false; + } + } + + /** + * Opens APG activity to select the signature key. + * + * @return true when activity was found and executed successfully + */ + public boolean selectSecretKey() { + Intent intent = new Intent(ACTION_SELECT_SECRET_KEY); + intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION); + try { + activity.startActivityForResult(intent, SELECT_SECRET_KEY); + return true; + } catch (ActivityNotFoundException e) { + activityNotFound(); + return false; + } + } + + /** + * Encrypts the given data by opening APGs encrypt activity. If encryptionKeys are given it + * encrypts immediately and goes back to your program after that + * + * @param data + * String that contains the message to be encrypted + * @param encryptionKeyIds + * long[] that holds the ids of the encryption keys + * @param signatureKeyId + * id of the signature key + * @return true when activity was found and executed successfully + */ + public boolean encrypt(String data, long[] encryptionKeyIds, long signatureKeyId, + boolean returnResult) { + Intent intent = new Intent(); + if (returnResult) { + intent.setAction(ACTION_ENCRYPT_AND_RETURN); + } else { + intent.setAction(ACTION_ENCRYPT); + } + intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION); + intent.setType("text/plain"); + intent.putExtra(EXTRA_TEXT, data); + intent.putExtra(EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + intent.putExtra(EXTRA_SIGNATURE_KEY_ID, signatureKeyId); + try { + activity.startActivityForResult(intent, ENCRYPT_MESSAGE); + return true; + } catch (ActivityNotFoundException e) { + activityNotFound(); + return false; + } + } + + /** + * Start the decrypt activity. + * + * @param activity + * @param data + * @param pgpData + * @return true when activity was found and executed successfully + */ + public boolean decrypt(String data, boolean returnResult) { + Intent intent = new Intent(); + if (returnResult) { + intent.setAction(ACTION_DECRYPT_AND_RETURN); + } else { + intent.setAction(ACTION_DECRYPT); + } + intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION); + intent.setType("text/plain"); + if (data == null) { + return false; + } + try { + intent.putExtra(EXTRA_TEXT, data); + activity.startActivityForResult(intent, DECRYPT_MESSAGE); + return true; + } catch (ActivityNotFoundException e) { + activityNotFound(); + return false; + } + } + + /** + * Handle the activity results that concern us. + * + * @param requestCode + * @param resultCode + * @param data + * @return handled or not + */ + public boolean onActivityResult(int requestCode, int resultCode, Intent data, ApgData apgData) { + + switch (requestCode) { + case SELECT_SECRET_KEY: + if (resultCode != Activity.RESULT_OK || data == null) { + // user canceled! + break; + } + apgData.setSignatureKeyId(data.getLongExtra(EXTRA_KEY_ID, 0)); + apgData.setSignatureUserId(data.getStringExtra(EXTRA_USER_ID)); + break; + + case SELECT_PUBLIC_KEYS: + if (resultCode != Activity.RESULT_OK || data == null) { + apgData.setEncryptionKeys(null); + break; + } + apgData.setEncryptionKeys(data.getLongArrayExtra(RESULT_EXTRA_MASTER_KEY_IDS)); + break; + + case ENCRYPT_MESSAGE: + if (resultCode != Activity.RESULT_OK || data == null) { + apgData.setEncryptionKeys(null); + break; + } + apgData.setEncryptedData(data.getStringExtra(EXTRA_ENCRYPTED_MESSAGE)); + break; + + case DECRYPT_MESSAGE: + if (resultCode != Activity.RESULT_OK || data == null) { + break; + } + + apgData.setSignatureUserId(data.getStringExtra(EXTRA_SIGNATURE_USER_ID)); + apgData.setSignatureKeyId(data.getLongExtra(EXTRA_SIGNATURE_KEY_ID, 0)); + apgData.setSignatureSuccess(data.getBooleanExtra(EXTRA_SIGNATURE_SUCCESS, false)); + apgData.setSignatureUnknown(data.getBooleanExtra(EXTRA_SIGNATURE_UNKNOWN, false)); + + apgData.setDecryptedData(data.getStringExtra(EXTRA_DECRYPTED_MESSAGE)); + break; + + default: + return false; + } + + return true; + } + + /** + * Select encryption keys. + * + * @param emails + * The emails that should be used for preselection. + * @return true when activity was found and executed successfully + */ + public boolean selectEncryptionKeys(String emails) { + return selectEncryptionKeys(emails, null); + } + + /** + * Select encryption keys. + * + * @param emails + * The emails that should be used for preselection. + * @param apgData + * ApgData with encryption keys and signature keys preselected + * @return true when activity was found and executed successfully + */ + public boolean selectEncryptionKeys(String emails, ApgData apgData) { + Intent intent = new Intent(ACTION_SELECT_PUBLIC_KEYS); + intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION); + + long[] initialKeyIds = null; + if (apgData == null || !apgData.hasEncryptionKeys()) { + + ContentProviderHelper cPHelper = new ContentProviderHelper(activity); + + initialKeyIds = cPHelper.getPublicKeyIdsFromEmail(emails); + + } else { + initialKeyIds = apgData.getEncryptionKeys(); + } + intent.putExtra(EXTRA_SELECTION, initialKeyIds); + + try { + activity.startActivityForResult(intent, SELECT_PUBLIC_KEYS); + return true; + } catch (ActivityNotFoundException e) { + activityNotFound(); + return false; + } + } + + private void activityNotFound() { + Toast.makeText(activity, "APG Activity not found! Is APG installed correctly?", + Toast.LENGTH_LONG).show(); + } +} diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgServiceHelper.java b/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgServiceHelper.java new file mode 100644 index 000000000..3f71f9647 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/integration/ApgServiceHelper.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2012 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.thialfihar.android.apg.integration; + +import java.io.InputStream; +import java.io.OutputStream; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +public class ApgServiceHelper { + + private final static String BLOB_URI = "content://org.thialfihar.android.apg.provider.apgserviceblobprovider"; + + private Context context; + + public ApgServiceHelper(Context context) { + this.context = context; + } + + /** + * Set up binary data to en/decrypt + * + * @param is + * InputStream to get the data from + */ + public void setBlob(InputStream is) { + Log.d(Constants.TAG, "setBlob() called"); + // 1. get the new contentUri + ContentResolver cr = context.getContentResolver(); + Uri contentUri = cr.insert(Uri.parse(BLOB_URI), new ContentValues()); + + // 2. insert binary data + OutputStream os = null; + try { + os = cr.openOutputStream(contentUri, "w"); + } catch (Exception e) { + Log.e(Constants.TAG, "... exception on setBlob", e); + } + + byte[] buffer = new byte[8]; + int len = 0; + try { + while ((len = is.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + Log.d(Constants.TAG, "... write finished, now closing"); + os.close(); + } catch (Exception e) { + Log.e(Constants.TAG, "... error on writing buffer", e); + } + +// mArgs.putString("BLOB", contentUri.toString()); + } + + /** + * Get the binary result + * + * <p> + * This gets your binary result. It only works if you called {@link #setBlob(InputStream)} + * before. + * + * If you did not call encrypt nor decrypt, this will be the same data as you inputed. + * </p> + * + * @return InputStream of the binary data which was en/decrypted + * + * @see #setBlob(InputStream) + * @see #getResult() + */ + public InputStream getBlobResult() { + // if (mArgs.containsKey("BLOB")) { + ContentResolver cr = context.getContentResolver(); + InputStream in = null; + try { +// in = cr.openInputStream(Uri.parse(mArgs.getString("BLOB"))); + } catch (Exception e) { + Log.e(Constants.TAG, "Could not return blob in result", e); + } + return in; + // } else { + // return null; + // } + } +} diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/integration/Constants.java b/APG-API-Lib/src/org/thialfihar/android/apg/integration/Constants.java new file mode 100644 index 000000000..7745f92d3 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/integration/Constants.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2012 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.thialfihar.android.apg.integration; + +public class Constants { + public static final String NAME = "apg"; + + public static final String TAG = "APG Integration Lib"; + + public static final String APG_PACKAGE_NAME = "org.thialfihar.android.apg"; + public static final int MIN_REQUIRED_VERSION = 50; + +} diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/integration/ContentProviderHelper.java b/APG-API-Lib/src/org/thialfihar/android/apg/integration/ContentProviderHelper.java new file mode 100644 index 000000000..7b725fe06 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/integration/ContentProviderHelper.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2010-2011 K-9 Mail Contributors + * + * 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.thialfihar.android.apg.integration; + +import android.app.Activity; +import android.content.ContentUris; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.widget.Toast; + +public class ContentProviderHelper { + public static final String AUTHORITY = Constants.APG_PACKAGE_NAME; + + public static final Uri CONTENT_URI_PUBLIC_KEY_RING_BY_KEY_ID = Uri.parse("content://" + + AUTHORITY + "/key_rings/public/key_id/"); + public static final Uri CONTENT_URI_PUBLIC_KEY_RING_BY_EMAILS = Uri.parse("content://" + + AUTHORITY + "/key_rings/public/emails/"); + + public static final Uri CONTENT_URI_SECRET_KEY_RING_BY_KEY_ID = Uri.parse("content://" + + AUTHORITY + "/key_rings/secret/key_id/"); + public static final Uri CONTENT_URI_SECRET_KEY_RING_BY_EMAILS = Uri.parse("content://" + + AUTHORITY + "/key_rings/secret/emails/"); + + private Context activity; + + public ContentProviderHelper(Activity activity) { + this.activity = activity; + } + + /** + * Get secret key ids based on a given email. + * + * @param context + * @param email + * The email in question. + * @return key ids + */ + public long[] getSecretKeyIdsFromEmail(String email) { + long ids[] = null; + try { + Uri contentUri = Uri.withAppendedPath(CONTENT_URI_SECRET_KEY_RING_BY_EMAILS, email); + Cursor c = activity.getContentResolver().query(contentUri, + new String[] { "master_key_id" }, null, null, null); + if (c != null && c.getCount() > 0) { + ids = new long[c.getCount()]; + while (c.moveToNext()) { + ids[c.getPosition()] = c.getLong(0); + } + } + + if (c != null) { + c.close(); + } + } catch (SecurityException e) { + insufficientPermissions(); + } + + return ids; + } + + /** + * Get public key ids based on a given email. + * + * @param context + * @param email + * The email in question. + * @return key ids + */ + public long[] getPublicKeyIdsFromEmail(String email) { + long ids[] = null; + try { + Uri contentUri = Uri.withAppendedPath(CONTENT_URI_PUBLIC_KEY_RING_BY_EMAILS, email); + Cursor c = activity.getContentResolver().query(contentUri, + new String[] { "master_key_id" }, null, null, null); + if (c != null && c.getCount() > 0) { + ids = new long[c.getCount()]; + while (c.moveToNext()) { + ids[c.getPosition()] = c.getLong(0); + } + } + + if (c != null) { + c.close(); + } + } catch (SecurityException e) { + insufficientPermissions(); + } + + return ids; + } + + /** + * Find out if a given email has a secret key. + * + * @param context + * @param email + * The email in question. + * @return true if there is a secret key for this email. + */ + public boolean hasSecretKeyForEmail(String email) { + try { + Uri contentUri = Uri.withAppendedPath(CONTENT_URI_SECRET_KEY_RING_BY_EMAILS, email); + Cursor c = activity.getContentResolver().query(contentUri, + new String[] { "master_key_id" }, null, null, null); + if (c != null && c.getCount() > 0) { + c.close(); + return true; + } + if (c != null) { + c.close(); + } + } catch (SecurityException e) { + insufficientPermissions(); + } + return false; + } + + /** + * Find out if a given email has a public key. + * + * @param context + * @param email + * The email in question. + * @return true if there is a public key for this email. + */ + public boolean hasPublicKeyForEmail(String email) { + try { + Uri contentUri = Uri.withAppendedPath(CONTENT_URI_PUBLIC_KEY_RING_BY_EMAILS, email); + Cursor c = activity.getContentResolver().query(contentUri, + new String[] { "master_key_id" }, null, null, null); + if (c != null && c.getCount() > 0) { + c.close(); + return true; + } + if (c != null) { + c.close(); + } + } catch (SecurityException e) { + insufficientPermissions(); + } + return false; + } + + /** + * Get the user id based on the key id. + * + * @param context + * @param keyId + * @return user id + */ + public String getUserId(long keyId) { + String userId = null; + try { + Uri contentUri = ContentUris.withAppendedId(CONTENT_URI_SECRET_KEY_RING_BY_KEY_ID, + keyId); + Cursor c = activity.getContentResolver().query(contentUri, new String[] { "user_id" }, + null, null, null); + if (c != null && c.moveToFirst()) { + userId = c.getString(0); + } + + if (c != null) { + c.close(); + } + } catch (SecurityException e) { + insufficientPermissions(); + } + + if (userId == null) { + userId = "unknown"; + } + return userId; + } + + private void insufficientPermissions() { + Toast.makeText(activity, "Permission to access APG Provider is missing!", Toast.LENGTH_LONG) + .show(); + } +} diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/integration/Util.java b/APG-API-Lib/src/org/thialfihar/android/apg/integration/Util.java new file mode 100644 index 000000000..01c6bb699 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/integration/Util.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2010-2011 K-9 Mail Contributors + * + * 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.thialfihar.android.apg.integration; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; + +import android.widget.Toast; + +public class Util { + + /** + * Check whether APG is installed and at a high enough version. + * + * @param context + * @return whether a suitable version of APG was found + */ + public boolean isApgAvailable(Context context) { + try { + PackageInfo pi = context.getPackageManager().getPackageInfo(Constants.APG_PACKAGE_NAME, + 0); + if (pi.versionCode >= Constants.MIN_REQUIRED_VERSION) { + return true; + } else { + Toast.makeText(context, + "This APG version is not supported! Please update to a newer one!", + Toast.LENGTH_LONG).show(); + } + } catch (NameNotFoundException e) { + // not found + } + + return false; + } +} diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgEncryptDecryptHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgEncryptDecryptHandler.aidl new file mode 100644 index 000000000..ff6b7254c --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgEncryptDecryptHandler.aidl @@ -0,0 +1,16 @@ +package org.thialfihar.android.apg.service; + +interface IApgEncryptDecryptHandler { + /** + * Either output or streamUri is given. One of them is null + * + */ + oneway void onSuccessEncrypt(in byte[] outputBytes, in String outputUri); + + oneway void onSuccessDecrypt(in byte[] outputBytes, in String outputUri, in boolean signature, + in long signatureKeyId, in String signatureUserId, in boolean signatureSuccess, + in boolean signatureUnknown); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgHelperHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgHelperHandler.aidl new file mode 100644 index 000000000..bb405329a --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgHelperHandler.aidl @@ -0,0 +1,9 @@ +package org.thialfihar.android.apg.service; + +interface IApgHelperHandler { + + oneway void onSuccessGetDecryptionKey(in long secretKeyId, in boolean symmetric); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgService.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgService.aidl new file mode 100644 index 000000000..71c6a9e42 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgService.aidl @@ -0,0 +1,130 @@ +package org.thialfihar.android.apg.service; + +import org.thialfihar.android.apg.service.IApgEncryptDecryptHandler; +import org.thialfihar.android.apg.service.IApgSignVerifyHandler; +import org.thialfihar.android.apg.service.IApgHelperHandler; + +/** + * All methods are oneway, which means they are asynchronous and non-blocking. + * Results are returned into given Handler, which has to be implemented on client side. + */ +interface IApgService { + + /** + * Encrypt + * + * Either inputBytes or inputUri is given, the other should be null. + * + * @param inputBytes + * Byte array you want to encrypt + * @param inputUri + * Blob in ContentProvider you want to encrypt + * @param useAsciiArmor + * Convert bytes to ascii armored text to guard against encoding problems + * @param compression + * Compression: 0x21070001: none, 1: Zip, 2: Zlib, 3: BZip2 + * @param encryptionKeyIds + * Ids of public keys used for encryption + * @param symmetricEncryptionAlgorithm + * 7: AES-128, 8: AES-192, 9: AES-256, 4: Blowfish, 10: Twofish, 3: CAST5, + * 6: DES, 2: Triple DES, 1: IDEA + * @param handler + * Results are returned to this IApgEncryptDecryptHandler Handler + * to onSuccessEncrypt(in byte[] output), after successful encryption + */ + oneway void encryptAsymmetric(in byte[] inputBytes, in String inputUri, in boolean useAsciiArmor, + in int compression, in long[] encryptionKeyIds, in int symmetricEncryptionAlgorithm, + in IApgEncryptDecryptHandler handler); + + /** + * Same as encryptAsymmetric but using a passphrase for symmetric encryption + * + * @param encryptionPassphrase + * Passphrase for direct symmetric encryption using symmetricEncryptionAlgorithm + */ + oneway void encryptSymmetric(in byte[] inputBytes, in String inputUri, in boolean useAsciiArmor, + in int compression, in String encryptionPassphrase, in int symmetricEncryptionAlgorithm, + in IApgEncryptDecryptHandler handler); + + /** + * Encrypt and sign + * + * Either inputBytes or inputUri is given, the other should be null. + * + * @param inputBytes + * Byte array you want to encrypt + * @param inputUri + * Blob in ContentProvider you want to encrypt + * @param useAsciiArmor + * Convert bytes to ascii armored text to guard against encoding problems + * @param compression + * Compression: 0x21070001: none, 1: Zip, 2: Zlib, 3: BZip2 + * @param encryptionKeyIds + * Ids of public keys used for encryption + * @param symmetricEncryptionAlgorithm + * 7: AES-128, 8: AES-192, 9: AES-256, 4: Blowfish, 10: Twofish, 3: CAST5, + * 6: DES, 2: Triple DES, 1: IDEA + * @param signatureKeyId + * Key id of key to sign with + * @param signatureHashAlgorithm + * 1: MD5, 3: RIPEMD-160, 2: SHA-1, 11: SHA-224, 8: SHA-256, 9: SHA-384, + * 10: SHA-512 + * @param signatureForceV3 + * Force V3 signatures + * @param signaturePassphrase + * Passphrase to unlock signature key + * @param handler + * Results are returned to this IApgEncryptDecryptHandler Handler + * to onSuccessEncrypt(in byte[] output), after successful encryption and signing + */ + oneway void encryptAndSignAsymmetric(in byte[] inputBytes, in String inputUri, + in boolean useAsciiArmor, in int compression, in long[] encryptionKeyIds, + in int symmetricEncryptionAlgorithm, in long signatureKeyId, in int signatureHashAlgorithm, + in boolean signatureForceV3, in String signaturePassphrase, + in IApgEncryptDecryptHandler handler); + + /** + * Same as encryptAndSignAsymmetric but using a passphrase for symmetric encryption + * + * @param encryptionPassphrase + * Passphrase for direct symmetric encryption using symmetricEncryptionAlgorithm + */ + oneway void encryptAndSignSymmetric(in byte[] inputBytes, in String inputUri, + in boolean useAsciiArmor, in int compression, in String encryptionPassphrase, + in int symmetricEncryptionAlgorithm, in long signatureKeyId, in int signatureHashAlgorithm, + in boolean signatureForceV3, in String signaturePassphrase, + in IApgEncryptDecryptHandler handler); + + /** + * Decrypts and verifies given input bytes. If no signature is present this method + * will only decrypt. + * + * @param inputBytes + * Byte array you want to decrypt and verify + * @param inputUri + * Blob in ContentProvider you want to decrypt and verify + * @param keyPassphrase + * Passphrase to unlock secret key for decryption. + * @param handler + * Handler where to return results to after successful encryption + */ + oneway void decryptAndVerifyAsymmetric(in byte[] inputBytes, in String inputUri, + in String keyPassphrase, in IApgEncryptDecryptHandler handler); + + /** + * Same as decryptAndVerifyAsymmetric but for symmetric decryption. + * + * @param encryptionPassphrase + * Passphrase to decrypt + */ + oneway void decryptAndVerifySymmetric(in byte[] inputBytes, in String inputUri, + in String encryptionPassphrase, in IApgEncryptDecryptHandler handler); + + /** + * + */ + oneway void getDecryptionKey(in byte[] inputBytes, in String inputUri, + in IApgHelperHandler handler); + + +}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgSignVerifyHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgSignVerifyHandler.aidl new file mode 100644 index 000000000..1375d1548 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgSignVerifyHandler.aidl @@ -0,0 +1,11 @@ +package org.thialfihar.android.apg.service; + +interface IApgSignVerifyHandler { + oneway void onSuccessSign(in byte[] outputBytes, in String outputUri); + + oneway void onSuccessVerify(in boolean signature, in long signatureKeyId, + in String signatureUserId, in boolean signatureSuccess, in boolean signatureUnknown); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file |