Allow to retrieve fingerprints and user ids through AIDL

Update ApgCon and doc accordingly.

Not very tested.
This commit is contained in:
Markus Doits 2011-01-23 21:36:35 +00:00
parent 6b7db8161a
commit 1ec5fc0541
3 changed files with 136 additions and 49 deletions

View File

@ -9,7 +9,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set;
import org.thialfihar.android.apg.provider.KeyRings; import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys; import org.thialfihar.android.apg.provider.Keys;
@ -55,8 +54,8 @@ public class ApgService extends Service {
FORCE_V3_SIGNATURE, // whether to force v3 signature FORCE_V3_SIGNATURE, // whether to force v3 signature
COMPRESSION, // what compression to use for encrypted output COMPRESSION, // what compression to use for encrypted output
SIGNATURE_KEY, // key for signing SIGNATURE_KEY, // key for signing
PRIVATE_KEY_PASSPHRASE PRIVATE_KEY_PASSPHRASE, // passphrase for encrypted private key
// passphrase for encrypted private key KEY_TYPE, // type of key (private or public)
} }
/** all things that might be returned */ /** all things that might be returned */
@ -64,12 +63,13 @@ public class ApgService extends Service {
ERRORS, // string array list with errors ERRORS, // string array list with errors
WARNINGS, // string array list with warnings WARNINGS, // string array list with warnings
ERROR, // numeric error ERROR, // numeric error
RESULT RESULT, // en-/decrypted
// en-/decrypted FINGERPRINTS, // fingerprints of keys
USER_IDS, // user ids
} }
/** required arguments for each AIDL function */ /** required arguments for each AIDL function */
private static final HashMap<String, Set<arg>> FUNCTIONS_REQUIRED_ARGS = new HashMap<String, Set<arg>>(); private static final HashMap<String, HashSet<arg>> FUNCTIONS_REQUIRED_ARGS = new HashMap<String, HashSet<arg>>();
static { static {
HashSet<arg> args = new HashSet<arg>(); HashSet<arg> args = new HashSet<arg>();
args.add(arg.SYMMETRIC_PASSPHRASE); args.add(arg.SYMMETRIC_PASSPHRASE);
@ -85,10 +85,14 @@ public class ApgService extends Service {
args.add(arg.MESSAGE); args.add(arg.MESSAGE);
FUNCTIONS_REQUIRED_ARGS.put("decrypt", args); FUNCTIONS_REQUIRED_ARGS.put("decrypt", args);
args = new HashSet<arg>();
args.add(arg.KEY_TYPE);
FUNCTIONS_REQUIRED_ARGS.put("get_keys", args);
} }
/** optional arguments for each AIDL function */ /** optional arguments for each AIDL function */
private static final HashMap<String, Set<arg>> FUNCTIONS_OPTIONAL_ARGS = new HashMap<String, Set<arg>>(); private static final HashMap<String, HashSet<arg>> FUNCTIONS_OPTIONAL_ARGS = new HashMap<String, HashSet<arg>>();
static { static {
HashSet<arg> args = new HashSet<arg>(); HashSet<arg> args = new HashSet<arg>();
args.add(arg.ENCRYPTION_ALGORYTHM); args.add(arg.ENCRYPTION_ALGORYTHM);
@ -166,6 +170,26 @@ public class ApgService extends Service {
return 0; return 0;
} }
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);
}
/** /**
* maps fingerprints or user ids of keys to master keys in database * maps fingerprints or user ids of keys to master keys in database
* *
@ -176,20 +200,14 @@ public class ApgService extends Service {
*/ */
private static long[] get_master_key(ArrayList<String> search_keys, Bundle pReturn) { private static long[] get_master_key(ArrayList<String> search_keys, Bundle pReturn) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); HashMap<String, Object> qParams = new HashMap<String, Object>();
qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " + "(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME qParams.put("columns", new String[] {
+ "." + 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 = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC";
Cursor mCursor = qb.query(Apg.getDatabase().db(), new String[] {
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0 KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1 UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1
}, KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?", new String[] { });
"" + Id.database.type_public qParams.put("key_type", Id.database.type_public);
}, null, null, orderBy);
Cursor mCursor = get_key_entries(qParams);
Log.v(TAG, "going through installed user keys"); Log.v(TAG, "going through installed user keys");
ArrayList<Long> _master_keys = new ArrayList<Long>(); ArrayList<Long> _master_keys = new ArrayList<Long>();
@ -235,27 +253,30 @@ public class ApgService extends Service {
* the bundle to add default parameters to if missing * the bundle to add default parameters to if missing
*/ */
private void add_default_arguments(String call, Bundle args) { private void add_default_arguments(String call, Bundle args) {
Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true); // check whether there are optional elements defined for that call
if (FUNCTIONS_OPTIONAL_ARGS.containsKey(call)) {
Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true);
Iterator<arg> _iter = FUNCTIONS_DEFAULTS.keySet().iterator(); Iterator<arg> _iter = FUNCTIONS_DEFAULTS.keySet().iterator();
while (_iter.hasNext()) { while (_iter.hasNext()) {
arg _current_arg = _iter.next(); arg _current_arg = _iter.next();
String _current_key = _current_arg.name(); String _current_key = _current_arg.name();
if (!args.containsKey(_current_key) && FUNCTIONS_OPTIONAL_ARGS.get(call).contains(_current_arg)) { if (!args.containsKey(_current_key) && FUNCTIONS_OPTIONAL_ARGS.get(call).contains(_current_arg)) {
String _current_function_name = FUNCTIONS_DEFAULTS.get(_current_arg); String _current_function_name = FUNCTIONS_DEFAULTS.get(_current_arg);
try { try {
Class<?> _ret_type = FUNCTIONS_DEFAULTS_TYPES.get(_current_function_name); Class<?> _ret_type = FUNCTIONS_DEFAULTS_TYPES.get(_current_function_name);
if (_ret_type == String.class) { if (_ret_type == String.class) {
args.putString(_current_key, (String) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences)); args.putString(_current_key, (String) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences));
} else if (_ret_type == boolean.class) { } else if (_ret_type == boolean.class) {
args.putBoolean(_current_key, (Boolean) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences)); args.putBoolean(_current_key, (Boolean) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences));
} else if (_ret_type == int.class) { } else if (_ret_type == int.class) {
args.putInt(_current_key, (Integer) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences)); args.putInt(_current_key, (Integer) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences));
} else { } else {
Log.e(TAG, "Unknown return type " + _ret_type.toString() + " for default option"); 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());
} }
} catch (Exception e) {
Log.e(TAG, "Exception in add_default_arguments " + e.getMessage());
} }
} }
} }
@ -286,11 +307,13 @@ public class ApgService extends Service {
* the bundle to write errors to * the bundle to write errors to
*/ */
private void check_required_args(String function, Bundle pArgs, Bundle pReturn) { private void check_required_args(String function, Bundle pArgs, Bundle pReturn) {
Iterator<arg> _iter = FUNCTIONS_REQUIRED_ARGS.get(function).iterator(); if (FUNCTIONS_REQUIRED_ARGS.containsKey(function)) {
while (_iter.hasNext()) { Iterator<arg> _iter = FUNCTIONS_REQUIRED_ARGS.get(function).iterator();
String _cur_arg = _iter.next().name(); while (_iter.hasNext()) {
if (!pArgs.containsKey(_cur_arg)) { String _cur_arg = _iter.next().name();
pReturn.getStringArrayList(ret.ERRORS.name()).add("Argument missing: " + _cur_arg); if (!pArgs.containsKey(_cur_arg)) {
pReturn.getStringArrayList(ret.ERRORS.name()).add("Argument missing: " + _cur_arg);
}
} }
} }
} }
@ -306,8 +329,14 @@ public class ApgService extends Service {
* the bundle to write warnings to * the bundle to write warnings to
*/ */
private void check_unknown_args(String function, Bundle pArgs, Bundle pReturn) { private void check_unknown_args(String function, Bundle pArgs, Bundle pReturn) {
HashSet<arg> all_args = new HashSet<arg>(FUNCTIONS_REQUIRED_ARGS.get(function));
all_args.addAll(FUNCTIONS_OPTIONAL_ARGS.get(function)); 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));
}
ArrayList<String> _unknown_args = new ArrayList<String>(); ArrayList<String> _unknown_args = new ArrayList<String>();
Iterator<String> _iter = pArgs.keySet().iterator(); Iterator<String> _iter = pArgs.keySet().iterator();
@ -415,6 +444,32 @@ public class ApgService extends Service {
private final IApgService.Stub mBinder = new IApgService.Stub() { private final IApgService.Stub mBinder = new IApgService.Stub() {
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()) {
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;
}
public boolean encrypt_with_public_key(Bundle pArgs, Bundle pReturn) { public boolean encrypt_with_public_key(Bundle pArgs, Bundle pReturn) {
if (!prepare_args("encrypt_with_public_key", pArgs, pReturn)) { if (!prepare_args("encrypt_with_public_key", pArgs, pReturn)) {
return false; return false;
@ -468,5 +523,6 @@ public class ApgService extends Service {
pReturn.putString(ret.RESULT.name(), out.toString()); pReturn.putString(ret.RESULT.name(), out.toString());
return true; return true;
} }
}; };
} }

View File

@ -14,7 +14,12 @@ interface IApgService {
* 104: Private key's passphrase missing * 104: Private key's passphrase missing
*/ */
/* Encryption function's arguments /* *******************************************************
* Encrypting and decrypting
* ********************************************************/
/* All encryption function's arguments
* *
* Bundle params' keys: * Bundle params' keys:
* (optional/required) * (optional/required)
@ -82,5 +87,27 @@ interface IApgService {
* Bundle return_vals: * Bundle return_vals:
* String "RESULT" = Decrypted message * String "RESULT" = Decrypted message
*/ */
boolean decrypt(in Bundle params, out Bundle return_vals);
boolean decrypt(in Bundle params, out Bundle return_vals);
/* *******************************************************
* 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 corrosponding fingerprints (order is the same)
*/
boolean get_keys(in Bundle params, out Bundle return_vals);
} }

View File

@ -327,6 +327,10 @@ public class ApgCon {
new call_async().execute(function); new call_async().execute(function);
} }
public boolean call(String function, Bundle pReturn) {
return call(function, args, pReturn);
}
private boolean call(String function, Bundle pArgs, Bundle pReturn) { private boolean call(String function, Bundle pArgs, Bundle pReturn) {
if (!initialize()) { if (!initialize()) {