2010-12-29 16:31:58 +00:00
|
|
|
package org.thialfihar.android.apg;
|
|
|
|
|
|
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.OutputStream;
|
2011-01-11 17:58:13 +00:00
|
|
|
import java.lang.reflect.Method;
|
2011-01-05 14:07:09 +00:00
|
|
|
import java.util.ArrayList;
|
2011-01-09 19:16:45 +00:00
|
|
|
import java.util.HashMap;
|
2011-01-11 22:24:20 +00:00
|
|
|
import java.util.HashSet;
|
2011-01-05 14:07:09 +00:00
|
|
|
import java.util.Iterator;
|
2010-12-29 16:31:58 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
import org.thialfihar.android.apg.provider.KeyRings;
|
|
|
|
|
import org.thialfihar.android.apg.provider.Keys;
|
|
|
|
|
import org.thialfihar.android.apg.provider.UserIds;
|
|
|
|
|
|
2010-12-29 16:31:58 +00:00
|
|
|
import android.content.Intent;
|
2011-01-13 20:12:10 +00:00
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.database.sqlite.SQLiteQueryBuilder;
|
2011-01-05 14:07:09 +00:00
|
|
|
import android.os.Bundle;
|
2010-12-29 16:31:58 +00:00
|
|
|
import android.os.IBinder;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
public class ApgService extends Service {
|
2011-01-18 20:35:33 +00:00
|
|
|
private final static String TAG = "ApgService";
|
2011-06-05 19:05:18 +00:00
|
|
|
private static final boolean LOCAL_LOGV = true;
|
|
|
|
|
private static final boolean LOCAL_LOGD = true;
|
2010-12-29 16:31:58 +00:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public IBinder onBind(Intent intent) {
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGD ) Log.d(TAG, "bound");
|
2010-12-29 16:31:58 +00:00
|
|
|
return mBinder;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-11 22:24:20 +00:00
|
|
|
/** error status */
|
2011-01-05 14:07:09 +00:00
|
|
|
private enum error {
|
|
|
|
|
ARGUMENTS_MISSING,
|
2011-01-13 20:12:10 +00:00
|
|
|
APG_FAILURE,
|
2011-01-18 21:17:05 +00:00
|
|
|
NO_MATCHING_SECRET_KEY,
|
|
|
|
|
PRIVATE_KEY_PASSPHRASE_WRONG,
|
2011-01-20 20:00:28 +00:00
|
|
|
PRIVATE_KEY_PASSPHRASE_MISSING;
|
2011-01-23 21:36:35 +00:00
|
|
|
|
2011-01-20 20:00:28 +00:00
|
|
|
public int shifted_ordinal() {
|
|
|
|
|
return ordinal() + 100;
|
|
|
|
|
}
|
2011-01-05 14:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
2011-01-11 22:24:20 +00:00
|
|
|
/** all arguments that can be passed by calling application */
|
|
|
|
|
private enum arg {
|
2011-01-18 20:35:41 +00:00
|
|
|
MESSAGE, // message to encrypt or to decrypt
|
|
|
|
|
SYMMETRIC_PASSPHRASE, // key for symmetric en/decryption
|
2011-01-11 22:24:20 +00:00
|
|
|
PUBLIC_KEYS, // public keys for encryption
|
2011-01-18 20:35:41 +00:00
|
|
|
ENCRYPTION_ALGORYTHM, // encryption algorithm
|
|
|
|
|
HASH_ALGORYTHM, // hash algorithm
|
|
|
|
|
ARMORED_OUTPUT, // whether to armor output
|
|
|
|
|
FORCE_V3_SIGNATURE, // whether to force v3 signature
|
2011-01-17 22:16:49 +00:00
|
|
|
COMPRESSION, // what compression to use for encrypted output
|
|
|
|
|
SIGNATURE_KEY, // key for signing
|
2011-01-23 21:36:35 +00:00
|
|
|
PRIVATE_KEY_PASSPHRASE, // passphrase for encrypted private key
|
|
|
|
|
KEY_TYPE, // type of key (private or public)
|
2011-01-11 22:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** all things that might be returned */
|
|
|
|
|
private enum ret {
|
2011-01-13 20:12:10 +00:00
|
|
|
ERRORS, // string array list with errors
|
|
|
|
|
WARNINGS, // string array list with warnings
|
|
|
|
|
ERROR, // numeric error
|
2011-01-23 21:36:35 +00:00
|
|
|
RESULT, // en-/decrypted
|
|
|
|
|
FINGERPRINTS, // fingerprints of keys
|
|
|
|
|
USER_IDS, // user ids
|
2011-01-11 22:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** required arguments for each AIDL function */
|
2011-01-23 21:36:35 +00:00
|
|
|
private static final HashMap<String, HashSet<arg>> FUNCTIONS_REQUIRED_ARGS = new HashMap<String, HashSet<arg>>();
|
2011-01-11 22:24:20 +00:00
|
|
|
static {
|
|
|
|
|
HashSet<arg> args = new HashSet<arg>();
|
2011-01-18 20:35:41 +00:00
|
|
|
args.add(arg.SYMMETRIC_PASSPHRASE);
|
|
|
|
|
args.add(arg.MESSAGE);
|
2011-01-11 22:24:20 +00:00
|
|
|
FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_passphrase", args);
|
|
|
|
|
|
|
|
|
|
args = new HashSet<arg>();
|
|
|
|
|
args.add(arg.PUBLIC_KEYS);
|
2011-01-18 20:35:41 +00:00
|
|
|
args.add(arg.MESSAGE);
|
2011-01-11 22:24:20 +00:00
|
|
|
FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_public_key", args);
|
2011-01-13 20:12:10 +00:00
|
|
|
|
|
|
|
|
args = new HashSet<arg>();
|
2011-01-18 20:35:41 +00:00
|
|
|
args.add(arg.MESSAGE);
|
2011-01-13 20:12:10 +00:00
|
|
|
FUNCTIONS_REQUIRED_ARGS.put("decrypt", args);
|
|
|
|
|
|
2011-01-23 21:36:35 +00:00
|
|
|
args = new HashSet<arg>();
|
|
|
|
|
args.add(arg.KEY_TYPE);
|
|
|
|
|
FUNCTIONS_REQUIRED_ARGS.put("get_keys", args);
|
|
|
|
|
|
2011-01-11 22:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** optional arguments for each AIDL function */
|
2011-01-23 21:36:35 +00:00
|
|
|
private static final HashMap<String, HashSet<arg>> FUNCTIONS_OPTIONAL_ARGS = new HashMap<String, HashSet<arg>>();
|
2011-01-11 22:24:20 +00:00
|
|
|
static {
|
|
|
|
|
HashSet<arg> args = new HashSet<arg>();
|
2011-01-18 20:35:41 +00:00
|
|
|
args.add(arg.ENCRYPTION_ALGORYTHM);
|
|
|
|
|
args.add(arg.HASH_ALGORYTHM);
|
|
|
|
|
args.add(arg.ARMORED_OUTPUT);
|
|
|
|
|
args.add(arg.FORCE_V3_SIGNATURE);
|
2011-01-11 22:24:20 +00:00
|
|
|
args.add(arg.COMPRESSION);
|
2011-01-18 20:35:41 +00:00
|
|
|
args.add(arg.PRIVATE_KEY_PASSPHRASE);
|
2011-01-17 22:16:49 +00:00
|
|
|
args.add(arg.SIGNATURE_KEY);
|
2011-01-11 22:24:20 +00:00
|
|
|
FUNCTIONS_OPTIONAL_ARGS.put("encrypt_with_passphrase", args);
|
|
|
|
|
FUNCTIONS_OPTIONAL_ARGS.put("encrypt_with_public_key", args);
|
2011-01-13 20:12:10 +00:00
|
|
|
|
|
|
|
|
args = new HashSet<arg>();
|
2011-01-18 20:35:41 +00:00
|
|
|
args.add(arg.SYMMETRIC_PASSPHRASE);
|
2011-01-13 20:12:10 +00:00
|
|
|
args.add(arg.PUBLIC_KEYS);
|
2011-01-18 20:35:41 +00:00
|
|
|
args.add(arg.PRIVATE_KEY_PASSPHRASE);
|
2011-01-13 20:12:10 +00:00
|
|
|
FUNCTIONS_OPTIONAL_ARGS.put("decrypt", args);
|
2011-01-11 22:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
2011-01-09 19:16:45 +00:00
|
|
|
/** a map from ApgService parameters to function calls to get the default */
|
2011-01-11 22:24:20 +00:00
|
|
|
private static final HashMap<arg, String> FUNCTIONS_DEFAULTS = new HashMap<arg, String>();
|
2011-01-09 19:16:45 +00:00
|
|
|
static {
|
2011-01-18 20:35:41 +00:00
|
|
|
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");
|
2011-01-11 22:24:20 +00:00
|
|
|
FUNCTIONS_DEFAULTS.put(arg.COMPRESSION, "getDefaultMessageCompression");
|
2011-01-09 19:16:45 +00:00
|
|
|
}
|
|
|
|
|
|
2011-01-11 17:58:13 +00:00
|
|
|
/** a map the default functions to their return types */
|
2011-01-11 22:24:20 +00:00
|
|
|
private static final HashMap<String, Class<?>> FUNCTIONS_DEFAULTS_TYPES = new HashMap<String, Class<?>>();
|
2011-01-11 17:58:13 +00:00
|
|
|
static {
|
|
|
|
|
try {
|
|
|
|
|
FUNCTIONS_DEFAULTS_TYPES.put("getDefaultEncryptionAlgorithm", Preferences.class.getMethod("getDefaultEncryptionAlgorithm").getReturnType());
|
|
|
|
|
FUNCTIONS_DEFAULTS_TYPES.put("getDefaultHashAlgorithm", Preferences.class.getMethod("getDefaultHashAlgorithm").getReturnType());
|
|
|
|
|
FUNCTIONS_DEFAULTS_TYPES.put("getDefaultAsciiArmour", Preferences.class.getMethod("getDefaultAsciiArmour").getReturnType());
|
|
|
|
|
FUNCTIONS_DEFAULTS_TYPES.put("getForceV3Signatures", Preferences.class.getMethod("getForceV3Signatures").getReturnType());
|
|
|
|
|
FUNCTIONS_DEFAULTS_TYPES.put("getDefaultMessageCompression", Preferences.class.getMethod("getDefaultMessageCompression").getReturnType());
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Function default exception: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** a map the default function names to their method */
|
2011-01-11 22:24:20 +00:00
|
|
|
private static final HashMap<String, Method> FUNCTIONS_DEFAULTS_METHODS = new HashMap<String, Method>();
|
2011-01-11 17:58:13 +00:00
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-17 22:16:49 +00:00
|
|
|
/**
|
|
|
|
|
* maps a fingerprint or user id of a key to as master key in database
|
|
|
|
|
*
|
|
|
|
|
* @param search_key
|
|
|
|
|
* fingerprint or user id to search for
|
|
|
|
|
* @return master key if found, or 0
|
|
|
|
|
*/
|
2011-01-20 18:38:15 +00:00
|
|
|
private static long get_master_key(String search_key, Bundle pReturn) {
|
2011-01-17 22:21:41 +00:00
|
|
|
if (search_key == null || search_key.length() != 8) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-01-17 22:16:49 +00:00
|
|
|
ArrayList<String> tmp = new ArrayList<String>();
|
|
|
|
|
tmp.add(search_key);
|
2011-01-20 18:38:15 +00:00
|
|
|
long[] _keys = get_master_key(tmp, pReturn);
|
2011-01-17 22:16:49 +00:00
|
|
|
if (_keys.length > 0)
|
|
|
|
|
return _keys[0];
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-23 21:36:35 +00:00
|
|
|
private static Cursor get_key_entries(HashMap<String, Object> params) {
|
|
|
|
|
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 = params.containsKey("order_by") ? (String) params.get("order_by") : UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
|
|
|
|
|
|
|
|
|
|
String type_val[] = null;
|
|
|
|
|
String type_where = null;
|
|
|
|
|
if (params.containsKey("key_type")) {
|
|
|
|
|
type_where = KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?";
|
|
|
|
|
type_val = new String[] {
|
|
|
|
|
"" + params.get("key_type")
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return qb.query(Apg.getDatabase().db(), (String[]) params.get("columns"), type_where, type_val, null, null, orderBy);
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2011-01-20 18:38:15 +00:00
|
|
|
private static long[] get_master_key(ArrayList<String> search_keys, Bundle pReturn) {
|
2011-01-13 20:12:10 +00:00
|
|
|
|
2011-01-23 21:36:35 +00:00
|
|
|
HashMap<String, Object> qParams = new HashMap<String, Object>();
|
|
|
|
|
qParams.put("columns", new String[] {
|
2011-01-23 21:36:27 +00:00
|
|
|
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0
|
|
|
|
|
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1
|
2011-01-23 21:36:35 +00:00
|
|
|
});
|
|
|
|
|
qParams.put("key_type", Id.database.type_public);
|
|
|
|
|
|
|
|
|
|
Cursor mCursor = get_key_entries(qParams);
|
2011-01-13 20:12:10 +00:00
|
|
|
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "going through installed user keys");
|
2011-01-13 20:12:10 +00:00
|
|
|
ArrayList<Long> _master_keys = new ArrayList<Long>();
|
|
|
|
|
while (mCursor.moveToNext()) {
|
2011-01-23 21:36:27 +00:00
|
|
|
long _cur_mkey = mCursor.getLong(0);
|
|
|
|
|
String _cur_user = mCursor.getString(1);
|
2011-01-20 18:38:15 +00:00
|
|
|
|
2011-01-20 18:19:42 +00:00
|
|
|
String _cur_fprint = Apg.getSmallFingerPrint(_cur_mkey);
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "current user: " + _cur_user + " (" + _cur_fprint + ")");
|
2011-01-20 18:19:42 +00:00
|
|
|
if (search_keys.contains(_cur_fprint) || search_keys.contains(_cur_user)) {
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "master key found for: " + _cur_fprint);
|
2011-01-13 20:12:10 +00:00
|
|
|
_master_keys.add(_cur_mkey);
|
2011-01-20 18:19:42 +00:00
|
|
|
search_keys.remove(_cur_fprint);
|
|
|
|
|
} else {
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "Installed key " + _cur_fprint + " is not in the list of public keys to encrypt with");
|
2011-01-13 20:12:10 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mCursor.close();
|
|
|
|
|
|
|
|
|
|
long[] _master_longs = new long[_master_keys.size()];
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (Long _key : _master_keys) {
|
|
|
|
|
_master_longs[i++] = _key;
|
|
|
|
|
}
|
2011-01-20 18:38:15 +00:00
|
|
|
|
|
|
|
|
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");
|
2011-01-20 18:19:42 +00:00
|
|
|
}
|
2011-01-20 18:38:15 +00:00
|
|
|
|
|
|
|
|
for (String _key : search_keys) {
|
|
|
|
|
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");
|
2011-01-20 18:19:42 +00:00
|
|
|
}
|
2011-01-20 18:38:15 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
return _master_longs;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-09 19:16:45 +00:00
|
|
|
/**
|
|
|
|
|
* Add default arguments if missing
|
|
|
|
|
*
|
|
|
|
|
* @param args
|
|
|
|
|
* the bundle to add default parameters to if missing
|
|
|
|
|
*/
|
2011-01-13 20:12:10 +00:00
|
|
|
private void add_default_arguments(String call, Bundle args) {
|
2011-01-23 21:36:35 +00:00
|
|
|
// check whether there are optional elements defined for that call
|
|
|
|
|
if (FUNCTIONS_OPTIONAL_ARGS.containsKey(call)) {
|
|
|
|
|
Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true);
|
2011-01-09 19:16:45 +00:00
|
|
|
|
2011-01-23 21:36:35 +00:00
|
|
|
Iterator<arg> _iter = FUNCTIONS_DEFAULTS.keySet().iterator();
|
|
|
|
|
while (_iter.hasNext()) {
|
|
|
|
|
arg _current_arg = _iter.next();
|
|
|
|
|
String _current_key = _current_arg.name();
|
|
|
|
|
if (!args.containsKey(_current_key) && FUNCTIONS_OPTIONAL_ARGS.get(call).contains(_current_arg)) {
|
|
|
|
|
String _current_function_name = FUNCTIONS_DEFAULTS.get(_current_arg);
|
|
|
|
|
try {
|
|
|
|
|
Class<?> _ret_type = FUNCTIONS_DEFAULTS_TYPES.get(_current_function_name);
|
|
|
|
|
if (_ret_type == String.class) {
|
|
|
|
|
args.putString(_current_key, (String) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences));
|
|
|
|
|
} else if (_ret_type == boolean.class) {
|
|
|
|
|
args.putBoolean(_current_key, (Boolean) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences));
|
|
|
|
|
} else if (_ret_type == int.class) {
|
|
|
|
|
args.putInt(_current_key, (Integer) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences));
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Unknown return type " + _ret_type.toString() + " for default option");
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Exception in add_default_arguments " + e.getMessage());
|
2011-01-09 19:16:45 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-11 22:24:20 +00:00
|
|
|
/**
|
|
|
|
|
* updates a Bundle with default return values
|
|
|
|
|
*
|
|
|
|
|
* @param pReturn
|
|
|
|
|
* the Bundle to update
|
|
|
|
|
*/
|
|
|
|
|
private void add_default_returns(Bundle pReturn) {
|
|
|
|
|
ArrayList<String> errors = new ArrayList<String>();
|
|
|
|
|
ArrayList<String> warnings = new ArrayList<String>();
|
2011-01-09 19:16:45 +00:00
|
|
|
|
2011-01-11 22:24:20 +00:00
|
|
|
pReturn.putStringArrayList(ret.ERRORS.name(), errors);
|
|
|
|
|
pReturn.putStringArrayList(ret.WARNINGS.name(), warnings);
|
|
|
|
|
}
|
2011-01-09 19:16:45 +00:00
|
|
|
|
2011-01-11 22:24:20 +00:00
|
|
|
/**
|
|
|
|
|
* 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 check_required_args(String function, Bundle pArgs, Bundle pReturn) {
|
2011-01-23 21:36:35 +00:00
|
|
|
if (FUNCTIONS_REQUIRED_ARGS.containsKey(function)) {
|
|
|
|
|
Iterator<arg> _iter = FUNCTIONS_REQUIRED_ARGS.get(function).iterator();
|
|
|
|
|
while (_iter.hasNext()) {
|
|
|
|
|
String _cur_arg = _iter.next().name();
|
|
|
|
|
if (!pArgs.containsKey(_cur_arg)) {
|
|
|
|
|
pReturn.getStringArrayList(ret.ERRORS.name()).add("Argument missing: " + _cur_arg);
|
|
|
|
|
}
|
2011-01-11 22:24:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-01-09 19:16:45 +00:00
|
|
|
|
2011-01-11 22:24:20 +00:00
|
|
|
/**
|
|
|
|
|
* 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 check_unknown_args(String function, Bundle pArgs, Bundle pReturn) {
|
2011-01-23 21:36:35 +00:00
|
|
|
|
|
|
|
|
HashSet<arg> all_args = new HashSet<arg>();
|
|
|
|
|
if (FUNCTIONS_REQUIRED_ARGS.containsKey(function)) {
|
|
|
|
|
all_args.addAll(FUNCTIONS_REQUIRED_ARGS.get(function));
|
|
|
|
|
}
|
|
|
|
|
if (FUNCTIONS_OPTIONAL_ARGS.containsKey(function)) {
|
|
|
|
|
all_args.addAll(FUNCTIONS_OPTIONAL_ARGS.get(function));
|
|
|
|
|
}
|
2011-01-09 19:16:45 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
ArrayList<String> _unknown_args = new ArrayList<String>();
|
2011-01-11 22:24:20 +00:00
|
|
|
Iterator<String> _iter = pArgs.keySet().iterator();
|
|
|
|
|
while (_iter.hasNext()) {
|
|
|
|
|
String _cur_key = _iter.next();
|
|
|
|
|
try {
|
2011-01-11 22:31:35 +00:00
|
|
|
arg _cur_arg = arg.valueOf(_cur_key);
|
2011-01-13 20:12:10 +00:00
|
|
|
if (!all_args.contains(_cur_arg)) {
|
2011-01-11 22:31:35 +00:00
|
|
|
pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key);
|
2011-01-13 20:12:10 +00:00
|
|
|
_unknown_args.add(_cur_key);
|
2011-01-11 22:31:35 +00:00
|
|
|
}
|
2011-01-11 22:24:20 +00:00
|
|
|
} catch (Exception e) {
|
|
|
|
|
pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key);
|
2011-01-13 20:12:10 +00:00
|
|
|
_unknown_args.add(_cur_key);
|
2011-01-11 22:24:20 +00:00
|
|
|
}
|
2011-01-13 20:12:10 +00:00
|
|
|
}
|
2011-01-09 19:16:45 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
// remove unknown arguments so our bundle has just what we need
|
|
|
|
|
for (String _arg : _unknown_args) {
|
|
|
|
|
pArgs.remove(_arg);
|
2011-01-11 22:24:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
2011-01-09 19:16:45 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
private boolean prepare_args(String call, Bundle pArgs, Bundle pReturn) {
|
|
|
|
|
Apg.initialize(getBaseContext());
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
/* add default return values for all functions */
|
|
|
|
|
add_default_returns(pReturn);
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
/* add default arguments if missing */
|
|
|
|
|
add_default_arguments(call, pArgs);
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "add_default_arguments");
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
/* check for required arguments */
|
|
|
|
|
check_required_args(call, pArgs, pReturn);
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "check_required_args");
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
/* check for unknown arguments and add to warning if found */
|
|
|
|
|
check_unknown_args(call, pArgs, pReturn);
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "check_unknown_args");
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
/* return if errors happened */
|
|
|
|
|
if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) {
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "Errors after preparing, not executing "+call);
|
2011-01-20 20:00:28 +00:00
|
|
|
pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.shifted_ordinal());
|
2011-01-13 20:12:10 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "error return");
|
2011-01-04 23:08:08 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2010-12-29 16:31:58 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
private boolean encrypt(Bundle pArgs, Bundle pReturn) {
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
long _pub_master_keys[] = {};
|
|
|
|
|
if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) {
|
|
|
|
|
ArrayList<String> _list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name());
|
|
|
|
|
ArrayList<String> _pub_keys = new ArrayList<String>();
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "Long size: " + _list.size());
|
2011-01-13 20:12:10 +00:00
|
|
|
Iterator<String> _iter = _list.iterator();
|
|
|
|
|
while (_iter.hasNext()) {
|
|
|
|
|
_pub_keys.add(_iter.next());
|
2010-12-29 16:31:58 +00:00
|
|
|
}
|
2011-01-20 18:38:15 +00:00
|
|
|
_pub_master_keys = get_master_key(_pub_keys, pReturn);
|
2010-12-29 16:31:58 +00:00
|
|
|
}
|
|
|
|
|
|
2011-01-18 20:35:41 +00:00
|
|
|
InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
|
2011-01-17 22:16:49 +00:00
|
|
|
InputData _in = new InputData(_inStream, 0); // XXX Size second param?
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
OutputStream _out = new ByteArrayOutputStream();
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "About to encrypt");
|
2011-01-13 20:12:10 +00:00
|
|
|
try {
|
|
|
|
|
Apg.encrypt(getBaseContext(), // context
|
|
|
|
|
_in, // input stream
|
|
|
|
|
_out, // output stream
|
2011-01-18 20:35:41 +00:00
|
|
|
pArgs.getBoolean(arg.ARMORED_OUTPUT.name()), // ARMORED_OUTPUT
|
2011-01-13 20:12:10 +00:00
|
|
|
_pub_master_keys, // encryption keys
|
2011-01-20 18:38:15 +00:00
|
|
|
get_master_key(pArgs.getString(arg.SIGNATURE_KEY.name()), pReturn), // signature key
|
2011-01-18 20:35:41 +00:00
|
|
|
pArgs.getString(arg.PRIVATE_KEY_PASSPHRASE.name()), // signature passphrase
|
2011-01-13 20:12:10 +00:00
|
|
|
null, // progress
|
2011-01-18 20:35:41 +00:00
|
|
|
pArgs.getInt(arg.ENCRYPTION_ALGORYTHM.name()), // encryption
|
|
|
|
|
pArgs.getInt(arg.HASH_ALGORYTHM.name()), // hash
|
2011-01-13 20:12:10 +00:00
|
|
|
pArgs.getInt(arg.COMPRESSION.name()), // compression
|
2011-01-18 20:35:41 +00:00
|
|
|
pArgs.getBoolean(arg.FORCE_V3_SIGNATURE.name()), // mPreferences.getForceV3Signatures(),
|
|
|
|
|
pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) // passPhrase
|
2011-01-13 20:12:10 +00:00
|
|
|
);
|
|
|
|
|
} catch (Exception e) {
|
2011-01-18 20:35:33 +00:00
|
|
|
Log.e(TAG, "Exception in encrypt");
|
2011-01-18 21:17:05 +00:00
|
|
|
String _msg = e.getMessage();
|
2011-01-18 22:24:28 +00:00
|
|
|
if (_msg.equals(getBaseContext().getString(R.string.error_noSignaturePassPhrase))) {
|
2011-01-18 21:17:05 +00:00
|
|
|
pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot encrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name() + " missing): " + _msg);
|
2011-01-20 20:00:28 +00:00
|
|
|
pReturn.putInt(ret.ERROR.name(), error.PRIVATE_KEY_PASSPHRASE_MISSING.shifted_ordinal());
|
2011-01-18 22:24:28 +00:00
|
|
|
} else if (_msg.equals(getBaseContext().getString(R.string.error_couldNotExtractPrivateKey))) {
|
2011-01-18 21:17:05 +00:00
|
|
|
pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot encrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name() + " probably wrong): " + _msg);
|
2011-01-20 20:00:28 +00:00
|
|
|
pReturn.putInt(ret.ERROR.name(), error.PRIVATE_KEY_PASSPHRASE_WRONG.shifted_ordinal());
|
2011-01-18 21:17:05 +00:00
|
|
|
} else {
|
|
|
|
|
pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when encrypting: " + e.getMessage());
|
2011-01-20 20:00:28 +00:00
|
|
|
pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shifted_ordinal());
|
2011-01-18 21:17:05 +00:00
|
|
|
}
|
2011-01-13 20:12:10 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "Encrypted");
|
2011-01-13 20:12:10 +00:00
|
|
|
pReturn.putString(ret.RESULT.name(), _out.toString());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
private final IApgService.Stub mBinder = new IApgService.Stub() {
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-23 21:36:35 +00:00
|
|
|
public boolean get_keys(Bundle pArgs, Bundle pReturn) {
|
|
|
|
|
|
|
|
|
|
prepare_args("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 mCursor = get_key_entries(qParams);
|
|
|
|
|
ArrayList<String> fprints = new ArrayList<String>();
|
|
|
|
|
ArrayList<String> ids = new ArrayList<String>();
|
|
|
|
|
while (mCursor.moveToNext()) {
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "adding key "+Apg.getSmallFingerPrint(mCursor.getLong(0)));
|
2011-01-23 21:36:35 +00:00
|
|
|
fprints.add(Apg.getSmallFingerPrint(mCursor.getLong(0)));
|
|
|
|
|
ids.add(mCursor.getString(1));
|
|
|
|
|
}
|
|
|
|
|
mCursor.close();
|
|
|
|
|
|
|
|
|
|
pReturn.putStringArrayList(ret.FINGERPRINTS.name(), fprints);
|
|
|
|
|
pReturn.putStringArrayList(ret.USER_IDS.name(), ids);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
public boolean encrypt_with_public_key(Bundle pArgs, Bundle pReturn) {
|
|
|
|
|
if (!prepare_args("encrypt_with_public_key", pArgs, pReturn)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
return encrypt(pArgs, pReturn);
|
|
|
|
|
}
|
2011-01-05 14:07:09 +00:00
|
|
|
|
2011-01-13 20:12:10 +00:00
|
|
|
public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) {
|
|
|
|
|
if (!prepare_args("encrypt_with_passphrase", pArgs, pReturn)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return encrypt(pArgs, pReturn);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean decrypt(Bundle pArgs, Bundle pReturn) {
|
|
|
|
|
if (!prepare_args("decrypt", pArgs, pReturn)) {
|
2011-01-05 14:07:09 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2011-01-04 23:08:08 +00:00
|
|
|
|
2011-01-18 21:17:05 +00:00
|
|
|
String _passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs
|
|
|
|
|
.getString(arg.PRIVATE_KEY_PASSPHRASE.name());
|
2011-01-17 22:16:49 +00:00
|
|
|
|
2011-01-18 20:35:41 +00:00
|
|
|
InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes());
|
2011-01-17 22:16:49 +00:00
|
|
|
InputData in = new InputData(inStream, 0); // XXX what size in second parameter?
|
2010-12-29 16:31:58 +00:00
|
|
|
OutputStream out = new ByteArrayOutputStream();
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "About to decrypt");
|
2010-12-29 16:31:58 +00:00
|
|
|
try {
|
2011-01-17 22:16:49 +00:00
|
|
|
Apg.decrypt(getBaseContext(), in, out, _passphrase, null, // progress
|
2011-01-18 20:35:41 +00:00
|
|
|
pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null // symmetric
|
2010-12-29 16:31:58 +00:00
|
|
|
);
|
|
|
|
|
} catch (Exception e) {
|
2011-01-18 20:35:33 +00:00
|
|
|
Log.e(TAG, "Exception in decrypt");
|
2011-01-18 21:17:05 +00:00
|
|
|
String _msg = e.getMessage();
|
2011-01-18 22:24:28 +00:00
|
|
|
if (_msg.equals(getBaseContext().getString(R.string.error_noSecretKeyFound))) {
|
2011-01-18 21:17:05 +00:00
|
|
|
pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot decrypt: " + _msg);
|
2011-01-20 20:00:28 +00:00
|
|
|
pReturn.putInt(ret.ERROR.name(), error.NO_MATCHING_SECRET_KEY.shifted_ordinal());
|
2011-01-18 22:24:28 +00:00
|
|
|
} else if (_msg.equals(getBaseContext().getString(R.string.error_wrongPassPhrase))) {
|
2011-01-18 21:17:05 +00:00
|
|
|
pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot decrypt (" + arg.PRIVATE_KEY_PASSPHRASE.name() + " wrong/missing): " + _msg);
|
2011-01-20 20:00:28 +00:00
|
|
|
pReturn.putInt(ret.ERROR.name(), error.PRIVATE_KEY_PASSPHRASE_WRONG.shifted_ordinal());
|
2011-01-13 20:12:10 +00:00
|
|
|
} else {
|
2011-01-18 21:17:05 +00:00
|
|
|
pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when decrypting: " + _msg);
|
2011-01-20 20:00:28 +00:00
|
|
|
pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shifted_ordinal());
|
2011-01-13 20:12:10 +00:00
|
|
|
}
|
2011-01-05 14:07:09 +00:00
|
|
|
return false;
|
2010-12-29 16:31:58 +00:00
|
|
|
}
|
2011-06-05 19:05:18 +00:00
|
|
|
if( LOCAL_LOGV ) Log.v(TAG, "Decrypted");
|
2010-12-29 16:31:58 +00:00
|
|
|
|
2011-01-11 22:24:20 +00:00
|
|
|
pReturn.putString(ret.RESULT.name(), out.toString());
|
2011-01-05 14:07:09 +00:00
|
|
|
return true;
|
2010-12-29 16:31:58 +00:00
|
|
|
}
|
2011-01-23 21:36:35 +00:00
|
|
|
|
2010-12-29 16:31:58 +00:00
|
|
|
};
|
|
|
|
|
}
|