diff options
-rw-r--r-- | src/org/thialfihar/android/apg/ApgService.java | 270 |
1 files changed, 168 insertions, 102 deletions
diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 717383b98..ff2fb8ad8 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -7,7 +7,9 @@ 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 java.util.Set; import android.content.Intent; import android.os.Bundle; @@ -23,23 +25,74 @@ public class ApgService extends Service { return mBinder; } + /** error status */ private enum error { ARGUMENTS_MISSING, APG_FAILURE } + /** all arguments that can be passed by calling application */ + private enum arg { + MSG, // message to encrypt or to decrypt + SYM_KEY, // key for symmetric en/decryption + PUBLIC_KEYS, // public keys for encryption + ENCRYPTION_ALGO, // encryption algorithm + HASH_ALGO, // hash algorithm + ARMORED, // whether to armor output + FORCE_V3_SIG, // whether to force v3 signature + COMPRESSION + // what compression to use for encrypted output + } + + /** all things that might be returned */ + private enum ret { + ERRORS, + WARNINGS, + ERROR, + RESULT + } + + /** required arguments for each AIDL function */ + private static final HashMap<String, Set<arg>> FUNCTIONS_REQUIRED_ARGS = new HashMap<String, Set<arg>>(); + static { + HashSet<arg> args = new HashSet<arg>(); + args.add(arg.SYM_KEY); + args.add(arg.MSG); + FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_passphrase", args); + FUNCTIONS_REQUIRED_ARGS.put("decrypt_with_passphrase", args); + + args = new HashSet<arg>(); + args.add(arg.PUBLIC_KEYS); + args.add(arg.MSG); + FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_public_key", args); + } + + /** optional arguments for each AIDL function */ + private static final HashMap<String, Set<arg>> FUNCTIONS_OPTIONAL_ARGS = new HashMap<String, Set<arg>>(); + static { + HashSet<arg> args = new HashSet<arg>(); + args.add(arg.ENCRYPTION_ALGO); + args.add(arg.HASH_ALGO); + args.add(arg.ARMORED); + args.add(arg.FORCE_V3_SIG); + args.add(arg.COMPRESSION); + FUNCTIONS_OPTIONAL_ARGS.put("encrypt_with_passphrase", args); + FUNCTIONS_OPTIONAL_ARGS.put("encrypt_with_public_key", args); + FUNCTIONS_OPTIONAL_ARGS.put("decrypt_with_passphrase", args); + } + /** a map from ApgService parameters to function calls to get the default */ - static final HashMap<String, String> FUNCTIONS_DEFAULTS = new HashMap<String, String>(); + private static final HashMap<arg, String> FUNCTIONS_DEFAULTS = new HashMap<arg, String>(); static { - FUNCTIONS_DEFAULTS.put("ENCRYPTION_ALGO", "getDefaultEncryptionAlgorithm"); - FUNCTIONS_DEFAULTS.put("HASH_ALGO", "getDefaultHashAlgorithm"); - FUNCTIONS_DEFAULTS.put("ARMORED", "getDefaultAsciiArmour"); - FUNCTIONS_DEFAULTS.put("FORCE_V3_SIG", "getForceV3Signatures"); - FUNCTIONS_DEFAULTS.put("COMPRESSION", "getDefaultMessageCompression"); + FUNCTIONS_DEFAULTS.put(arg.ENCRYPTION_ALGO, "getDefaultEncryptionAlgorithm"); + FUNCTIONS_DEFAULTS.put(arg.HASH_ALGO, "getDefaultHashAlgorithm"); + FUNCTIONS_DEFAULTS.put(arg.ARMORED, "getDefaultAsciiArmour"); + FUNCTIONS_DEFAULTS.put(arg.FORCE_V3_SIG, "getForceV3Signatures"); + FUNCTIONS_DEFAULTS.put(arg.COMPRESSION, "getDefaultMessageCompression"); } /** a map the default functions to their return types */ - static final HashMap<String, Class> FUNCTIONS_DEFAULTS_TYPES = new HashMap<String, Class>(); + private static final HashMap<String, Class<?>> FUNCTIONS_DEFAULTS_TYPES = new HashMap<String, Class<?>>(); static { try { FUNCTIONS_DEFAULTS_TYPES.put("getDefaultEncryptionAlgorithm", Preferences.class.getMethod("getDefaultEncryptionAlgorithm").getReturnType()); @@ -53,7 +106,7 @@ public class ApgService extends Service { } /** a map the default function names to their method */ - static final HashMap<String, Method> FUNCTIONS_DEFAULTS_METHODS = new HashMap<String, 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")); @@ -73,17 +126,17 @@ public class ApgService extends Service { * the bundle to add default parameters to if missing * */ - private void add_defaults(Bundle args) { + private void add_default_arguments(Bundle args) { Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true); - Iterator<String> _iter = FUNCTIONS_DEFAULTS.keySet().iterator(); + Iterator<arg> _iter = FUNCTIONS_DEFAULTS.keySet().iterator(); while (_iter.hasNext()) { - String _current_key = _iter.next(); + arg _current_arg = _iter.next(); + String _current_key = _current_arg.name(); if (!args.containsKey(_current_key)) { - String _current_function_name = FUNCTIONS_DEFAULTS.get(_current_key); + String _current_function_name = FUNCTIONS_DEFAULTS.get(_current_arg); try { - @SuppressWarnings("unchecked") - 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) { args.putString(_current_key, (String) FUNCTIONS_DEFAULTS_METHODS.get(_current_function_name).invoke(_mPreferences)); } else if (_ret_type == boolean.class) { @@ -94,74 +147,98 @@ public class ApgService extends Service { Log.e(TAG, "Unknown return type " + _ret_type.toString() + " for default option"); } } catch (Exception e) { - Log.e(TAG, "Exception in add_defaults " + e.getMessage()); + Log.e(TAG, "Exception in add_default_arguments " + e.getMessage()); } } } } - private final IApgService.Stub mBinder = new IApgService.Stub() { - - public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { - - ArrayList<String> errors = new ArrayList<String>(); - ArrayList<String> warnings = new ArrayList<String>(); - - pReturn.putStringArrayList("ERRORS", errors); - pReturn.putStringArrayList("WARNINGS", warnings); - - Bundle _my_args = new Bundle(pArgs); - - /* add default values if missing */ - add_defaults(_my_args); + /** + * 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>(); - /* required args */ - String msg = _my_args.getString("MSG"); - _my_args.remove("MSG"); + pReturn.putStringArrayList(ret.ERRORS.name(), errors); + pReturn.putStringArrayList(ret.WARNINGS.name(), warnings); + } - String passphrase = _my_args.getString("SYM_KEY"); - _my_args.remove("SYM_KEY"); + /** + * 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) { + 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); + } + } + } - /* optional args */ - Boolean armored = _my_args.getBoolean("ARMORED"); - _my_args.remove("ARMORED"); + /** + * 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) { + HashSet<arg> all_args = new HashSet<arg>(FUNCTIONS_REQUIRED_ARGS.get(function)); + all_args.addAll(FUNCTIONS_OPTIONAL_ARGS.get(function)); - int encryption_algorithm = _my_args.getInt("ENCRYPTION_ALGO"); - _my_args.remove("ENCRYPTION_ALGO"); + Iterator<String> _iter = pArgs.keySet().iterator(); + while (_iter.hasNext()) { + String _cur_key = _iter.next(); + try { + arg.valueOf(_cur_key); + } catch (Exception e) { + pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key); + } - int hash_algorithm = _my_args.getInt("HASH_ALGO"); - _my_args.remove("HASH_ALGO"); + } + } - int compression = _my_args.getInt("COMPRESSION"); - _my_args.remove("COMPRESSION"); + private final IApgService.Stub mBinder = new IApgService.Stub() { - Boolean force_v3_signatures = _my_args.getBoolean("FORCE_V3_SIG"); - _my_args.remove("FORCE_V3_SIG"); + public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { + /* add default return values for all functions */ + add_default_returns(pReturn); - /* check required args */ - if (msg == null) { - errors.add("Message to encrypt (MSG) missing"); - } + /* add default arguments if missing */ + add_default_arguments(pArgs); + Log.d(TAG, "add_default_arguments"); - if (passphrase == null) { - errors.add("Symmetric key (SYM_KEY) missing"); - } + /* check for required arguments */ + check_required_args("encrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_required_args"); - /* check for unknown args and add to warning */ - if (!_my_args.isEmpty()) { - Iterator<String> _iter = _my_args.keySet().iterator(); - while (_iter.hasNext()) { - warnings.add("Unknown key: " + _iter.next()); - } - } + /* check for unknown arguments and add to warning if found */ + check_unknown_args("encrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_unknown_args"); /* return if errors happened */ - if (errors.size() != 0) { - pReturn.putInt("ERROR", error.ARGUMENTS_MISSING.ordinal()); + if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { + pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.ordinal()); return false; } + Log.d(TAG, "error return"); - InputStream _inStream = new ByteArrayInputStream(msg.getBytes()); + InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); InputData _in = new InputData(_inStream, 0); // XXX Size second // param? OutputStream _out = new ByteArrayOutputStream(); @@ -171,82 +248,71 @@ public class ApgService extends Service { Apg.encrypt(getApplicationContext(), // context _in, // input stream _out, // output stream - armored, // armored + pArgs.getBoolean(arg.ARMORED.name()), // armored new long[0], // encryption keys 0, // signature key null, // signature passphrase null, // progress - encryption_algorithm, // encryption - hash_algorithm, // hash - compression, // compression - force_v3_signatures, // mPreferences.getForceV3Signatures(), - passphrase // passPhrase + pArgs.getInt(arg.ENCRYPTION_ALGO.name()), // encryption + pArgs.getInt(arg.HASH_ALGO.name()), // hash + pArgs.getInt(arg.COMPRESSION.name()), // compression + pArgs.getBoolean(arg.FORCE_V3_SIG.name()), // mPreferences.getForceV3Signatures(), + pArgs.getString(arg.SYM_KEY.name()) // passPhrase ); } catch (Exception e) { Log.d(TAG, "Exception in encrypt"); - errors.add("Internal failure in APG when encrypting: " + e.getMessage()); + pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure in APG when encrypting: " + e.getMessage()); - pReturn.putInt("ERROR", error.APG_FAILURE.ordinal()); + pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); return false; } - Log.d(TAG, "Encrypted"); - pReturn.putString("RESULT", _out.toString()); + pReturn.putString(ret.RESULT.name(), _out.toString()); return true; } public boolean decrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { - ArrayList<String> errors = new ArrayList<String>(); - ArrayList<String> warnings = new ArrayList<String>(); - - pReturn.putStringArrayList("ERRORS", errors); - pReturn.putStringArrayList("WARNINGS", warnings); + /* add default return values for all functions */ + add_default_returns(pReturn); - String encrypted_msg = pArgs.getString("MSG"); - pArgs.remove("MSG"); + /* add default arguments if missing */ + add_default_arguments(pArgs); + Log.d(TAG, "add_default_arguments"); - String passphrase = pArgs.getString("SYM_KEY"); - pArgs.remove("SYM_KEY"); - if (encrypted_msg == null) { - errors.add("Message to decrypt (MSG) missing"); - } + /* check required args */ + check_required_args("decrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_required_args"); - if (passphrase == null) { - errors.add("Symmetric key (SYM_KEY) missing"); - } - if (!pArgs.isEmpty()) { - Iterator<String> iter = pArgs.keySet().iterator(); - while (iter.hasNext()) { - warnings.add("Unknown key: " + iter.next()); - } - } + /* check for unknown args and add to warning */ + check_unknown_args("decrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_unknown_args"); - if (errors.size() != 0) { - pReturn.putStringArrayList("ERROR", errors); - pReturn.putInt("ERROR", error.ARGUMENTS_MISSING.ordinal()); + + /* return if errors happened */ + if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { + pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.ordinal()); return false; } - InputStream inStream = new ByteArrayInputStream(encrypted_msg.getBytes()); + InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); InputData in = new InputData(inStream, 0); // XXX what size in // second parameter? OutputStream out = new ByteArrayOutputStream(); try { - Apg.decrypt(getApplicationContext(), in, out, passphrase, null, // progress + Apg.decrypt(getApplicationContext(), in, out, pArgs.getString(arg.SYM_KEY.name()), null, // progress true // symmetric ); } catch (Exception e) { Log.d(TAG, "Exception in decrypt"); - errors.add("Internal failure in APG when decrypting: " + e.getMessage()); + pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure in APG when decrypting: " + e.getMessage()); - pReturn.putInt("ERROR", error.APG_FAILURE.ordinal()); - pReturn.putStringArrayList("ERROR", errors); + pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); return false; } - pReturn.putString("RESULT", out.toString()); + pReturn.putString(ret.RESULT.name(), out.toString()); return true; } }; |