removed deprecated code, reworked service blob provider

This commit is contained in:
Dominik 2012-11-15 17:54:25 +01:00
parent d61e00ae6c
commit e247fe18af
32 changed files with 885 additions and 2322 deletions

View File

@ -356,6 +356,13 @@
android:name=".provider.ApgProvider"
android:authorities="org.thialfihar.android.apg"
android:readPermission="org.thialfihar.android.apg.permission.READ_KEY_DETAILS" />
<!-- TODO: authority! -->
<provider
android:name=".provider.ApgServiceBlobProvider"
android:authorities="org.thialfihar.android.apg.provider.apgserviceblobprovider"
android:permission="org.thialfihar.android.apg.permission.STORE_BLOBS" />
<!-- DEPRECATED: -->
<!-- <provider -->
@ -381,11 +388,6 @@
<!-- android:value="2" /> -->
<!-- </service> -->
<!-- <provider -->
<!-- android:name=".deprecated.ApgServiceBlobProvider" -->
<!-- android:authorities="org.thialfihar.android.apg.provider.apgserviceblobprovider" -->
<!-- android:permission="org.thialfihar.android.apg.permission.STORE_BLOBS" /> -->
</application>
</manifest>

View File

@ -1,836 +0,0 @@
/*
* Copyright (C) 2011 Markus Doits <markus.doits@googlemail.com>
*
* 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.deprecated;
import org.thialfihar.android.apg.deprecated.ApgConInterface.OnCallFinishListener;
import org.thialfihar.android.apg.deprecated.IApgService2;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import org.thialfihar.android.apg.util.Log;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
/**
* A APG-AIDL-Wrapper
*
* <p>
* This class can be used by other projects to simplify connecting to the
* APG-AIDL-Service. Kind of wrapper of for AIDL.
* </p>
*
* <p>
* It is not used in this project.
* </p>
*
* @author Markus Doits <markus.doits@googlemail.com>
* @version 1.1rc1
*
*/
public class ApgCon {
private static final boolean LOCAL_LOGV = true;
private static final boolean LOCAL_LOGD = true;
private final static String TAG = "ApgCon";
private final static int API_VERSION = 2; // aidl api-version it expects
private final static String BLOB_URI = "content://org.thialfihar.android.apg.provider.apgserviceblobprovider";
/**
* How many seconds to wait for a connection to AGP when connecting.
* Being unsuccessful for this number of seconds, a connection
* is assumed to be failed.
*/
public int secondsToWaitForConnection = 15;
private class CallAsync extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... arg) {
if( LOCAL_LOGD ) Log.d(TAG, "Async execution starting");
call(arg[0]);
return null;
}
protected void onPostExecute(Void res) {
if( LOCAL_LOGD ) Log.d(TAG, "Async execution finished");
mAsyncRunning = false;
}
}
private final Context mContext;
private final error mConnectionStatus;
private boolean mAsyncRunning = false;
private OnCallFinishListener mOnCallFinishListener;
private final Bundle mResult = new Bundle();
private final Bundle mArgs = new Bundle();
private final ArrayList<String> mErrorList = new ArrayList<String>();
private final ArrayList<String> mWarningList = new ArrayList<String>();
/** Remote service for decrypting and encrypting data */
private IApgService2 mApgService = null;
/** Set apgService accordingly to connection status */
private ServiceConnection mApgConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if( LOCAL_LOGD ) Log.d(TAG, "IApgService bound to apgService");
mApgService = IApgService2.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName className) {
if( LOCAL_LOGD ) Log.d(TAG, "IApgService disconnected");
mApgService = null;
}
};
/**
* Different types of local errors
*/
public static enum error {
/**
* no error
*/
NO_ERROR,
/**
* generic error
*/
GENERIC,
/**
* connection to apg service not possible
*/
CANNOT_BIND_TO_APG,
/**
* function to call not provided
*/
CALL_MISSING,
/**
* apg service does not know what to do
*/
CALL_NOT_KNOWN,
/**
* could not find APG being installed
*/
APG_NOT_FOUND,
/**
* found APG but without AIDL interface
*/
APG_AIDL_MISSING,
/**
* found APG but with wrong API
*/
APG_API_MISSMATCH
}
private static enum ret {
ERROR, // returned from AIDL
RESULT, // returned from AIDL
WARNINGS, // mixed AIDL and LOCAL
ERRORS, // mixed AIDL and LOCAL
}
/**
* Constructor
*
* <p>
* Creates a new ApgCon object and searches for the right APG version on
* initialization. If not found, errors are printed to the error log.
* </p>
*
* @param ctx
* the running context
*/
public ApgCon(Context ctx) {
if( LOCAL_LOGV ) Log.v(TAG, "EncryptionService created");
mContext = ctx;
error tmpError = null;
try {
if( LOCAL_LOGV ) Log.v(TAG, "Searching for the right APG version");
ServiceInfo apgServices[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg",
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services;
if (apgServices == null) {
Log.e(TAG, "Could not fetch services");
tmpError = error.GENERIC;
} else {
boolean apgServiceFound = false;
for (ServiceInfo inf : apgServices) {
if( LOCAL_LOGV ) Log.v(TAG, "Found service of APG: " + inf.name);
if (inf.name.equals("org.thialfihar.android.apg.ApgService")) {
apgServiceFound = true;
if (inf.metaData == null) {
Log.w(TAG, "Could not determine ApgService API");
Log.w(TAG, "This probably won't work!");
mWarningList.add("(LOCAL) Could not determine ApgService API");
tmpError = error.APG_API_MISSMATCH;
} else if (inf.metaData.getInt("api_version") != API_VERSION) {
Log.w(TAG, "Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
Log.w(TAG, "This probably won't work!");
mWarningList.add("(LOCAL) Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION);
tmpError = error.APG_API_MISSMATCH;
} else {
if( LOCAL_LOGV ) Log.v(TAG, "Found api_version " + API_VERSION + ", everything should work");
tmpError = error.NO_ERROR;
}
}
}
if (!apgServiceFound) {
Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work");
mErrorList.add("(LOCAL) Could not find APG with AIDL interface, this probably won't work");
mResult.putInt(ret.ERROR.name(), error.APG_AIDL_MISSING.ordinal());
tmpError = error.APG_NOT_FOUND;
}
}
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Could not find APG, is it installed?", e);
mErrorList.add("(LOCAL) Could not find APG, is it installed?");
mResult.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal());
tmpError = error.APG_NOT_FOUND;
}
mConnectionStatus = tmpError;
}
/** try to connect to the apg service */
private boolean connect() {
if( LOCAL_LOGV ) Log.v(TAG, "trying to bind the apgService to context");
if (mApgService != null) {
if( LOCAL_LOGV ) Log.v(TAG, "allready connected");
return true;
}
try {
mContext.bindService(new Intent(IApgService2.class.getName()), mApgConnection, Context.BIND_AUTO_CREATE);
} catch (Exception e) {
Log.e(TAG, "could not bind APG service", e);
return false;
}
int waitCount = 0;
while (mApgService == null && waitCount++ < secondsToWaitForConnection) {
if( LOCAL_LOGV ) Log.v(TAG, "sleeping 1 second to wait for apg");
android.os.SystemClock.sleep(1000);
}
if (waitCount >= secondsToWaitForConnection) {
if( LOCAL_LOGV ) Log.v(TAG, "slept waiting for nothing!");
return false;
}
return true;
}
/**
* Disconnects ApgCon from Apg
*
* <p>
* This should be called whenever all work with APG is done (e.g. everything
* you wanted to encrypt is encrypted), since connections with AIDL should
* not be upheld indefinitely.
* <p>
*
* <p>
* Also, if you destroy you end using your ApgCon-instance, this must be
* called or else the connection to APG is leaked
* </p>
*/
public void disconnect() {
if( LOCAL_LOGV ) Log.v(TAG, "disconnecting apgService");
if (mApgService != null) {
mContext.unbindService(mApgConnection);
mApgService = null;
}
}
private boolean initialize() {
if (mApgService == null) {
if (!connect()) {
if( LOCAL_LOGV ) Log.v(TAG, "connection to apg service failed");
return false;
}
}
return true;
}
/**
* Calls a function from APG's AIDL-interface
*
* <p>
* After you have set up everything with {@link #setArg(String, String)}
* (and variants), you can call a function of the AIDL-interface. This
* will:
* <ul>
* <li>start connection to the remote interface (if not already connected)</li>
* <li>call the function passed with all parameters synchronously</li>
* <li>set up everything to retrieve the result and/or warnings/errors</li>
* <li>call the callback if provided
* </ul>
* </p>
*
* <p>
* Note your thread will be blocked during execution - if you want to call
* the function asynchronously, see {@link #callAsync(String)}.
* </p>
*
* @param function
* a remote function to call
* @return true, if call successful (= no errors), else false
*
* @see #callAsync(String)
* @see #setArg(String, String)
* @see #setOnCallFinishListener(OnCallFinishListener)
*/
public boolean call(String function) {
boolean success = this.call(function, mArgs, mResult);
if (mOnCallFinishListener != null) {
try {
if( LOCAL_LOGD ) Log.d(TAG, "About to execute callback");
mOnCallFinishListener.onCallFinish(mResult);
if( LOCAL_LOGD ) Log.d(TAG, "Callback executed");
} catch (Exception e) {
Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage(), e);
mWarningList.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage());
}
}
return success;
}
/**
* Calls a function of remote interface asynchronously
*
* <p>
* This does exactly the same as {@link #call(String)}, but asynchronously.
* While connection to APG and work are done in background, your thread can
* go on executing.
* <p>
*
* <p>
* To see whether the task is finished, you have two possibilities:
* <ul>
* <li>In your thread, poll {@link #isRunning()}</li>
* <li>Supply a callback with {@link #setOnCallFinishListener(OnCallFinishListener)}</li>
* </ul>
* </p>
*
* @param function
* a remote function to call
*
* @see #call(String)
* @see #isRunning()
* @see #setOnCallFinishListener(OnCallFinishListener)
*/
public void callAsync(String function) {
mAsyncRunning = true;
new CallAsync().execute(function);
}
private boolean call(String function, Bundle pArgs, Bundle pReturn) {
if (!initialize()) {
mErrorList.add("(LOCAL) Cannot bind to ApgService");
mResult.putInt(ret.ERROR.name(), error.CANNOT_BIND_TO_APG.ordinal());
return false;
}
if (function == null || function.length() == 0) {
mErrorList.add("(LOCAL) Function to call missing");
mResult.putInt(ret.ERROR.name(), error.CALL_MISSING.ordinal());
return false;
}
try {
Boolean success = (Boolean) IApgService2.class.getMethod(function, Bundle.class, Bundle.class).invoke(mApgService, pArgs, pReturn);
mErrorList.addAll(pReturn.getStringArrayList(ret.ERRORS.name()));
mWarningList.addAll(pReturn.getStringArrayList(ret.WARNINGS.name()));
return success;
} catch (NoSuchMethodException e) {
Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage(), e);
mErrorList.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage());
mResult.putInt(ret.ERROR.name(), error.CALL_NOT_KNOWN.ordinal());
return false;
} catch (InvocationTargetException e) {
Throwable orig = e.getTargetException();
Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage(), orig);
mErrorList.add("(LOCAL) Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage());
return false;
} catch (Exception e) {
Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage(), e);
mErrorList.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage());
mResult.putInt(ret.ERROR.name(), error.GENERIC.ordinal());
return false;
}
}
/**
* Set a string argument for APG
*
* <p>
* This defines a string argument for APG's AIDL-interface.
* </p>
*
* <p>
* To know what key-value-pairs are possible (or required), take a look into
* the IApgService.aidl
* </p>
*
* <p>
* Note that parameters are not reseted after a call, so you have to
* reset ({@link #clearArgs()}) them manually if you want to.
* </p>
*
*
* @param key
* the key
* @param val
* the value
*
* @see #clearArgs()
*/
public void setArg(String key, String val) {
mArgs.putString(key, val);
}
/**
* Set a string-array argument for APG
*
* <p>
* If the AIDL-parameter is an {@literal ArrayList<String>}, you have to use
* this function.
* </p>
*
* <code>
* <pre>
* setArg("a key", new String[]{ "entry 1", "entry 2" });
* </pre>
* </code>
*
* @param key
* the key
* @param vals
* the value
*
* @see #setArg(String, String)
*/
public void setArg(String key, String vals[]) {
ArrayList<String> list = new ArrayList<String>();
for (String val : vals) {
list.add(val);
}
mArgs.putStringArrayList(key, list);
}
/**
* Set up a boolean argument for APG
*
* @param key
* the key
* @param vals
* the value
*
* @see #setArg(String, String)
*/
public void setArg(String key, boolean val) {
mArgs.putBoolean(key, val);
}
/**
* Set up a int argument for APG
*
* @param key
* the key
* @param vals
* the value
*
* @see #setArg(String, String)
*/
public void setArg(String key, int val) {
mArgs.putInt(key, val);
}
/**
* Set up a int-array argument for APG
* <p>
* If the AIDL-parameter is an {@literal ArrayList<Integer>}, you have to
* use this function.
* </p>
*
* @param key
* the key
* @param vals
* the value
*
* @see #setArg(String, String)
*/
public void setArg(String key, int vals[]) {
ArrayList<Integer> list = new ArrayList<Integer>();
for (int val : vals) {
list.add(val);
}
mArgs.putIntegerArrayList(key, list);
}
/**
* Set up binary data to en/decrypt
*
* @param is
* InputStream to get the data from
*/
public void setBlob(InputStream is) {
if( LOCAL_LOGD ) Log.d(TAG, "setBlob() called");
// 1. get the new contentUri
ContentResolver cr = mContext.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(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);
}
if(LOCAL_LOGD) Log.d(TAG, "... write finished, now closing");
os.close();
} catch (Exception e) {
Log.e(TAG, "... error on writing buffer", e);
}
mArgs.putString("BLOB", contentUri.toString() );
}
/**
* Clears all arguments
*
* <p>
* Anything the has been set up with the various
* {@link #setArg(String, String)} functions is cleared.
* </p>
*
* <p>
* Note that any warning, error, callback, result, etc. is NOT cleared with
* this.
* </p>
*
* @see #reset()
*/
public void clearArgs() {
mArgs.clear();
}
/**
* Return the object associated with the key
*
* @param key
* the object's key you want to return
* @return an object at position key, or null if not set
*/
public Object getArg(String key) {
return mArgs.get(key);
}
/**
* Iterates through the errors
*
* <p>
* With this method you can iterate through all errors. The errors are only
* returned once and deleted immediately afterwards, so you can only return
* each error once.
* </p>
*
* @return a human readable description of a error that happened, or null if
* no more errors
*
* @see #hasNextError()
* @see #clearErrors()
*/
public String getNextError() {
if (mErrorList.size() != 0)
return mErrorList.remove(0);
else
return null;
}
/**
* Check if there are any new errors
*
* @return true, if there are unreturned errors, false otherwise
*
* @see #getNextError()
*/
public boolean hasNextError() {
return mErrorList.size() != 0;
}
/**
* Get the numeric representation of the last error
*
* <p>
* Values <100 mean the error happened locally, values >=100 mean the error
* happened at the remote side (APG). See the IApgService.aidl (or get the
* human readable description with {@link #getNextError()}) for what
* errors >=100 mean.
* </p>
*
* @return the id of the error that happened
*/
public int getError() {
if (mResult.containsKey(ret.ERROR.name()))
return mResult.getInt(ret.ERROR.name());
else
return -1;
}
/**
* Iterates through the warnings
*
* <p>
* With this method you can iterate through all warnings. Warnings are
* only returned once and deleted immediately afterwards, so you can only
* return each warning once.
* </p>
*
* @return a human readable description of a warning that happened, or null
* if no more warnings
*
* @see #hasNextWarning()
* @see #clearWarnings()
*/
public String getNextWarning() {
if (mWarningList.size() != 0)
return mWarningList.remove(0);
else
return null;
}
/**
* Check if there are any new warnings
*
* @return true, if there are unreturned warnings, false otherwise
*
* @see #getNextWarning()
*/
public boolean hasNextWarning() {
return mWarningList.size() != 0;
}
/**
* Get the result
*
* <p>
* This gets your result. After doing an encryption or decryption with APG,
* you get the output with this function.
* </p>
*
* <p>
* Note when your last remote call is unsuccessful, the result will
* still have the same value like the last successful call (or null, if no
* call was successful). To ensure you do not work with old call's results,
* either be sure to {@link #reset()} (or at least {@link #clearResult()})
* your instance before each new call or always check that
* {@link #hasNextError()} is false.
* </p>
*
* <p>
* Note: When handling binary data with {@link #setBlob(InputStream)}, you
* get your result with {@link #getBlobResult()}.
* </p>
*
* @return the mResult of the last {@link #call(String)} or
* {@link #callAsync(String)}.
*
* @see #reset()
* @see #clearResult()
* @see #getResultBundle()
* @see #getBlobResult()
*/
public String getResult() {
return mResult.getString(ret.RESULT.name());
}
/**
* 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 = mContext.getContentResolver();
InputStream in = null;
try {
in = cr.openInputStream(Uri.parse(mArgs.getString("BLOB")));
} catch( Exception e ) {
Log.e(TAG, "Could not return blob in result", e);
}
return in;
} else {
return null;
}
}
/**
* Get the result bundle
*
* <p>
* Unlike {@link #getResult()}, which only returns any en-/decrypted
* message, this function returns the complete information that was returned
* by Apg. This also includes the "RESULT", but additionally the warnings,
* errors and any other information.
* </p>
* <p>
* For warnings and errors it is suggested to use the functions that are
* provided here, namely {@link #getError()}, {@link #getNextError()},
* {@link #get_next_Warning()} etc.), but if any call returns something non
* standard, you have access to the complete result bundle to extract the
* information.
* </p>
*
* @return the complete result bundle of the last call to apg
*/
public Bundle getResultBundle() {
return mResult;
}
public error getConnectionStatus() {
return mConnectionStatus;
}
/**
* Clears all unfetched errors
*
* @see #getNextError()
* @see #hasNextError()
*/
public void clearErrors() {
mErrorList.clear();
mResult.remove(ret.ERROR.name());
}
/**
* Clears all unfetched warnings
*
* @see #getNextWarning()
* @see #hasNextWarning()
*/
public void clearWarnings() {
mWarningList.clear();
}
/**
* Clears the last mResult
*
* @see #getResult()
*/
public void clearResult() {
mResult.remove(ret.RESULT.name());
}
/**
* Set a callback listener when call to AIDL finishes
*
* @param obj
* a object to call back after async execution
* @see ApgConInterface
*/
public void setOnCallFinishListener(OnCallFinishListener lis) {
mOnCallFinishListener = lis;
}
/**
* Clears any callback object
*
* @see #setOnCallFinishListener(OnCallFinishListener)
*/
public void clearOnCallFinishListener() {
mOnCallFinishListener = null;
}
/**
* Checks if an async execution is running
*
* <p>
* If you started something with {@link #callAsync(String)}, this will
* return true if the task is still running
* </p>
*
* @return true, if an async task is still running, false otherwise
*
* @see #callAsync(String)
*
*/
public boolean isRunning() {
return mAsyncRunning;
}
/**
* Completely resets your instance
*
* <p>
* This currently resets everything in this instance. Errors, warnings,
* results, callbacks, ... are removed. Any connection to the remote
* interface is upheld, though.
* </p>
*
* <p>
* Note when an async execution ({@link #callAsync(String)}) is
* running, it's result, warnings etc. will still be evaluated (which might
* be not what you want). Also mind that any callback you set is also
* reseted, so when finishing the execution any before defined callback will
* NOT BE TRIGGERED.
* </p>
*/
public void reset() {
clearErrors();
clearWarnings();
clearArgs();
clearOnCallFinishListener();
mResult.clear();
}
}

View File

@ -1,21 +0,0 @@
/*
* 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.deprecated;
public interface ApgConInterface {
public static interface OnCallFinishListener {
public abstract void onCallFinish(android.os.Bundle result);
}
}

View File

@ -1,673 +0,0 @@
///*
// * 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.deprecated;
//
//import java.io.ByteArrayInputStream;
//import java.io.ByteArrayOutputStream;
//import java.io.IOException;
//import java.io.InputStream;
//import java.io.OutputStream;
//import java.lang.reflect.Method;
//import java.util.ArrayList;
//import java.util.HashMap;
//import java.util.HashSet;
//import java.util.Iterator;
//
//import org.thialfihar.android.apg.deprecated.IApgService2;
//import org.thialfihar.android.apg.Id;
//import org.thialfihar.android.apg.R;
//import org.thialfihar.android.apg.deprecated.IApgService2.Stub;
//import org.thialfihar.android.apg.Id.database;
//import org.thialfihar.android.apg.R.string;
//import org.thialfihar.android.apg.helper.PGPHelper;
//import org.thialfihar.android.apg.helper.PGPMain;
//import org.thialfihar.android.apg.helper.Preferences;
//import org.thialfihar.android.apg.provider.KeyRings;
//import org.thialfihar.android.apg.provider.Keys;
//import org.thialfihar.android.apg.provider.UserIds;
//import org.thialfihar.android.apg.service.PassphraseCacheService;
//import org.thialfihar.android.apg.util.InputData;
//
//import android.content.ContentResolver;
//import android.content.Intent;
//import android.database.Cursor;
//import android.database.sqlite.SQLiteQueryBuilder;
//import android.net.Uri;
//import android.os.Bundle;
//import android.os.IBinder;
//import org.thialfihar.android.apg.util.Log;
//
///**
// * ATTENTION:
// *
// * This is the old ApgService used as remote service over aidl interface. It will be reworked!
// *
// */
//public class ApgService2 extends PassphraseCacheService {
// private final static String TAG = "ApgService";
// public static final boolean LOCAL_LOGV = true;
// public static final boolean LOCAL_LOGD = true;
//
// @Override
// public IBinder onBind(Intent intent) {
// if (LOCAL_LOGD)
// Log.d(TAG, "bound");
// return mBinder;
// }
//
// /** error status */
// private static enum error {
// ARGUMENTS_MISSING, APG_FAILURE, NO_MATCHING_SECRET_KEY, PRIVATE_KEY_PASSPHRASE_WRONG, PRIVATE_KEY_PASSPHRASE_MISSING;
//
// public int shiftedOrdinal() {
// return ordinal() + 100;
// }
// }
//
// private static enum call {
// encrypt_with_passphrase, encrypt_with_public_key, decrypt, get_keys
// }
//
// /** all arguments that can be passed by calling application */
// public static enum arg {
// MESSAGE, // message to encrypt or to decrypt
// SYMMETRIC_PASSPHRASE, // key for symmetric en/decryption
// PUBLIC_KEYS, // public keys for encryption
// ENCRYPTION_ALGORYTHM, // encryption algorithm
// HASH_ALGORYTHM, // hash algorithm
// ARMORED_OUTPUT, // whether to armor output
// FORCE_V3_SIGNATURE, // whether to force v3 signature
// COMPRESSION, // what compression to use for encrypted output
// SIGNATURE_KEY, // key for signing
// PRIVATE_KEY_PASSPHRASE, // passphrase for encrypted private key
// KEY_TYPE, // type of key (private or public)
// BLOB, // blob passed
// }
//
// /** all things that might be returned */
// private static enum ret {
// ERRORS, // string array list with errors
// WARNINGS, // string array list with warnings
// ERROR, // numeric error
// RESULT, // en-/decrypted
// FINGERPRINTS, // fingerprints of keys
// USER_IDS, // user ids
// }
//
// /** required arguments for each AIDL function */
// private static final HashMap<String, HashSet<arg>> FUNCTIONS_REQUIRED_ARGS = new HashMap<String, HashSet<arg>>();
// static {
// HashSet<arg> args = new HashSet<arg>();
// args.add(arg.SYMMETRIC_PASSPHRASE);
// FUNCTIONS_REQUIRED_ARGS.put(call.encrypt_with_passphrase.name(), args);
//
// args = new HashSet<arg>();
// args.add(arg.PUBLIC_KEYS);
// FUNCTIONS_REQUIRED_ARGS.put(call.encrypt_with_public_key.name(), args);
//
// args = new HashSet<arg>();
// FUNCTIONS_REQUIRED_ARGS.put(call.decrypt.name(), args);
//
// args = new HashSet<arg>();
// args.add(arg.KEY_TYPE);
// FUNCTIONS_REQUIRED_ARGS.put(call.get_keys.name(), args);
// }
//
// /** optional arguments for each AIDL function */
// private static final HashMap<String, HashSet<arg>> FUNCTIONS_OPTIONAL_ARGS = new HashMap<String, HashSet<arg>>();
// static {
// HashSet<arg> args = new HashSet<arg>();
// args.add(arg.ENCRYPTION_ALGORYTHM);
// args.add(arg.HASH_ALGORYTHM);
// args.add(arg.ARMORED_OUTPUT);
// args.add(arg.FORCE_V3_SIGNATURE);
// args.add(arg.COMPRESSION);
// args.add(arg.PRIVATE_KEY_PASSPHRASE);
// args.add(arg.SIGNATURE_KEY);
// args.add(arg.BLOB);
// args.add(arg.MESSAGE);
// FUNCTIONS_OPTIONAL_ARGS.put(call.encrypt_with_passphrase.name(), args);
// FUNCTIONS_OPTIONAL_ARGS.put(call.encrypt_with_public_key.name(), args);
//
// args = new HashSet<arg>();
// args.add(arg.SYMMETRIC_PASSPHRASE);
// args.add(arg.PUBLIC_KEYS);
// args.add(arg.PRIVATE_KEY_PASSPHRASE);
// args.add(arg.MESSAGE);
// args.add(arg.BLOB);
// FUNCTIONS_OPTIONAL_ARGS.put(call.decrypt.name(), args);
// }
//
// /** a map from ApgService parameters to function calls to get the default */
// private static final HashMap<arg, String> FUNCTIONS_DEFAULTS = new HashMap<arg, String>();
// static {
// FUNCTIONS_DEFAULTS.put(arg.ENCRYPTION_ALGORYTHM, "getDefaultEncryptionAlgorithm");
// FUNCTIONS_DEFAULTS.put(arg.HASH_ALGORYTHM, "getDefaultHashAlgorithm");
// FUNCTIONS_DEFAULTS.put(arg.ARMORED_OUTPUT, "getDefaultAsciiArmour");
// FUNCTIONS_DEFAULTS.put(arg.FORCE_V3_SIGNATURE, "getForceV3Signatures");
// FUNCTIONS_DEFAULTS.put(arg.COMPRESSION, "getDefaultMessageCompression");
// }
//
// /** a map of the default function names to their method */
// private static final HashMap<String, Method> FUNCTIONS_DEFAULTS_METHODS = new HashMap<String, Method>();
// static {
// try {
// FUNCTIONS_DEFAULTS_METHODS.put("getDefaultEncryptionAlgorithm",
// Preferences.class.getMethod("getDefaultEncryptionAlgorithm"));
// FUNCTIONS_DEFAULTS_METHODS.put("getDefaultHashAlgorithm",
// Preferences.class.getMethod("getDefaultHashAlgorithm"));
// FUNCTIONS_DEFAULTS_METHODS.put("getDefaultAsciiArmour",
// Preferences.class.getMethod("getDefaultAsciiArmour"));
// FUNCTIONS_DEFAULTS_METHODS.put("getForceV3Signatures",
// Preferences.class.getMethod("getForceV3Signatures"));
// FUNCTIONS_DEFAULTS_METHODS.put("getDefaultMessageCompression",
// Preferences.class.getMethod("getDefaultMessageCompression"));
// } catch (Exception e) {
// Log.e(TAG, "Function method exception: " + e.getMessage());
// }
// }
//
// private static void writeToOutputStream(InputStream is, OutputStream os) throws IOException {
// byte[] buffer = new byte[8];
// int len = 0;
// while ((len = is.read(buffer)) != -1) {
// os.write(buffer, 0, len);
// }
// }
//
// private static Cursor getKeyEntries(HashMap<String, Object> pParams) {
// SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
// qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " + "("
// + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME + "."
// + Keys.KEY_RING_ID + " AND " + Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY
// + " = '1'" + ") " + " INNER JOIN " + UserIds.TABLE_NAME + " ON " + "("
// + Keys.TABLE_NAME + "." + Keys._ID + " = " + UserIds.TABLE_NAME + "."
// + UserIds.KEY_ID + " AND " + UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ");
//
// String orderBy = pParams.containsKey("order_by") ? (String) pParams.get("order_by")
// : UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
//
// String typeVal[] = null;
// String typeWhere = null;
// if (pParams.containsKey("key_type")) {
// typeWhere = KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?";
// typeVal = new String[] { "" + pParams.get("key_type") };
// }
// return qb.query(PGPMain.getDatabase().db(), (String[]) pParams.get("columns"), typeWhere,
// typeVal, null, null, orderBy);
// }
//
// /**
// * maps a fingerprint or user id of a key to a master key in database
// *
// * @param search_key
// * fingerprint or user id to search for
// * @return master key if found, or 0
// */
// private static long getMasterKey(String pSearchKey, Bundle pReturn) {
// if (pSearchKey == null || pSearchKey.length() != 8) {
// return 0;
// }
// ArrayList<String> keyList = new ArrayList<String>();
// keyList.add(pSearchKey);
// long[] keys = getMasterKey(keyList, pReturn);
// if (keys.length > 0) {
// return keys[0];
// } else {
// return 0;
// }
// }
//
// /**
// * maps fingerprints or user ids of keys to master keys in database
// *
// * @param search_keys
// * a list of keys (fingerprints or user ids) to look for in database
// * @return an array of master keys
// */
// private static long[] getMasterKey(ArrayList<String> pSearchKeys, Bundle pReturn) {
//
// HashMap<String, Object> qParams = new HashMap<String, Object>();
// qParams.put("columns", new String[] { KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0
// UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1
// });
// qParams.put("key_type", Id.database.type_public);
//
// Cursor mCursor = getKeyEntries(qParams);
//
// if (LOCAL_LOGV)
// Log.v(TAG, "going through installed user keys");
// ArrayList<Long> masterKeys = new ArrayList<Long>();
// while (mCursor.moveToNext()) {
// long curMkey = mCursor.getLong(0);
// String curUser = mCursor.getString(1);
//
// String curFprint = PGPHelper.getSmallFingerPrint(curMkey);
// if (LOCAL_LOGV)
// Log.v(TAG, "current user: " + curUser + " (" + curFprint + ")");
// if (pSearchKeys.contains(curFprint) || pSearchKeys.contains(curUser)) {
// if (LOCAL_LOGV)
// Log.v(TAG, "master key found for: " + curFprint);
// masterKeys.add(curMkey);
// pSearchKeys.remove(curFprint);
// } else {
// if (LOCAL_LOGV)
// Log.v(TAG, "Installed key " + curFprint
// + " is not in the list of public keys to encrypt with");
// }
// }
// mCursor.close();
//
// long[] masterKeyLongs = new long[masterKeys.size()];
// int i = 0;
// for (Long key : masterKeys) {
// masterKeyLongs[i++] = key;
// }
//
// if (i == 0) {
// Log.w(TAG, "Found not one public key");
// pReturn.getStringArrayList(ret.WARNINGS.name()).add(
// "Searched for public key(s) but found not one");
// }
//
// for (String key : pSearchKeys) {
// Log.w(TAG, "Searched for key " + key + " but cannot find it in APG");
// pReturn.getStringArrayList(ret.WARNINGS.name()).add(
// "Searched for key " + key + " but cannot find it in APG");
// }
//
// return masterKeyLongs;
// }
//
// /**
// * Add default arguments if missing
// *
// * @param args
// * the bundle to add default parameters to if missing
// */
// private void addDefaultArguments(String pCall, Bundle pArgs) {
// // check whether there are optional elements defined for that call
// if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pCall)) {
// Preferences preferences = Preferences.getPreferences(getBaseContext(), true);
//
// Iterator<arg> iter = FUNCTIONS_DEFAULTS.keySet().iterator();
// while (iter.hasNext()) {
// arg currentArg = iter.next();
// String currentKey = currentArg.name();
// if (!pArgs.containsKey(currentKey)
// && FUNCTIONS_OPTIONAL_ARGS.get(pCall).contains(currentArg)) {
// String currentFunctionName = FUNCTIONS_DEFAULTS.get(currentArg);
// try {
// Class<?> returnType = FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
// .getReturnType();
// if (returnType == String.class) {
// pArgs.putString(currentKey,
// (String) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
// .invoke(preferences));
// } else if (returnType == boolean.class) {
// pArgs.putBoolean(currentKey,
// (Boolean) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
// .invoke(preferences));
// } else if (returnType == int.class) {
// pArgs.putInt(currentKey,
// (Integer) FUNCTIONS_DEFAULTS_METHODS.get(currentFunctionName)
// .invoke(preferences));
// } else {
// Log.e(TAG, "Unknown return type " + returnType.toString()
// + " for default option");
// }
// } catch (Exception e) {
// Log.e(TAG, "Exception in add_default_arguments " + e.getMessage());
// }
// }
// }
// }
// }
//
// /**
// * updates a Bundle with default return values
// *
// * @param pReturn
// * the Bundle to update
// */
// private void addDefaultReturns(Bundle pReturn) {
// ArrayList<String> errors = new ArrayList<String>();
// ArrayList<String> warnings = new ArrayList<String>();
//
// pReturn.putStringArrayList(ret.ERRORS.name(), errors);
// pReturn.putStringArrayList(ret.WARNINGS.name(), warnings);
// }
//
// /**
// * checks for required arguments and adds them to the error if missing
// *
// * @param function
// * the functions required arguments to check for
// * @param pArgs
// * the Bundle of arguments to check
// * @param pReturn
// * the bundle to write errors to
// */
// private void checkForRequiredArgs(String pFunction, Bundle pArgs, Bundle pReturn) {
// if (FUNCTIONS_REQUIRED_ARGS.containsKey(pFunction)) {
// Iterator<arg> iter = FUNCTIONS_REQUIRED_ARGS.get(pFunction).iterator();
// while (iter.hasNext()) {
// String curArg = iter.next().name();
// if (!pArgs.containsKey(curArg)) {
// pReturn.getStringArrayList(ret.ERRORS.name())
// .add("Argument missing: " + curArg);
// }
// }
// }
//
// if (pFunction.equals(call.encrypt_with_passphrase.name())
// || pFunction.equals(call.encrypt_with_public_key.name())
// || pFunction.equals(call.decrypt.name())) {
// // check that either MESSAGE or BLOB are there
// if (!pArgs.containsKey(arg.MESSAGE.name()) && !pArgs.containsKey(arg.BLOB.name())) {
// pReturn.getStringArrayList(ret.ERRORS.name()).add(
// "Arguments missing: Neither MESSAGE nor BLOG found");
// }
//
// }
// }
//
// /**
// * checks for unknown arguments and add them to warning if found
// *
// * @param function
// * the functions name to check against
// * @param pArgs
// * the Bundle of arguments to check
// * @param pReturn
// * the bundle to write warnings to
// */
// private void checkForUnknownArgs(String pFunction, Bundle pArgs, Bundle pReturn) {
//
// HashSet<arg> allArgs = new HashSet<arg>();
// if (FUNCTIONS_REQUIRED_ARGS.containsKey(pFunction)) {
// allArgs.addAll(FUNCTIONS_REQUIRED_ARGS.get(pFunction));
// }
// if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pFunction)) {
// allArgs.addAll(FUNCTIONS_OPTIONAL_ARGS.get(pFunction));
// }
//
// ArrayList<String> unknownArgs = new ArrayList<String>();
// Iterator<String> iter = pArgs.keySet().iterator();
// while (iter.hasNext()) {
// String curKey = iter.next();
// try {
// arg curArg = arg.valueOf(curKey);
// if (!allArgs.contains(curArg)) {
// pReturn.getStringArrayList(ret.WARNINGS.name()).add(
// "Unknown argument: " + curKey);
// unknownArgs.add(curKey);
// }
// } catch (Exception e) {
// pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + curKey);
// unknownArgs.add(curKey);
// }
// }
//
// // remove unknown arguments so our bundle has just what we need
// for (String arg : unknownArgs) {
// pArgs.remove(arg);
// }
// }
//
// private boolean prepareArgs(String pCall, Bundle pArgs, Bundle pReturn) {
// // PGPMain.initialize(getBaseContext());
//
// /* add default return values for all functions */
// addDefaultReturns(pReturn);
//
// /* add default arguments if missing */
// addDefaultArguments(pCall, pArgs);
// if (LOCAL_LOGV)
// Log.v(TAG, "add_default_arguments");
//
// /* check for required arguments */
// checkForRequiredArgs(pCall, pArgs, pReturn);
// if (LOCAL_LOGV)
// Log.v(TAG, "check_required_args");
//
// /* check for unknown arguments and add to warning if found */
// checkForUnknownArgs(pCall, pArgs, pReturn);
// if (LOCAL_LOGV)
// Log.v(TAG, "check_unknown_args");
//
// /* return if errors happened */
// if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) {
// if (LOCAL_LOGV)
// Log.v(TAG, "Errors after preparing, not executing " + pCall);
// pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.shiftedOrdinal());
// return false;
// }
// if (LOCAL_LOGV)
// Log.v(TAG, "error return");
//
// return true;
// }
//
// private boolean encrypt(Bundle pArgs, Bundle pReturn) {
// boolean isBlob = pArgs.containsKey(arg.BLOB.name());
//
// long pubMasterKeys[] = {};
// if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) {
// ArrayList<String> list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name());
// ArrayList<String> pubKeys = new ArrayList<String>();
// if (LOCAL_LOGV)
// Log.v(TAG, "Long size: " + list.size());
// Iterator<String> iter = list.iterator();
// while (iter.hasNext()) {
// pubKeys.add(iter.next());
// }
// pubMasterKeys = getMasterKey(pubKeys, pReturn);
// }
//
// InputStream inStream = null;
// if (isBlob) {
// ContentResolver cr = getContentResolver();
// try {
// inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name())));
// } catch (Exception e) {
// Log.e(TAG, "... exception on opening blob", e);
// }
// } else {
// inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
// }
// InputData in = new InputData(inStream, 0); // XXX Size second param?
//
// OutputStream out = new ByteArrayOutputStream();
// if (LOCAL_LOGV)
// Log.v(TAG, "About to encrypt");
// try {
// PGPMain.encrypt(getBaseContext(), // context
// in, // input stream
// out, // output stream
// pArgs.getBoolean(arg.ARMORED_OUTPUT.name()), // ARMORED_OUTPUT
// pubMasterKeys, // encryption keys
// getMasterKey(pArgs.getString(arg.SIGNATURE_KEY.name()), pReturn), // signature
// // key
// pArgs.getString(arg.PRIVATE_KEY_PASSPHRASE.name()), // signature passphrase
// null, // progress
// pArgs.getInt(arg.ENCRYPTION_ALGORYTHM.name()), // encryption
// pArgs.getInt(arg.HASH_ALGORYTHM.name()), // hash
// pArgs.getInt(arg.COMPRESSION.name()), // compression
// pArgs.getBoolean(arg.FORCE_V3_SIGNATURE.name()), // mPreferences.getForceV3Signatures(),
// pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) // passPhrase
// );
// } catch (Exception e) {
// Log.e(TAG, "Exception in encrypt");
// String msg = e.getMessage();
// if (msg.equals(getBaseContext().getString(R.string.error_noSignaturePassPhrase))) {
// pReturn.getStringArrayList(ret.ERRORS.name()).add(
// "Cannot encrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name() + " missing): "
// + msg);
// pReturn.putInt(ret.ERROR.name(),
// error.PRIVATE_KEY_PASSPHRASE_MISSING.shiftedOrdinal());
// } else if (msg.equals(getBaseContext().getString(
// R.string.error_couldNotExtractPrivateKey))) {
// pReturn.getStringArrayList(ret.ERRORS.name()).add(
// "Cannot encrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name()
// + " probably wrong): " + msg);
// pReturn.putInt(ret.ERROR.name(),
// error.PRIVATE_KEY_PASSPHRASE_WRONG.shiftedOrdinal());
// } else {
// pReturn.getStringArrayList(ret.ERRORS.name()).add(
// "Internal failure (" + e.getClass() + ") in APG when encrypting: "
// + e.getMessage());
// pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shiftedOrdinal());
// }
// return false;
// }
// if (LOCAL_LOGV)
// Log.v(TAG, "Encrypted");
// if (isBlob) {
// ContentResolver cr = getContentResolver();
// try {
// OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB
// .name())));
// writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()), outStream);
// outStream.close();
// } catch (Exception e) {
// Log.e(TAG, "... exception on writing blob", e);
// }
// } else {
// pReturn.putString(ret.RESULT.name(), out.toString());
// }
// return true;
// }
//
// private final IApgService2.Stub mBinder = new IApgService2.Stub() {
//
// public boolean getKeys(Bundle pArgs, Bundle pReturn) {
//
// prepareArgs("get_keys", pArgs, pReturn);
//
// HashMap<String, Object> qParams = new HashMap<String, Object>();
// qParams.put("columns", new String[] {
// KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0
// UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1
// });
//
// qParams.put("key_type", pArgs.getInt(arg.KEY_TYPE.name()));
//
// Cursor cursor = getKeyEntries(qParams);
// ArrayList<String> fPrints = new ArrayList<String>();
// ArrayList<String> ids = new ArrayList<String>();
// while (cursor.moveToNext()) {
// if (LOCAL_LOGV)
// Log.v(TAG, "adding key " + PGPHelper.getSmallFingerPrint(cursor.getLong(0)));
// fPrints.add(PGPHelper.getSmallFingerPrint(cursor.getLong(0)));
// ids.add(cursor.getString(1));
// }
// cursor.close();
//
// pReturn.putStringArrayList(ret.FINGERPRINTS.name(), fPrints);
// pReturn.putStringArrayList(ret.USER_IDS.name(), ids);
// return true;
// }
//
// public boolean encryptWithPublicKey(Bundle pArgs, Bundle pReturn) {
// if (!prepareArgs("encrypt_with_public_key", pArgs, pReturn)) {
// return false;
// }
//
// return encrypt(pArgs, pReturn);
// }
//
// public boolean encryptWithPassphrase(Bundle pArgs, Bundle pReturn) {
// if (!prepareArgs("encrypt_with_passphrase", pArgs, pReturn)) {
// return false;
// }
//
// return encrypt(pArgs, pReturn);
//
// }
//
// public boolean decrypt(Bundle pArgs, Bundle pReturn) {
// if (!prepareArgs("decrypt", pArgs, pReturn)) {
// return false;
// }
//
// boolean isBlob = pArgs.containsKey(arg.BLOB.name());
//
// String passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs
// .getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs
// .getString(arg.PRIVATE_KEY_PASSPHRASE.name());
//
// InputStream inStream = null;
// if (isBlob) {
// ContentResolver cr = getContentResolver();
// try {
// inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name())));
// } catch (Exception e) {
// Log.e(TAG, "... exception on opening blob", e);
// }
// } else {
// inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
// }
//
// InputData in = new InputData(inStream, 0); // XXX what size in second parameter?
// OutputStream out = new ByteArrayOutputStream();
// if (LOCAL_LOGV)
// Log.v(TAG, "About to decrypt");
// try {
// PGPMain.decrypt(getBaseContext(), in, out, passphrase, null, // progress
// pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null // symmetric
// );
// } catch (Exception e) {
// Log.e(TAG, "Exception in decrypt");
// String msg = e.getMessage();
// if (msg.equals(getBaseContext().getString(R.string.error_noSecretKeyFound))) {
// pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot decrypt: " + msg);
// pReturn.putInt(ret.ERROR.name(), error.NO_MATCHING_SECRET_KEY.shiftedOrdinal());
// } else if (msg.equals(getBaseContext().getString(R.string.error_wrongPassPhrase))) {
// pReturn.getStringArrayList(ret.ERRORS.name()).add(
// "Cannot decrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name()
// + " wrong/missing): " + msg);
// pReturn.putInt(ret.ERROR.name(),
// error.PRIVATE_KEY_PASSPHRASE_WRONG.shiftedOrdinal());
// } else {
// pReturn.getStringArrayList(ret.ERRORS.name()).add(
// "Internal failure (" + e.getClass() + ") in APG when decrypting: "
// + msg);
// pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shiftedOrdinal());
// }
// return false;
// }
// if (LOCAL_LOGV)
// Log.v(TAG, "... decrypted");
//
// if (isBlob) {
// ContentResolver cr = getContentResolver();
// try {
// OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB
// .name())));
// writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()),
// outStream);
// outStream.close();
// } catch (Exception e) {
// Log.e(TAG, "... exception on writing blob", e);
// }
// } else {
// pReturn.putString(ret.RESULT.name(), out.toString());
// }
// return true;
// }
//
// };
//}

View File

@ -1,71 +0,0 @@
///*
// * 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.deprecated;
//
//
//import android.content.ContentUris;
//import android.content.ContentValues;
//import android.content.Context;
//import android.database.Cursor;
//import android.database.sqlite.SQLiteDatabase;
//import android.database.sqlite.SQLiteOpenHelper;
//import android.net.Uri;
//import org.thialfihar.android.apg.util.Log;
//
//public class ApgServiceBlobDatabase extends SQLiteOpenHelper {
//
// private static final String TAG = "ApgServiceBlobDatabase";
//
// private static final int VERSION = 1;
// private static final String NAME = "apg_service_blob_data";
// private static final String TABLE = "data";
//
// public ApgServiceBlobDatabase(Context context) {
// super(context, NAME, null, VERSION);
// if (ApgService2.LOCAL_LOGD)
// Log.d(TAG, "constructor called");
// }
//
// @Override
// public void onCreate(SQLiteDatabase db) {
// if (ApgService2.LOCAL_LOGD)
// Log.d(TAG, "onCreate() called");
// db.execSQL("create table " + TABLE + " ( _id integer primary key autoincrement,"
// + "key text not null)");
// }
//
// @Override
// public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// if (ApgService2.LOCAL_LOGD)
// Log.d(TAG, "onUpgrade() called");
// // no upgrade necessary yet
// }
//
// public Uri insert(ContentValues vals) {
// if (ApgService2.LOCAL_LOGD)
// Log.d(TAG, "insert() called");
// SQLiteDatabase db = this.getWritableDatabase();
// long newId = db.insert(TABLE, null, vals);
// return ContentUris.withAppendedId(ApgServiceBlobProvider.CONTENT_URI, newId);
// }
//
// public Cursor query(String id, String key) {
// if (ApgService2.LOCAL_LOGD)
// Log.d(TAG, "query() called");
// SQLiteDatabase db = this.getReadableDatabase();
// return db.query(TABLE, new String[] { "_id" }, "_id = ? and key = ?", new String[] { id,
// key }, null, null, null);
// }
//}

View File

@ -1,151 +0,0 @@
///*
// * 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.deprecated;
//
//import org.thialfihar.android.apg.Constants;
//
//import android.content.ContentProvider;
//import android.content.ContentValues;
//import android.database.Cursor;
//import android.net.Uri;
//import android.os.ParcelFileDescriptor;
//import org.thialfihar.android.apg.util.Log;
//
//import java.io.File;
//import java.io.FileNotFoundException;
//import java.io.IOException;
//import java.util.List;
//import java.util.UUID;
//
//public class ApgServiceBlobProvider extends ContentProvider {
//
// private static final String TAG = "ApgServiceBlobProvider";
//
// public static final Uri CONTENT_URI = Uri.parse("content://org.thialfihar.android.apg.provider.apgserviceblobprovider");
//
// private static final String COLUMN_KEY = "key";
//
// private static final String STORE_PATH = Constants.path.APP_DIR+"/ApgServiceBlobs";
//
// private ApgServiceBlobDatabase mDb = null;
//
// public ApgServiceBlobProvider() {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "Constructor called");
// File dir = new File(STORE_PATH);
// dir.mkdirs();
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "Constructor finished");
// }
//
// @Override
// public int delete(Uri arg0, String arg1, String[] arg2) {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "delete() called");
// // TODO Auto-generated method stub
// return 0;
// }
//
// @Override
// public String getType(Uri arg0) {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "getType() called");
// // not needed for now
// return null;
// }
//
// @Override
// public Uri insert(Uri uri, ContentValues ignored) {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "insert() called");
// // ContentValues are actually ignored, because we want to store a blob with no more information
// // but have to create an record with the password generated here first
//
// ContentValues vals = new ContentValues();
//
// // Insert a random key in the database. This has to provided by the caller when updating or
// // getting the blob
// String password = UUID.randomUUID().toString();
// vals.put(COLUMN_KEY, password);
//
// Uri insertedUri = mDb.insert(vals);
// return Uri.withAppendedPath(insertedUri, password);
// }
//
// @Override
// public boolean onCreate() {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "onCreate() called");
// mDb = new ApgServiceBlobDatabase(getContext());
// // TODO Auto-generated method stub
// return true;
// }
//
// @Override
// public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "query() called");
// // TODO Auto-generated method stub
// return null;
// }
//
// @Override
// public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "update() called");
// // TODO Auto-generated method stub
// return 0;
// }
//
// @Override
// public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException, FileNotFoundException {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "openFile() called");
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... with uri: "+uri.toString());
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... with mode: "+mode);
//
// List<String> segments = uri.getPathSegments();
// if(segments.size() < 2) {
// throw new SecurityException("Password not found in URI");
// }
// String id = segments.get(0);
// String key = segments.get(1);
//
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... got id: "+id);
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... and key: "+key);
//
// // get the data
// Cursor result = mDb.query(id, key);
//
// if(result.getCount() == 0) {
// // either the key is wrong or no id exists
// throw new FileNotFoundException("No file found with that ID and/or password");
// }
//
// File targetFile = new File(STORE_PATH, id);
// if(mode.equals("w")) {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... will try to open file w");
// if( !targetFile.exists() ) {
// try {
// targetFile.createNewFile();
// } catch (IOException e) {
// Log.e(TAG, "... got IEOException on creating new file", e);
// throw new FileNotFoundException("Could not create file to write to");
// }
// }
// return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE );
// } else if(mode.equals("r")) {
// if(ApgService2.LOCAL_LOGD) Log.d(TAG, "... will try to open file r");
// if( !targetFile.exists() ) {
// throw new FileNotFoundException("Error: Could not find the file requested");
// }
// return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
// }
//
// return null;
// }
//
//}

View File

@ -1,43 +0,0 @@
package org.thialfihar.android.apg.deprecated;
//package org.thialfihar.android.apg.provider.blob;
//
//import android.net.Uri;
//import android.provider.BaseColumns;
//
//public class BlobContract {
//
// interface BlobColumns {
// String DATA = "data";
// }
//
// public static final String CONTENT_AUTHORITY = "org.thialfihar.android.apg";
//
// private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
//
// public static final String PATH_BLOB = "blob";
//
// public static class Blobs implements BlobColumns, BaseColumns {
// public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_BLOB)
// .build();
//
// /** Use if multiple items get returned */
// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.apg.blob";
//
// /** Use if a single item is returned */
// public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.apg.blob";
//
// /** Default "ORDER BY" clause. */
// public static final String DEFAULT_SORT = BaseColumns._ID + " ASC";
//
// public static Uri buildUri(String id) {
// return CONTENT_URI.buildUpon().appendPath(id).build();
// }
//
// public static String getId(Uri uri) {
// return uri.getLastPathSegment();
// }
// }
//
// private BlobContract() {
// }
//}

View File

@ -1,125 +0,0 @@
package org.thialfihar.android.apg.deprecated;
interface IApgService2 {
/* All functions fill the returnVals Bundle with the following keys:
*
* ArrayList<String> "WARNINGS" = Warnings, if any
* ArrayList<String> "ERRORS" = Human readable error descriptions, if any
* int "ERROR" = Numeric representation of error, if any
* starting with 100:
* 100: Required argument missing
* 101: Generic failure of APG
* 102: No matching private key found
* 103: Private key's passphrase wrong
* 104: Private key's passphrase missing
*/
/* ********************************************************
* Encryption
* ********************************************************/
/* All encryption function's arguments
*
* Bundle params' keys:
* (optional/required)
* TYPE "STRING KEY" = EXPLANATION / VALUES
*
* (required)
* String "MESSAGE" = Message to encrypt
* OR
* String "BLOB" = ContentUri to a file handle
* with binary data to encrypt
* (Attention: file will be overwritten
* with encrypted content!)
*
* (optional)
* int "ENCRYPTION_ALGORYTHM" = Encryption Algorithm
* 7: AES-128, 8: AES-192, 9: AES-256,
* 4: Blowfish, 10: Twofish, 3: CAST5,
* 6: DES, 2: Triple DES, 1: IDEA
* (optional)
* int "HASH_ALGORYTHM" = Hash Algorithm
* 1: MD5, 3: RIPEMD-160, 2: SHA-1,
* 11: SHA-224, 8: SHA-256, 9: SHA-384,
* 10: SHA-512
* (optional)
* Boolean "ARMORED_OUTPUT" = Armor output
*
* (optional)
* Boolean "FORCE_V3_SIGNATURE" = Force V3 Signatures
*
* (optional)
* int "COMPRESSION" = Compression to use
* 0x21070001: none, 1: Zip, 2: Zlib,
* 3: BZip2
* (optional)
* String "SIGNATURE_KEY" = Key to sign with
*
* (optional)
* String "PRIVATE_KEY_PASSPHRASE" = Passphrase for signing key
*
* Bundle returnVals (in addition to the ERRORS/WARNINGS above):
* If "MESSAGE" was set:
* String "RESULT" = Encrypted message
*/
/* Additional argument for function below:
* (required)
* String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase to use
*/
boolean encryptWithPassphrase(in Bundle params, out Bundle returnVals);
/* Additional argument:
* (required)
* ArrayList<String> "PUBLIC_KEYS" = Public keys (8char fingerprint "123ABC12" OR
* complete id "Alice Meyer <ab@email.com>")
*/
boolean encryptWithPublicKey(in Bundle params, out Bundle returnVals);
/* ********************************************************
* Decryption
* ********************************************************/
/* Bundle params:
* (required)
* String "MESSAGE" = Message to dencrypt
* OR
* String "BLOB" = ContentUri to a file handle
* with binary data to dencrypt
* (Attention: file will be overwritten
* with dencrypted content!)
*
* (optional)
* String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase for decryption
*
* (optional)
* String "PRIVATE_KEY_PASSPHRASE" = Private keys's passphrase on asymmetric encryption
*
* Bundle return_vals:
* If "MESSAGE" was set:
* String "RESULT" = Decrypted message
*/
boolean decrypt(in Bundle params, out Bundle returnVals);
/* ********************************************************
* Get key information
* ********************************************************/
/* Get info about all available keys
*
* Bundle params:
* (required)
* int "KEY_TYPE" = info about what type of keys to return
* 0: public keys
* 1: private keys
*
* Returns:
* StringArrayList "FINGERPRINTS" = Short fingerprints of keys
*
* StringArrayList "USER_IDS" = User ids of corresponding fingerprints
* (order is the same as in FINGERPRINTS)
*/
boolean getKeys(in Bundle params, out Bundle returnVals);
}

View File

@ -1,3 +1,19 @@
/*
* 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.helper;
import org.thialfihar.android.apg.R;

View File

@ -16,8 +16,6 @@
package org.thialfihar.android.apg.helper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;

View File

@ -23,7 +23,6 @@ import java.util.Iterator;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.thialfihar.android.apg.Constants;
@ -31,49 +30,9 @@ import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.util.Log;
public class PGPConversionHelper {
/**
* Converts Vector<PGPSecretKey> to a byte[]
*
* @param keys
* @return
*/
public static byte[] PGPSecretKeyListToBytes(ArrayList<PGPSecretKey> keys) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
for (PGPSecretKey key : keys) {
try {
key.encode(os);
} catch (IOException e) {
Log.e(Constants.TAG, "Error while converting PGPSecretKey to byte[]!", e);
}
}
byte[] keysBytes = os.toByteArray();
return keysBytes;
}
/**
* Convert from byte[] to PGPSecretKeyRing
*
* @param keysBytes
* @return
*/
// public static PGPSecretKeyRing BytesToPGPSecretKeyRing(byte[] keysBytes) {
// PGPObjectFactory factory = new PGPObjectFactory(keysBytes);
// PGPSecretKeyRing keyRing = null;
// try {
// if ((keyRing = (PGPSecretKeyRing) factory.nextObject()) == null) {
// Log.e(Constants.TAG, "No keys given!");
// }
// } catch (IOException e) {
// Log.e(Constants.TAG, "Error while converting to PGPSecretKeyRing!", e);
// }
//
// return keyRing;
// }
/**
* Convert from byte[] to PGPPublicKeyRing
* Convert from byte[] to PGPKeyRing
*
* @param keysBytes
* @return
@ -86,7 +45,7 @@ public class PGPConversionHelper {
Log.e(Constants.TAG, "No keys given!");
}
} catch (IOException e) {
Log.e(Constants.TAG, "Error while converting to PGPPublicKeyRing!", e);
Log.e(Constants.TAG, "Error while converting to PGPKeyRing!", e);
}
return keyRing;
@ -114,6 +73,8 @@ public class PGPConversionHelper {
/**
* Convert from byte[] to PGPSecretKey
*
* Singles keys are encoded as keyRings with one single key in it by Bouncy Castle
*
* @param keysBytes
* @return
*/
@ -123,6 +84,25 @@ public class PGPConversionHelper {
return key;
}
/**
* Convert from ArrayList<PGPSecretKey> to byte[]
*
* @param keys
* @return
*/
public static byte[] PGPSecretKeyArrayListToBytes(ArrayList<PGPSecretKey> keys) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
for (PGPSecretKey key : keys) {
try {
key.encode(os);
} catch (IOException e) {
Log.e(Constants.TAG, "Error while converting ArrayList<PGPSecretKey> to byte[]!", e);
}
}
return os.toByteArray();
}
/**
* Convert from PGPSecretKey to byte[]
*

View File

@ -707,8 +707,7 @@ public class PGPMain {
}
if (signatureKeyId != Id.key.none) {
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context,
signatureKeyId);
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
signingKey = PGPHelper.getSigningKey(context, signatureKeyId);
if (signingKey == null) {
throw new ApgGeneralException(context.getString(R.string.error_signatureFailed));
@ -718,8 +717,9 @@ public class PGPMain {
throw new ApgGeneralException(
context.getString(R.string.error_noSignaturePassPhrase));
}
if (progress != null)
progress.setProgress(R.string.progress_extractingSignatureKey, 0, 100);
updateProgress(progress, R.string.progress_extractingSignatureKey, 0, 100);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
@ -762,8 +762,7 @@ public class PGPMain {
PGPV3SignatureGenerator signatureV3Generator = null;
if (signatureKeyId != Id.key.none) {
if (progress != null)
progress.setProgress(R.string.progress_preparingSignature, 10, 100);
updateProgress(progress, R.string.progress_preparingSignature, 10, 100);
// content signer based on signing key algorithm and choosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
@ -1079,8 +1078,7 @@ public class PGPMain {
if (passphrase == null || passphrase.length() <= 0) {
throw new ApgGeneralException("Unable to obtain passphrase");
} else {
PGPPublicKeyRing pubring = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
pubKeyId);
PGPPublicKeyRing pubring = ProviderHelper.getPGPPublicKeyRingByKeyId(context, pubKeyId);
PGPSecretKey signingKey = PGPHelper.getSigningKey(context, masterKeyId);
if (signingKey == null) {
@ -1199,7 +1197,7 @@ public class PGPMain {
if (passphrase == null) {
passphrase = "";
}
Bundle returnData = new Bundle();
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
PGPObjectFactory pgpF = new PGPObjectFactory(in);
@ -1505,8 +1503,8 @@ public class PGPMain {
} else {
signatureKeyId = signature.getKeyID();
String userId = null;
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(
context, signatureKeyId);
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
signatureKeyId);
if (signKeyRing != null) {
userId = PGPHelper.getMainUserId(PGPHelper.getMasterKey(signKeyRing));
}

View File

@ -35,7 +35,6 @@ import org.thialfihar.android.apg.util.Log;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.DatabaseUtils;
@ -199,8 +198,7 @@ public class ApgProvider extends ContentProvider {
/** {@inheritDoc} */
@Override
public boolean onCreate() {
final Context context = getContext();
mApgDatabase = new ApgDatabase(context);
mApgDatabase = new ApgDatabase(getContext());
return true;
}
@ -315,6 +313,7 @@ public class ApgProvider extends ContentProvider {
}
/** {@inheritDoc} */
@SuppressWarnings("deprecation")
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {

View File

@ -0,0 +1,40 @@
/*
* 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.provider;
import org.thialfihar.android.apg.Constants;
import android.net.Uri;
import android.provider.BaseColumns;
public class ApgServiceBlobContract {
interface BlobsColumns {
String KEY = "key";
}
public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME + ".blobs";
private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static class Blobs implements BlobsColumns, BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI;
}
private ApgServiceBlobContract() {
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2011 Markus Doits <markus.doits@googlemail.com>
*
* 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.provider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import org.thialfihar.android.apg.provider.ApgServiceBlobContract.BlobsColumns;
public class ApgServiceBlobDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "apg_blob.db";
private static final int DATABASE_VERSION = 2;
public static final String TABLE = "data";
public ApgServiceBlobDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE + " ( " + BaseColumns._ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + BlobsColumns.KEY + " TEXT NOT NULL)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// no upgrade necessary yet
}
}

View File

@ -0,0 +1,151 @@
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2011 Markus Doits <markus.doits@googlemail.com>
*
* 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.provider;
import org.thialfihar.android.apg.Constants;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import org.thialfihar.android.apg.provider.ApgServiceBlobContract.Blobs;
import org.thialfihar.android.apg.provider.ApgServiceBlobContract.BlobsColumns;
import org.thialfihar.android.apg.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
public class ApgServiceBlobProvider extends ContentProvider {
private static final String STORE_PATH = Constants.path.APP_DIR + "/ApgBlobs";
private ApgServiceBlobDatabase mBlobDatabase = null;
public ApgServiceBlobProvider() {
File dir = new File(STORE_PATH);
dir.mkdirs();
}
@Override
public boolean onCreate() {
mBlobDatabase = new ApgServiceBlobDatabase(getContext());
return true;
}
/** {@inheritDoc} */
@Override
public Uri insert(Uri uri, ContentValues ignored) {
// ContentValues are actually ignored, because we want to store a blob with no more
// information but have to create an record with the password generated here first
ContentValues vals = new ContentValues();
// Insert a random key in the database. This has to provided by the caller when updating or
// getting the blob
String password = UUID.randomUUID().toString();
vals.put(BlobsColumns.KEY, password);
SQLiteDatabase db = mBlobDatabase.getWritableDatabase();
long newRowId = db.insert(ApgServiceBlobDatabase.TABLE, null, vals);
Uri insertedUri = ContentUris.withAppendedId(Blobs.CONTENT_URI, newRowId);
return Uri.withAppendedPath(insertedUri, password);
}
/** {@inheritDoc} */
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException,
FileNotFoundException {
Log.d(Constants.TAG, "openFile() called with uri: " + uri.toString() + " and mode: " + mode);
List<String> segments = uri.getPathSegments();
if (segments.size() < 2) {
throw new SecurityException("Password not found in URI");
}
String id = segments.get(0);
String key = segments.get(1);
Log.d(Constants.TAG, "Got id: " + id + " and key: " + key);
// get the data
SQLiteDatabase db = mBlobDatabase.getReadableDatabase();
Cursor result = db.query(ApgServiceBlobDatabase.TABLE, new String[] { BaseColumns._ID },
BaseColumns._ID + " = ? and " + BlobsColumns.KEY + " = ?",
new String[] { id, key }, null, null, null);
if (result.getCount() == 0) {
// either the key is wrong or no id exists
throw new FileNotFoundException("No file found with that ID and/or password");
}
File targetFile = new File(STORE_PATH, id);
if (mode.equals("w")) {
Log.d(Constants.TAG, "Try to open file w");
if (!targetFile.exists()) {
try {
targetFile.createNewFile();
} catch (IOException e) {
Log.e(Constants.TAG, "Got IEOException on creating new file", e);
throw new FileNotFoundException("Could not create file to write to");
}
}
return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_WRITE_ONLY
| ParcelFileDescriptor.MODE_TRUNCATE);
} else if (mode.equals("r")) {
Log.d(Constants.TAG, "Try to open file r");
if (!targetFile.exists()) {
throw new FileNotFoundException("Error: Could not find the file requested");
}
return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
return null;
}
/** {@inheritDoc} */
@Override
public String getType(Uri uri) {
return null;
}
/** {@inheritDoc} */
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return null;
}
/** {@inheritDoc} */
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
/** {@inheritDoc} */
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}

View File

@ -1,3 +1,19 @@
/*
* 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.provider;
import java.io.IOException;
@ -177,6 +193,7 @@ public class ProviderHelper {
* @throws IOException
* @throws GeneralException
*/
@SuppressWarnings("unchecked")
public static void saveKeyRing(Context context, PGPPublicKeyRing keyRing) throws IOException {
PGPPublicKey masterKey = keyRing.getPublicKey();
long masterKeyId = masterKey.getKeyID();
@ -232,6 +249,7 @@ public class ProviderHelper {
* @throws IOException
* @throws GeneralException
*/
@SuppressWarnings("unchecked")
public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException {
PGPSecretKey masterKey = keyRing.getSecretKey();
long masterKeyId = masterKey.getKeyID();

View File

@ -1,3 +1,19 @@
/*
* 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.service;
import java.io.ByteArrayInputStream;
@ -17,7 +33,6 @@ import org.thialfihar.android.apg.helper.PGPMain;
import org.thialfihar.android.apg.helper.PGPMain.ApgGeneralException;
import org.thialfihar.android.apg.util.InputData;
import org.thialfihar.android.apg.util.Log;
import org.thialfihar.android.apg.util.ProgressDialogUpdater;
import android.app.Service;
import android.content.Context;
@ -32,7 +47,7 @@ import android.os.RemoteException;
* - is this service thread safe? Probably not!
*
*/
public class ApgService extends Service implements ProgressDialogUpdater {
public class ApgService extends Service {
Context mContext;
@Override
@ -53,6 +68,14 @@ public class ApgService extends Service implements ProgressDialogUpdater {
return mBinder;
}
private static void writeToOutputStream(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[8];
int len = 0;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
}
void encryptAndSignImplementation(byte[] inputBytes, String inputUri, boolean useAsciiArmor,
int compression, long[] encryptionKeyIds, String encryptionPassphrase,
int symmetricEncryptionAlgorithm, long signatureKeyId, int signatureHashAlgorithm,
@ -61,6 +84,19 @@ public class ApgService extends Service implements ProgressDialogUpdater {
try {
// TODO use inputUri
// InputStream inStream = null;
// if (isBlob) {
// ContentResolver cr = getContentResolver();
// try {
// inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name())));
// } catch (Exception e) {
// Log.e(TAG, "... exception on opening blob", e);
// }
// } else {
// inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
// }
// InputData in = new InputData(inStream, 0); // XXX Size second param?
// build InputData and write into OutputStream
InputStream inputStream = new ByteArrayInputStream(inputBytes);
@ -69,12 +105,25 @@ public class ApgService extends Service implements ProgressDialogUpdater {
OutputStream output = new ByteArrayOutputStream();
PGPMain.encryptAndSign(mContext, ApgService.this, input, output, useAsciiArmor,
compression, encryptionKeyIds, encryptionPassphrase,
symmetricEncryptionAlgorithm, signatureKeyId, signatureHashAlgorithm,
signatureForceV3, signaturePassphrase);
PGPMain.encryptAndSign(mContext, null, input, output, useAsciiArmor, compression,
encryptionKeyIds, encryptionPassphrase, symmetricEncryptionAlgorithm,
signatureKeyId, signatureHashAlgorithm, signatureForceV3, signaturePassphrase);
output.close();
// if (isBlob) {
// ContentResolver cr = getContentResolver();
// try {
// OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB
// .name())));
// writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()), outStream);
// outStream.close();
// } catch (Exception e) {
// Log.e(TAG, "... exception on writing blob", e);
// }
// } else {
// pReturn.putString(ret.RESULT.name(), out.toString());
// }
byte[] outputBytes = ((ByteArrayOutputStream) output).toByteArray();
@ -103,8 +152,8 @@ public class ApgService extends Service implements ProgressDialogUpdater {
OutputStream outputStream = new ByteArrayOutputStream();
Bundle outputBundle = PGPMain.decryptAndVerify(mContext, ApgService.this, inputData,
outputStream, passphrase, assumeSymmetric);
Bundle outputBundle = PGPMain.decryptAndVerify(mContext, null, inputData, outputStream,
passphrase, assumeSymmetric);
outputStream.close();
@ -148,15 +197,13 @@ public class ApgService extends Service implements ProgressDialogUpdater {
try {
secretKeyId = PGPMain.getDecryptionKeyId(ApgService.this, inputStream);
if (secretKeyId == Id.key.none) {
throw new PGPMain.ApgGeneralException(
getString(R.string.error_noSecretKeyFound));
throw new ApgGeneralException(getString(R.string.error_noSecretKeyFound));
}
symmetric = false;
} catch (PGPMain.NoAsymmetricEncryptionException e) {
secretKeyId = Id.key.symmetric;
if (!PGPMain.hasSymmetricEncryption(ApgService.this, inputStream)) {
throw new PGPMain.ApgGeneralException(
getString(R.string.error_noKnownEncryptionFound));
throw new ApgGeneralException(getString(R.string.error_noKnownEncryptionFound));
}
symmetric = true;
}
@ -276,21 +323,4 @@ public class ApgService extends Service implements ProgressDialogUpdater {
}
}
@Override
public void setProgress(String message, int current, int total) {
// TODO Auto-generated method stub
}
@Override
public void setProgress(int resourceId, int current, int total) {
// TODO Auto-generated method stub
}
@Override
public void setProgress(int current, int total) {
// TODO Auto-generated method stub
}
}

View File

@ -1,3 +1,19 @@
/*
* 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.service;
interface IApgEncryptDecryptHandler {

View File

@ -1,3 +1,19 @@
/*
* 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.service;
interface IApgHelperHandler {

View File

@ -1,3 +1,19 @@
/*
* 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.service;
import org.thialfihar.android.apg.service.IApgEncryptDecryptHandler;

View File

@ -1,3 +1,19 @@
/*
* 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.service;
interface IApgSignVerifyHandler {

View File

@ -422,7 +422,7 @@ public class EditKeyActivity extends SherlockFragmentActivity {
data.putString(ApgIntentService.NEW_PASSPHRASE, mNewPassPhrase);
data.putStringArrayList(ApgIntentService.USER_IDS, getUserIds(mUserIdsView));
ArrayList<PGPSecretKey> keys = getKeys(mKeysView);
data.putByteArray(ApgIntentService.KEYS, PGPConversionHelper.PGPSecretKeyListToBytes(keys));
data.putByteArray(ApgIntentService.KEYS, PGPConversionHelper.PGPSecretKeyArrayListToBytes(keys));
data.putIntegerArrayList(ApgIntentService.KEYS_USAGES, getKeysUsages(mKeysView));
data.putLong(ApgIntentService.MASTER_KEY_ID, getMasterKeyId());

View File

@ -116,8 +116,8 @@ public class ExpandableListFragment extends Fragment implements OnCreateContextM
pframe.addView(progress, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
root.addView(pframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
root.addView(pframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
// ------------------------------------------------------------------
@ -127,22 +127,22 @@ public class ExpandableListFragment extends Fragment implements OnCreateContextM
TextView tv = new TextView(getActivity());
tv.setId(INTERNAL_EMPTY_ID);
tv.setGravity(Gravity.CENTER);
lframe.addView(tv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
lframe.addView(tv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
ExpandableListView lv = new ExpandableListView(getActivity());
lv.setId(android.R.id.list);
lv.setDrawSelectorOnTop(false);
lframe.addView(lv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
lframe.addView(lv, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
root.addView(lframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
root.addView(lframe, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
// ------------------------------------------------------------------
root.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
root.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
return root;
}

View File

@ -7,7 +7,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/Button02"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="encryptOnClick"
android:text="Encrypt" />
<Button
android:id="@+id/intent_demo_create_new_key"
android:layout_width="match_parent"
@ -50,6 +57,13 @@
android:onClick="encryptOnClick"
android:text="Encrypt" />
<Button
android:id="@+id/intent_demo_encrypt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="encryptAndReturnOnClick"
android:text="Encrypt and return result" />
<Button
android:id="@+id/intent_demo_decrypt"
android:layout_width="match_parent"
@ -57,6 +71,13 @@
android:onClick="decryptOnClick"
android:text="Decrypt" />
<Button
android:id="@+id/intent_demo_decrypt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="decryptAndReturnOnClick"
android:text="Decrypt and return result" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -70,11 +70,20 @@ public class IntentDemoActivity extends Activity {
public void encryptOnClick(View view) {
mApgIntentHelper.encrypt(mMessageTextView.getText().toString(),
mApgData.getEncryptionKeys(), mApgData.getSignatureKeyId());
mApgData.getEncryptionKeys(), mApgData.getSignatureKeyId(), false);
}
public void encryptAndReturnOnClick(View view) {
mApgIntentHelper.encrypt(mMessageTextView.getText().toString(),
mApgData.getEncryptionKeys(), mApgData.getSignatureKeyId(), true);
}
public void decryptOnClick(View view) {
mApgIntentHelper.decrypt(mCiphertextTextView.getText().toString());
mApgIntentHelper.decrypt(mCiphertextTextView.getText().toString(), false);
}
public void decryptAndReturnOnClick(View view) {
mApgIntentHelper.decrypt(mCiphertextTextView.getText().toString(), true);
}
@Override

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2010-2011 K-9 Mail Contributors
* 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2010-2011 K-9 Mail Contributors
* 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.
@ -17,19 +17,59 @@
package org.thialfihar.android.apg.integration;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentUris;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
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) {
@ -44,16 +84,16 @@ public class ApgIntentHelper {
* @return true when activity was found and executed successfully
*/
public boolean createNewKey(String userIds, boolean noPassphrase, boolean generateDefaultKeys) {
Intent intent = new Intent(Constants.Intent.CREATE_KEY);
Intent intent = new Intent(ACTION_CREATE_KEY);
if (userIds != null) {
intent.putExtra(Constants.EXTRA_USER_IDS, userIds);
intent.putExtra(EXTRA_USER_IDS, userIds);
}
intent.putExtra(Constants.EXTRA_NO_PASSPHRASE, noPassphrase);
intent.putExtra(Constants.EXTRA_GENERATE_DEFAULT_KEYS, generateDefaultKeys);
intent.putExtra(EXTRA_NO_PASSPHRASE, noPassphrase);
intent.putExtra(EXTRA_GENERATE_DEFAULT_KEYS, generateDefaultKeys);
intent.putExtra(Constants.EXTRA_INTENT_VERSION, Constants.INTENT_VERSION);
intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION);
try {
activity.startActivityForResult(intent, Constants.CREATE_KEY);
activity.startActivityForResult(intent, CREATE_KEY);
return true;
} catch (ActivityNotFoundException e) {
activityNotFound();
@ -77,11 +117,11 @@ public class ApgIntentHelper {
* @return true when activity was found and executed successfully
*/
public boolean editKey(long keyId) {
Intent intent = new Intent(Constants.Intent.EDIT_KEY);
intent.putExtra(Constants.EXTRA_KEY_ID, keyId);
intent.putExtra(Constants.EXTRA_INTENT_VERSION, Constants.INTENT_VERSION);
Intent intent = new Intent(ACTION_EDIT_KEY);
intent.putExtra(EXTRA_KEY_ID, keyId);
intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION);
try {
activity.startActivityForResult(intent, Constants.EDIT_KEY);
activity.startActivityForResult(intent, EDIT_KEY);
return true;
} catch (ActivityNotFoundException e) {
activityNotFound();
@ -95,10 +135,10 @@ public class ApgIntentHelper {
* @return true when activity was found and executed successfully
*/
public boolean selectSecretKey() {
Intent intent = new Intent(Constants.Intent.SELECT_SECRET_KEY);
intent.putExtra(Constants.EXTRA_INTENT_VERSION, Constants.INTENT_VERSION);
Intent intent = new Intent(ACTION_SELECT_SECRET_KEY);
intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION);
try {
activity.startActivityForResult(intent, Constants.SELECT_SECRET_KEY);
activity.startActivityForResult(intent, SELECT_SECRET_KEY);
return true;
} catch (ActivityNotFoundException e) {
activityNotFound();
@ -118,15 +158,21 @@ public class ApgIntentHelper {
* id of the signature key
* @return true when activity was found and executed successfully
*/
public boolean encrypt(String data, long[] encryptionKeyIds, long signatureKeyId) {
Intent intent = new Intent(Constants.Intent.ENCRYPT_AND_RETURN);
intent.putExtra(Constants.EXTRA_INTENT_VERSION, Constants.INTENT_VERSION);
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(Constants.EXTRA_TEXT, data);
intent.putExtra(Constants.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds);
intent.putExtra(Constants.EXTRA_SIGNATURE_KEY_ID, signatureKeyId);
intent.putExtra(EXTRA_TEXT, data);
intent.putExtra(EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds);
intent.putExtra(EXTRA_SIGNATURE_KEY_ID, signatureKeyId);
try {
activity.startActivityForResult(intent, Constants.ENCRYPT_MESSAGE);
activity.startActivityForResult(intent, ENCRYPT_MESSAGE);
return true;
} catch (ActivityNotFoundException e) {
activityNotFound();
@ -142,16 +188,21 @@ public class ApgIntentHelper {
* @param pgpData
* @return true when activity was found and executed successfully
*/
public boolean decrypt(String data) {
Intent intent = new Intent(Constants.Intent.DECRYPT_AND_RETURN);
intent.putExtra(Constants.EXTRA_INTENT_VERSION, Constants.INTENT_VERSION);
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(Constants.EXTRA_TEXT, data);
activity.startActivityForResult(intent, Constants.DECRYPT_MESSAGE);
intent.putExtra(EXTRA_TEXT, data);
activity.startActivityForResult(intent, DECRYPT_MESSAGE);
return true;
} catch (ActivityNotFoundException e) {
activityNotFound();
@ -170,44 +221,42 @@ public class ApgIntentHelper {
public boolean onActivityResult(int requestCode, int resultCode, Intent data, ApgData apgData) {
switch (requestCode) {
case Constants.SELECT_SECRET_KEY:
case SELECT_SECRET_KEY:
if (resultCode != Activity.RESULT_OK || data == null) {
// user canceled!
break;
}
apgData.setSignatureKeyId(data.getLongExtra(Constants.EXTRA_KEY_ID, 0));
apgData.setSignatureUserId(data.getStringExtra(Constants.EXTRA_USER_ID));
apgData.setSignatureKeyId(data.getLongExtra(EXTRA_KEY_ID, 0));
apgData.setSignatureUserId(data.getStringExtra(EXTRA_USER_ID));
break;
case Constants.SELECT_PUBLIC_KEYS:
case SELECT_PUBLIC_KEYS:
if (resultCode != Activity.RESULT_OK || data == null) {
apgData.setEncryptionKeys(null);
break;
}
apgData.setEncryptionKeys(data.getLongArrayExtra(Constants.RESULT_EXTRA_MASTER_KEY_IDS));
apgData.setEncryptionKeys(data.getLongArrayExtra(RESULT_EXTRA_MASTER_KEY_IDS));
break;
case Constants.ENCRYPT_MESSAGE:
case ENCRYPT_MESSAGE:
if (resultCode != Activity.RESULT_OK || data == null) {
apgData.setEncryptionKeys(null);
break;
}
apgData.setEncryptedData(data.getStringExtra(Constants.EXTRA_ENCRYPTED_MESSAGE));
apgData.setEncryptedData(data.getStringExtra(EXTRA_ENCRYPTED_MESSAGE));
break;
case Constants.DECRYPT_MESSAGE:
case DECRYPT_MESSAGE:
if (resultCode != Activity.RESULT_OK || data == null) {
break;
}
apgData.setSignatureUserId(data.getStringExtra(Constants.EXTRA_SIGNATURE_USER_ID));
apgData.setSignatureKeyId(data.getLongExtra(Constants.EXTRA_SIGNATURE_KEY_ID, 0));
apgData.setSignatureSuccess(data.getBooleanExtra(Constants.EXTRA_SIGNATURE_SUCCESS,
false));
apgData.setSignatureUnknown(data.getBooleanExtra(Constants.EXTRA_SIGNATURE_UNKNOWN,
false));
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(Constants.EXTRA_DECRYPTED_MESSAGE));
apgData.setDecryptedData(data.getStringExtra(EXTRA_DECRYPTED_MESSAGE));
break;
default:
@ -238,46 +287,23 @@ public class ApgIntentHelper {
* @return true when activity was found and executed successfully
*/
public boolean selectEncryptionKeys(String emails, ApgData apgData) {
Intent intent = new Intent(Constants.Intent.SELECT_PUBLIC_KEYS);
intent.putExtra(Constants.EXTRA_INTENT_VERSION, Constants.INTENT_VERSION);
Intent intent = new Intent(ACTION_SELECT_PUBLIC_KEYS);
intent.putExtra(EXTRA_INTENT_VERSION, INTENT_VERSION);
long[] initialKeyIds = null;
if (apgData == null || !apgData.hasEncryptionKeys()) {
List<Long> keyIds = new ArrayList<Long>();
if (apgData != null && apgData.hasSignatureKey()) {
keyIds.add(apgData.getSignatureKeyId());
}
try {
Uri contentUri = Uri.withAppendedPath(
Constants.CONTENT_URI_PUBLIC_KEY_RING_BY_EMAILS, emails);
Cursor c = activity.getContentResolver().query(contentUri,
new String[] { "master_key_id" }, null, null, null);
if (c != null) {
while (c.moveToNext()) {
keyIds.add(c.getLong(0));
}
}
ContentProviderHelper cPHelper = new ContentProviderHelper(activity);
initialKeyIds = cPHelper.getPublicKeyIdsFromEmail(emails);
if (c != null) {
c.close();
}
} catch (SecurityException e) {
insufficientPermissions();
}
if (!keyIds.isEmpty()) {
initialKeyIds = new long[keyIds.size()];
for (int i = 0, size = keyIds.size(); i < size; ++i) {
initialKeyIds[i] = keyIds.get(i);
}
}
} else {
initialKeyIds = apgData.getEncryptionKeys();
}
intent.putExtra(Constants.EXTRA_SELECTION, initialKeyIds);
intent.putExtra(EXTRA_SELECTION, initialKeyIds);
try {
activity.startActivityForResult(intent, Constants.SELECT_PUBLIC_KEYS);
activity.startActivityForResult(intent, SELECT_PUBLIC_KEYS);
return true;
} catch (ActivityNotFoundException e) {
activityNotFound();
@ -285,162 +311,8 @@ public class ApgIntentHelper {
}
}
/**
* 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(Constants.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(Constants.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(Constants.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(Constants.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(
Constants.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 activityNotFound() {
Toast.makeText(activity, "APG Activity not found! Is APG installed correctly?",
Toast.LENGTH_LONG).show();
}
private void insufficientPermissions() {
Toast.makeText(activity, "Permission to access APG Provider is missing!", Toast.LENGTH_LONG)
.show();
}
}

View File

@ -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;
// }
}
}

View File

@ -1,5 +1,4 @@
/*
* Copyright (C) 2010-2011 K-9 Mail Contributors
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -17,70 +16,12 @@
package org.thialfihar.android.apg.integration;
import android.net.Uri;
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;
public static final String AUTHORITY = "org.thialfihar.android.apg.provider";
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/");
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 String APG_INTENT_PREFIX = "org.thialfihar.android.apg.intent.";
public static class Intent {
public static final String DECRYPT = APG_INTENT_PREFIX + "DECRYPT";
public static final String ENCRYPT = APG_INTENT_PREFIX + "ENCRYPT";
public static final String DECRYPT_FILE = APG_INTENT_PREFIX + "DECRYPT_FILE";
public static final String ENCRYPT_FILE = APG_INTENT_PREFIX + "ENCRYPT_FILE";
public static final String DECRYPT_AND_RETURN = APG_INTENT_PREFIX + "DECRYPT_AND_RETURN";
public static final String ENCRYPT_AND_RETURN = APG_INTENT_PREFIX + "ENCRYPT_AND_RETURN";
public static final String SELECT_PUBLIC_KEYS = APG_INTENT_PREFIX + "SELECT_PUBLIC_KEYS";
public static final String SELECT_SECRET_KEY = APG_INTENT_PREFIX + "SELECT_SECRET_KEY";
public static final String CREATE_KEY = APG_INTENT_PREFIX + "CREATE_KEY";
public static final String 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;
}

View File

@ -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();
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2010-2011 K-9 Mail Contributors
* 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.