From fc08f14ef180d492f34d4fadeee321b5aabecf13 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Mon, 27 Dec 2010 18:33:05 +0000 Subject: [PATCH 01/69] Branch for ApgService AIDL development until spec is final From e8d29c01c286f24f660f6d1c55f896c7bc0994c9 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 29 Dec 2010 16:31:58 +0000 Subject: [PATCH 02/69] Add first basic implementation of Apgservice Provides an AIDL-API for other apps to encrypt and decrypt a string symmetrically with a passphrase. Function names and API is by no way finalized and will change! Support for asymetric encription will follow. For reference and discussion see issue #71, https://code.google.com/p/android-privacy-guard/issues/detail?id=71 --- AndroidManifest.xml | 6 +- .../thialfihar/android/apg/ApgService.java | 76 +++++++++++++++++++ .../thialfihar/android/apg/IApgService.aidl | 6 ++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/org/thialfihar/android/apg/ApgService.java create mode 100644 src/org/thialfihar/android/apg/IApgService.aidl diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 47197a129..0ece93e55 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -195,7 +195,11 @@ android:configChanges="keyboardHidden|orientation|keyboard"/> - + + + + + Date: Wed, 29 Dec 2010 16:43:10 +0000 Subject: [PATCH 03/69] Merge trunk into apg_service --- res/values-it/strings.xml | 6 + src/org/thialfihar/android/apg/Apg.java | 146 ++++++++++++++++-------- 2 files changed, 102 insertions(+), 50 deletions(-) diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index b252606c4..d1d76f09d 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -141,6 +141,7 @@ scaduto non valido %s key server(s) + fingerprint Nessuno @@ -154,6 +155,10 @@ 10 min 20 min 40 min + 1 ora + 2 ore + 4 ore + 8 ore tutta la sessione Default di sistema @@ -223,6 +228,7 @@ non è stato trovato nessun tipo di crittazione valido la scheda di memoria non è pronta o non è utilizzabile acconto \'%s\' non trovato + accesso in lettura all'\account negato non è stato possibile aggiungere l\'acconto \'%s\' mail non valida \'%s\' la dimensione della chiave deve essere almeno di 512bit diff --git a/src/org/thialfihar/android/apg/Apg.java b/src/org/thialfihar/android/apg/Apg.java index b7d327077..cf71185e1 100644 --- a/src/org/thialfihar/android/apg/Apg.java +++ b/src/org/thialfihar/android/apg/Apg.java @@ -400,7 +400,8 @@ public class Apg { throws Apg.GeneralException, NoSuchProviderException, PGPException, NoSuchAlgorithmException, SignatureException, IOException, Database.GeneralException { - progress.setProgress(R.string.progress_buildingKey, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_buildingKey, 0, 100); Security.addProvider(new BouncyCastleProvider()); @@ -461,7 +462,8 @@ public class Apg { keys.add(editor.getValue()); } - progress.setProgress(R.string.progress_preparingMasterKey, 10, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingMasterKey, 10, 100); KeyEditor keyEditor = (KeyEditor) keyEditors.getChildAt(0); int usageId = keyEditor.getUsage(); boolean canSign = (usageId == Id.choice.usage.sign_only || @@ -481,7 +483,8 @@ public class Apg { masterKey.extractPrivateKey(oldPassPhrase.toCharArray(), new BouncyCastleProvider()); - progress.setProgress(R.string.progress_certifyingMasterKey, 20, 100); + if( progress != null ) + progress.setProgress(R.string.progress_certifyingMasterKey, 20, 100); for (int i = 0; i < userIds.size(); ++i) { String userId = userIds.get(i); @@ -525,7 +528,8 @@ public class Apg { hashedPacketsGen.setKeyExpirationTime(true, numDays * 86400); } - progress.setProgress(R.string.progress_buildingMasterKeyRing, 30, 100); + if( progress != null ) + progress.setProgress(R.string.progress_buildingMasterKeyRing, 30, 100); PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, masterKeyPair, mainUserId, @@ -533,9 +537,11 @@ public class Apg { hashedPacketsGen.generate(), unhashedPacketsGen.generate(), new SecureRandom(), new BouncyCastleProvider().getName()); - progress.setProgress(R.string.progress_addingSubKeys, 40, 100); + if( progress != null ) + progress.setProgress(R.string.progress_addingSubKeys, 40, 100); for (int i = 1; i < keys.size(); ++i) { - progress.setProgress(40 + 50 * (i - 1)/ (keys.size() - 1), 100); + if( progress != null ) + progress.setProgress(40 + 50 * (i - 1)/ (keys.size() - 1), 100); PGPSecretKey subKey = keys.get(i); keyEditor = (KeyEditor) keyEditors.getChildAt(i); PGPPublicKey subPublicKey = subKey.getPublicKey(); @@ -584,11 +590,13 @@ public class Apg { PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing(); PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing(); - progress.setProgress(R.string.progress_savingKeyRing, 90, 100); + if( progress != null ) + progress.setProgress(R.string.progress_savingKeyRing, 90, 100); mDatabase.saveKeyRing(secretKeyRing); mDatabase.saveKeyRing(publicKeyRing); - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); } public static Bundle importKeyRings(Activity context, int type, @@ -598,9 +606,11 @@ public class Apg { Bundle returnData = new Bundle(); if (type == Id.type.secret_key) { - progress.setProgress(R.string.progress_importingSecretKeys, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_importingSecretKeys, 0, 100); } else { - progress.setProgress(R.string.progress_importingPublicKeys, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_importingPublicKeys, 0, 100); } if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { @@ -671,7 +681,8 @@ public class Apg { } else if (retValue == Id.return_value.bad) { ++badKeys; } - progress.setProgress((int)(100 * progressIn.position() / data.getSize()), 100); + if( progress != null ) + progress.setProgress((int)(100 * progressIn.position() / data.getSize()), 100); obj = objectFactory.nextObject(); } } @@ -683,7 +694,8 @@ public class Apg { returnData.putInt("updated", oldKeys); returnData.putInt("bad", badKeys); - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); return returnData; } @@ -695,9 +707,11 @@ public class Apg { Bundle returnData = new Bundle(); if (keyRingIds.size() == 1) { - progress.setProgress(R.string.progress_exportingKey, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_exportingKey, 0, 100); } else { - progress.setProgress(R.string.progress_exportingKeys, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_exportingKeys, 0, 100); } if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { @@ -707,7 +721,8 @@ public class Apg { int numKeys = 0; for (int i = 0; i < keyRingIds.size(); ++i) { - progress.setProgress(i * 100 / keyRingIds.size(), 100); + if( progress != null ) + progress.setProgress(i * 100 / keyRingIds.size(), 100); Object obj = mDatabase.getKeyRing(keyRingIds.get(i)); PGPPublicKeyRing publicKeyRing; PGPSecretKeyRing secretKeyRing; @@ -726,7 +741,8 @@ public class Apg { out.close(); returnData.putInt("exported", numKeys); - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); return returnData; } @@ -1236,15 +1252,16 @@ public class Apg { if (signaturePassPhrase == null) { throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase)); } - progress.setProgress(R.string.progress_extractingSignatureKey, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_extractingSignatureKey, 0, 100); signaturePrivateKey = signingKey.extractPrivateKey(signaturePassPhrase.toCharArray(), new BouncyCastleProvider()); if (signaturePrivateKey == null) { throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey)); } } - - progress.setProgress(R.string.progress_preparingStreams, 5, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingStreams, 5, 100); // encrypt and compress input file content PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(symmetricAlgorithm, true, new SecureRandom(), @@ -1266,7 +1283,8 @@ public class Apg { PGPV3SignatureGenerator signatureV3Generator = null; if (signatureKeyId != 0) { - progress.setProgress(R.string.progress_preparingSignature, 10, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingSignature, 10, 100); if (forceV3Signature) { signatureV3Generator = new PGPV3SignatureGenerator(signingKey.getPublicKey().getAlgorithm(), @@ -1307,8 +1325,8 @@ public class Apg { // file name not needed, so empty string OutputStream pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(), new byte[1 << 16]); - - progress.setProgress(R.string.progress_encrypting, 20, 100); + if( progress != null ) + progress.setProgress(R.string.progress_encrypting, 20, 100); long done = 0; int n = 0; byte[] buffer = new byte[1 << 16]; @@ -1324,14 +1342,16 @@ public class Apg { } done += n; if (data.getSize() != 0) { - progress.setProgress((int) (20 + (95 - 20) * done / data.getSize()), 100); + if( progress != null ) + progress.setProgress((int) (20 + (95 - 20) * done / data.getSize()), 100); } } literalGen.close(); if (signatureKeyId != 0) { - progress.setProgress(R.string.progress_generatingSignature, 95, 100); + if( progress != null ) + progress.setProgress(R.string.progress_generatingSignature, 95, 100); if (forceV3Signature) { signatureV3Generator.generate().encode(pOut); } else { @@ -1346,7 +1366,8 @@ public class Apg { armorOut.close(); } - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); } public static void signText(Context context, @@ -1385,9 +1406,11 @@ public class Apg { if (signaturePrivateKey == null) { throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey)); } - progress.setProgress(R.string.progress_preparingStreams, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingStreams, 0, 100); - progress.setProgress(R.string.progress_preparingSignature, 30, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingSignature, 30, 100); PGPSignatureGenerator signatureGenerator = null; PGPV3SignatureGenerator signatureV3Generator = null; @@ -1411,7 +1434,8 @@ public class Apg { signatureGenerator.setHashedSubpackets(spGen.generate()); } - progress.setProgress(R.string.progress_signing, 40, 100); + if( progress != null ) + progress.setProgress(R.string.progress_signing, 40, 100); armorOut.beginClearText(hashAlgorithm); @@ -1454,7 +1478,8 @@ public class Apg { } armorOut.close(); - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); } public static void generateSignature(Context context, @@ -1501,9 +1526,11 @@ public class Apg { if (signaturePrivateKey == null) { throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey)); } - progress.setProgress(R.string.progress_preparingStreams, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingStreams, 0, 100); - progress.setProgress(R.string.progress_preparingSignature, 30, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingSignature, 30, 100); PGPSignatureGenerator signatureGenerator = null; PGPV3SignatureGenerator signatureV3Generator = null; @@ -1532,7 +1559,8 @@ public class Apg { signatureGenerator.setHashedSubpackets(spGen.generate()); } - progress.setProgress(R.string.progress_signing, 40, 100); + if( progress != null ) + progress.setProgress(R.string.progress_signing, 40, 100); InputStream inStream = data.getInputStream(); if (binary) { @@ -1575,7 +1603,8 @@ public class Apg { out.close(); outStream.close(); - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); } public static long getDecryptionKeyId(Context context, InputData data) @@ -1669,7 +1698,8 @@ public class Apg { long signatureKeyId = 0; int currentProgress = 0; - progress.setProgress(R.string.progress_readingData, currentProgress, 100); + if( progress != null ) + progress.setProgress(R.string.progress_readingData, currentProgress, 100); if (o instanceof PGPEncryptedDataList) { enc = (PGPEncryptedDataList) o; @@ -1704,12 +1734,14 @@ public class Apg { throw new GeneralException(context.getString(R.string.error_noSymmetricEncryptionPacket)); } - progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100); clear = pbe.getDataStream(passPhrase.toCharArray(), new BouncyCastleProvider()); encryptedData = pbe; currentProgress += 5; } else { - progress.setProgress(R.string.progress_findingKey, currentProgress, 100); + if( progress != null ) + progress.setProgress(R.string.progress_findingKey, currentProgress, 100); PGPPublicKeyEncryptedData pbe = null; PGPSecretKey secretKey = null; Iterator it = enc.getEncryptedDataObjects(); @@ -1731,7 +1763,8 @@ public class Apg { } currentProgress += 5; - progress.setProgress(R.string.progress_extractingKey, currentProgress, 100); + if( progress != null ) + progress.setProgress(R.string.progress_extractingKey, currentProgress, 100); PGPPrivateKey privateKey = null; try { privateKey = secretKey.extractPrivateKey(passPhrase.toCharArray(), @@ -1743,7 +1776,8 @@ public class Apg { throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey)); } currentProgress += 5; - progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100); + if( progress != null ) + progress.setProgress(R.string.progress_preparingStreams, currentProgress, 100); clear = pbe.getDataStream(privateKey, new BouncyCastleProvider()); encryptedData = pbe; currentProgress += 5; @@ -1756,7 +1790,8 @@ public class Apg { int signatureIndex = -1; if (dataChunk instanceof PGPCompressedData) { - progress.setProgress(R.string.progress_decompressingData, currentProgress, 100); + if( progress != null ) + progress.setProgress(R.string.progress_decompressingData, currentProgress, 100); PGPObjectFactory fact = new PGPObjectFactory(((PGPCompressedData) dataChunk).getDataStream()); dataChunk = fact.nextObject(); @@ -1765,7 +1800,8 @@ public class Apg { } if (dataChunk instanceof PGPOnePassSignatureList) { - progress.setProgress(R.string.progress_processingSignature, currentProgress, 100); + if( progress != null ) + progress.setProgress(R.string.progress_processingSignature, currentProgress, 100); returnData.putBoolean(EXTRA_SIGNATURE, true); PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; for (int i = 0; i < sigList.size(); ++i) { @@ -1802,7 +1838,8 @@ public class Apg { } if (dataChunk instanceof PGPLiteralData) { - progress.setProgress(R.string.progress_decrypting, currentProgress, 100); + if( progress != null ) + progress.setProgress(R.string.progress_decrypting, currentProgress, 100); PGPLiteralData literalData = (PGPLiteralData) dataChunk; OutputStream out = outStream; @@ -1838,11 +1875,13 @@ public class Apg { currentProgress = (int)(startProgress + (endProgress - startProgress) * (data.getStreamPosition() - startPos) / (data.getSize() - startPos)); } - progress.setProgress(currentProgress, 100); + if( progress != null ) + progress.setProgress(currentProgress, 100); } if (signature != null) { - progress.setProgress(R.string.progress_verifyingSignature, 90, 100); + if( progress != null ) + progress.setProgress(R.string.progress_verifyingSignature, 90, 100); PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject(); PGPSignature messageSignature = (PGPSignature) signatureList.get(signatureIndex); if (signature.verify(messageSignature)) { @@ -1855,7 +1894,8 @@ public class Apg { // TODO: add integrity somewhere if (encryptedData.isIntegrityProtected()) { - progress.setProgress(R.string.progress_verifyingIntegrity, 95, 100); + if( progress != null ) + progress.setProgress(R.string.progress_verifyingIntegrity, 95, 100); if (encryptedData.verify()) { // passed } else { @@ -1865,7 +1905,8 @@ public class Apg { // no integrity check } - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); return returnData; } @@ -1878,7 +1919,8 @@ public class Apg { ByteArrayOutputStream out = new ByteArrayOutputStream(); ArmoredInputStream aIn = new ArmoredInputStream(data.getInputStream()); - progress.setProgress(R.string.progress_done, 0, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 0, 100); // mostly taken from ClearSignedFileProcessor ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); @@ -1903,7 +1945,8 @@ public class Apg { returnData.putBoolean(EXTRA_SIGNATURE, true); - progress.setProgress(R.string.progress_processingSignature, 60, 100); + if( progress != null ) + progress.setProgress(R.string.progress_processingSignature, 60, 100); PGPObjectFactory pgpFact = new PGPObjectFactory(aIn); PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject(); @@ -1950,7 +1993,8 @@ public class Apg { if (signature == null) { returnData.putBoolean(EXTRA_SIGNATURE_UNKNOWN, true); - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); return returnData; } @@ -1976,7 +2020,8 @@ public class Apg { returnData.putBoolean(EXTRA_SIGNATURE_SUCCESS, signature.verify()); - progress.setProgress(R.string.progress_done, 100, 100); + if( progress != null ) + progress.setProgress(R.string.progress_done, 100, 100); return returnData; } @@ -2234,7 +2279,8 @@ public class Apg { int pos = 0; String msg = context.getString(R.string.progress_deletingSecurely, file.getName()); while (pos < length) { - progress.setProgress(msg, (int)(100 * pos / length), 100); + if( progress != null ) + progress.setProgress(msg, (int)(100 * pos / length), 100); random.nextBytes(data); raf.write(data); pos += data.length; From 455510e0c0e51e9650121472637ffdbb589baf14 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 29 Dec 2010 16:47:55 +0000 Subject: [PATCH 04/69] Fix wrong placed backslash --- res/values-it/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index d1d76f09d..e6f286de5 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -228,7 +228,7 @@ non è stato trovato nessun tipo di crittazione valido la scheda di memoria non è pronta o non è utilizzabile acconto \'%s\' non trovato - accesso in lettura all'\account negato + accesso in lettura all\'account negato non è stato possibile aggiungere l\'acconto \'%s\' mail non valida \'%s\' la dimensione della chiave deve essere almeno di 512bit From ec988efb55165978233118691ec95268f7d30667 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 29 Dec 2010 16:49:27 +0000 Subject: [PATCH 05/69] Remove weird chars at the beginning of xml --- res/values-no/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-no/strings.xml b/res/values-no/strings.xml index 1d372f386..c40f53883 100644 --- a/res/values-no/strings.xml +++ b/res/values-no/strings.xml @@ -1,4 +1,4 @@ -cho + the result at 3. was still having preferences from 1. To work around this, the function getPreferences has been updated to force the new generation of preferences while not breaking any other code relying on the old behaviour. --- src/org/thialfihar/android/apg/Preferences.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/org/thialfihar/android/apg/Preferences.java b/src/org/thialfihar/android/apg/Preferences.java index d22565804..e704d79f3 100644 --- a/src/org/thialfihar/android/apg/Preferences.java +++ b/src/org/thialfihar/android/apg/Preferences.java @@ -12,9 +12,13 @@ public class Preferences { private static Preferences mPreferences; private SharedPreferences mSharedPreferences; - public static synchronized Preferences getPreferences(Context context) + public static synchronized Preferences getPreferences(Context context) { + return getPreferences(context, false); + } + + public static synchronized Preferences getPreferences(Context context, boolean force_new) { - if (mPreferences == null) { + if (mPreferences == null || force_new) { mPreferences = new Preferences(context); } return mPreferences; From 2660c561a171a09c1c6ed2610aea3d0efca23f98 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 30 Dec 2010 13:48:24 +0000 Subject: [PATCH 07/69] Reload preferences on call refs r326 --- src/org/thialfihar/android/apg/ApgService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 6110fe7cd..9cdc5099d 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -21,8 +21,7 @@ public class ApgService extends Service { private final IApgService.Stub mBinder = new IApgService.Stub() { public String encrypt_with_passphrase(String msg, String passphrase) { - Preferences mPreferences = Preferences - .getPreferences(getApplicationContext()); + Preferences mPreferences = Preferences.getPreferences(getBaseContext(), true); InputStream inStream = new ByteArrayInputStream(msg.getBytes()); InputData in = new InputData(inStream, 9999); OutputStream out = new ByteArrayOutputStream(); @@ -41,7 +40,8 @@ public class ApgService extends Service { null, // progress mPreferences.getDefaultEncryptionAlgorithm(), mPreferences.getDefaultHashAlgorithm(), - Id.choice.compression.none, false, // mPreferences.getForceV3Signatures(), + Id.choice.compression.none, // compression + false, // mPreferences.getForceV3Signatures(), passphrase // passPhrase ); } catch (Exception e) { From 6477f6076420b71ad1697aa8db9d453bd2422412 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 4 Jan 2011 23:08:08 +0000 Subject: [PATCH 08/69] Add connection helper for other projects This eases using the AIDL-Interface and is the recommended way for other project to implement the connection. --- .../thialfihar/android/apg/ApgService.java | 31 ++-- .../thialfihar/android/apg/IApgService.aidl | 4 +- .../thialfihar/android/apg/utils/ApgCon.java | 144 ++++++++++++++++++ 3 files changed, 165 insertions(+), 14 deletions(-) create mode 100644 src/org/thialfihar/android/apg/utils/ApgCon.java diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 9cdc5099d..bb5b6463a 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -4,6 +4,10 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import android.content.Intent; import android.os.IBinder; @@ -20,7 +24,10 @@ public class ApgService extends Service { private final IApgService.Stub mBinder = new IApgService.Stub() { - public String encrypt_with_passphrase(String msg, String passphrase) { + public String encrypt_with_passphrase(List args) { + String msg = args.remove(0); + String passphrase = args.remove(0); + Preferences mPreferences = Preferences.getPreferences(getBaseContext(), true); InputStream inStream = new ByteArrayInputStream(msg.getBytes()); InputData in = new InputData(inStream, 9999); @@ -29,17 +36,16 @@ public class ApgService extends Service { Apg.initialize(getApplicationContext()); try { - Apg.encrypt( - getApplicationContext(), - in, - out, + Apg.encrypt(getApplicationContext(), // context + in, // input stream + out, // output stream true, // armored enc_keys, // encryption keys 0, // signature key null, // signature passphrase null, // progress - mPreferences.getDefaultEncryptionAlgorithm(), - mPreferences.getDefaultHashAlgorithm(), + mPreferences.getDefaultEncryptionAlgorithm(), // encryption + mPreferences.getDefaultHashAlgorithm(), // hash Id.choice.compression.none, // compression false, // mPreferences.getForceV3Signatures(), passphrase // passPhrase @@ -53,12 +59,13 @@ public class ApgService extends Service { return out.toString(); } - public String decrypt_with_passphrase(String encrypted_msg, - String passphrase) { - InputStream inStream = new ByteArrayInputStream(encrypted_msg - .getBytes()); + public String decrypt_with_passphrase(List args) { + String encrypted_msg = args.remove(0); + String passphrase = args.remove(0); + + InputStream inStream = new ByteArrayInputStream(encrypted_msg.getBytes()); InputData in = new InputData(inStream, 9999); // XXX what size in - // second parameter? + // second parameter? OutputStream out = new ByteArrayOutputStream(); try { Apg.decrypt(getApplicationContext(), in, out, passphrase, null, // progress diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index 6097d4ce4..65d2653d5 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -1,6 +1,6 @@ package org.thialfihar.android.apg; interface IApgService { - String encrypt_with_passphrase(String msg, String passphrase); - String decrypt_with_passphrase(String encrypted_msg, String passphrase); + String encrypt_with_passphrase(in List params); + String decrypt_with_passphrase(in List params); } \ No newline at end of file diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java new file mode 100644 index 000000000..f6ace207a --- /dev/null +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -0,0 +1,144 @@ +package org.thialfihar.android.apg.utils; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import android.content.Context; +import android.content.ComponentName; +import android.content.ServiceConnection; +import android.content.Intent; +import android.os.IBinder; +import android.util.Log; + +import org.thialfihar.android.apg.IApgService; + +/** + * This class can be used by other projects to simplify connecting to the + * APG-Service. Kind of wrapper of for AIDL. + * + * It is not used in this project. + */ +public class ApgCon { + + private String TAG = "ApgCon"; + + private final Context mContext; + + /** Remote service for decrypting and encrypting data */ + private IApgService apgService = null; + + /** Set apgService accordingly to connection status */ + private ServiceConnection apgConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + Log.d(TAG, "IApgService bound to apgService"); + apgService = IApgService.Stub.asInterface(service); + } + + public void onServiceDisconnected(ComponentName className) { + Log.d(TAG, "IApgService disconnected"); + apgService = null; + } + }; + + /** Possible fields which are returned to the application */ + public static enum retKey { + ERROR, // error enum, see below + ERROR_DESC, // human readable description + RESULT, // if everything went fine, result + } + + public static enum error { + GENERIC, // no special type + CANNOT_BIND_TO_APG, // connection to apg service not possible + CALL_MISSING, // function to call not provided + CALL_NOT_KNOWN, // apg service does not know what to do + } + + public ApgCon(Context ctx) { + Log.d(TAG, "EncryptionService created"); + mContext = ctx; + } + + /** try to connect to the apg service */ + private boolean connect() { + Log.d(TAG, "trying to bind the apgService to context"); + + if (apgService != null) { + Log.d(TAG, "allready connected"); + return true; + } + + try { + mContext.bindService(new Intent(IApgService.class.getName()), apgConnection, Context.BIND_AUTO_CREATE); + } catch (Exception e) { + Log.d(TAG, "could not bind APG service"); + return false; + } + + int wait_count = 0; + while (apgService == null && wait_count++ < 15) { + Log.d(TAG, "sleeping 1 second to wait for apg"); + android.os.SystemClock.sleep(1000); + } + ; + + if (wait_count >= 15) { + Log.d(TAG, "slept waiting for nothing!"); + return false; + } + + return true; + } + + private boolean initialize() { + if (apgService == null) { + if (!connect()) { + Log.d(TAG, "connection to apg service failed"); + return false; + } + } + return true; + } + + public boolean call(String function, Map return_map, String... function_params) { + return_map.put(retKey.ERROR, null); + + if (!initialize()) { + return_map.put(retKey.ERROR, error.CANNOT_BIND_TO_APG); + return false; + } + + if (function == null || function.length() == 0) { + return_map.put(retKey.ERROR, error.CALL_MISSING); + return false; + } + + try { + List params_list = Arrays.asList(function_params); + return_map.put(retKey.RESULT, IApgService.class.getMethod(function, List.class).invoke(apgService, params_list)); + } catch (NoSuchMethodException e) { + Log.d(TAG, e.getMessage()); + return_map.put(retKey.ERROR, error.CALL_NOT_KNOWN); + return_map.put(retKey.ERROR_DESC, e.getMessage()); + return false; + } catch (Exception e) { + Log.d(TAG, e.getMessage()); + return_map.put(retKey.ERROR, error.GENERIC); + return_map.put(retKey.ERROR_DESC, e.getMessage()); + return false; + } + + return true; + + } + + private void disconnect() { + Log.d(TAG, "disconnecting apgService"); + if (apgService != null) { + mContext.unbindService(apgConnection); + apgService = null; + } + } + +} From dbb46f1633b94aa7be39ebb8f4acc24a3420083f Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 4 Jan 2011 23:09:56 +0000 Subject: [PATCH 09/69] Remove forgotten line --- src/org/thialfihar/android/apg/utils/ApgCon.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index f6ace207a..174bce5dc 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -102,7 +102,6 @@ public class ApgCon { } public boolean call(String function, Map return_map, String... function_params) { - return_map.put(retKey.ERROR, null); if (!initialize()) { return_map.put(retKey.ERROR, error.CANNOT_BIND_TO_APG); From 1a338de47e7d9faa73a3bc6eda51cb47a18dc91b Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 5 Jan 2011 14:07:09 +0000 Subject: [PATCH 10/69] Redesign AIDL-Interface once more Using Bundles makes passing data easier and does not need to redefine the interface if the internel functions change. The helper class has been updated accordingly. In addition, it wrappes completely around all input and output (if wanted). --- .../thialfihar/android/apg/ApgService.java | 103 +++++++++++++++--- .../thialfihar/android/apg/IApgService.aidl | 33 +++++- .../thialfihar/android/apg/utils/ApgCon.java | 81 ++++++++++---- 3 files changed, 179 insertions(+), 38 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index bb5b6463a..316e9a22c 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -4,12 +4,11 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.ArrayList; +import java.util.Iterator; import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; import android.util.Log; @@ -22,11 +21,45 @@ public class ApgService extends Service { return mBinder; } + private enum error { + ARGUMENTS_MISSING, + APG_FAILURE + } + private final IApgService.Stub mBinder = new IApgService.Stub() { - public String encrypt_with_passphrase(List args) { - String msg = args.remove(0); - String passphrase = args.remove(0); + public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { + ArrayList errors = new ArrayList(); + ArrayList warnings = new ArrayList(); + + pReturn.putStringArrayList("ERRORS", errors); + pReturn.putStringArrayList("WARNINGS", warnings); + + String msg = pArgs.getString("MSG"); + pArgs.remove("MSG"); + + String passphrase = pArgs.getString("SYM_KEY"); + pArgs.remove("SYM_KEY"); + + if (msg == null) { + errors.add("Message to encrypt (MSG) missing"); + } + + if (passphrase == null) { + errors.add("Symmetric key (SYM_KEY) missing"); + } + + if (!pArgs.isEmpty()) { + Iterator iter = pArgs.keySet().iterator(); + while (iter.hasNext()) { + warnings.add("Unknown key: " + iter.next()); + } + } + + if (errors.size() != 0) { + pReturn.putInt("ERROR", error.ARGUMENTS_MISSING.ordinal()); + return false; + } Preferences mPreferences = Preferences.getPreferences(getBaseContext(), true); InputStream inStream = new ByteArrayInputStream(msg.getBytes()); @@ -52,16 +85,50 @@ public class ApgService extends Service { ); } catch (Exception e) { Log.d(TAG, "Exception in encrypt"); - e.printStackTrace(); - return null; + errors.add("Internal failure in APG when encrypting: " + e.getMessage()); + + pReturn.putInt("ERROR", error.APG_FAILURE.ordinal()); + return false; } + Log.d(TAG, "Encrypted"); - return out.toString(); + pReturn.putString("RESULT", out.toString()); + return true; } - public String decrypt_with_passphrase(List args) { - String encrypted_msg = args.remove(0); - String passphrase = args.remove(0); + public boolean decrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { + ArrayList errors = new ArrayList(); + ArrayList warnings = new ArrayList(); + + pReturn.putStringArrayList("ERRORS", errors); + pReturn.putStringArrayList("WARNINGS", warnings); + + String encrypted_msg = pArgs.getString("MSG"); + pArgs.remove("MSG"); + + String passphrase = pArgs.getString("SYM_KEY"); + pArgs.remove("SYM_KEY"); + + if (encrypted_msg == null) { + errors.add("Message to decrypt (MSG) missing"); + } + + if (passphrase == null) { + errors.add("Symmetric key (SYM_KEY) missing"); + } + + if (!pArgs.isEmpty()) { + Iterator iter = pArgs.keySet().iterator(); + while (iter.hasNext()) { + warnings.add("Unknown key: " + iter.next()); + } + } + + if (errors.size() != 0) { + pReturn.putStringArrayList("ERROR", errors); + pReturn.putInt("ERROR", error.ARGUMENTS_MISSING.ordinal()); + return false; + } InputStream inStream = new ByteArrayInputStream(encrypted_msg.getBytes()); InputData in = new InputData(inStream, 9999); // XXX what size in @@ -73,11 +140,15 @@ public class ApgService extends Service { ); } catch (Exception e) { Log.d(TAG, "Exception in decrypt"); - e.printStackTrace(); - return null; + errors.add("Internal failure in APG when decrypting: " + e.getMessage()); + + pReturn.putInt("ERROR", error.APG_FAILURE.ordinal()); + pReturn.putStringArrayList("ERROR", errors); + return false; } - return out.toString(); + pReturn.putString("RESULT", out.toString()); + return true; } }; } diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index 65d2653d5..f31265f8e 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -1,6 +1,35 @@ package org.thialfihar.android.apg; interface IApgService { - String encrypt_with_passphrase(in List params); - String decrypt_with_passphrase(in List params); + + /** All functions fill the return_vals Bundle with the following keys: + * + * ArrayList "WARNINGS" = Warnings, if any + * ArrayList "ERRORS" = Human readable error descriptions, why function call failed + * int "ERROR" = Numeric representation of error + */ + + /** Encrypt something with a symmetric key + * + * Bundle params: + * (optional/required) TYPE "STRING KEY" = EXPLANATION + * + * (required) String "MSG" = Message to encrypt + * (required) String "SYM_KEY" = Symmetric key to use + * + * Bundle return_vals (in addition to the ERRORS/WARNINGS above): + * String "RESULT" = Encrypted MSG + */ + boolean encrypt_with_passphrase(in Bundle params, out Bundle return_vals); + + /** Decrypt something with a symmetric key + * + * Bundle params: + * (required) String "MSG" = Message to decrypt + * (required) String "SYM_KEY" = Symmetric key to use + * + * Bundle return_vals: + * String "RESULT" = Decrypted MSG + */ + boolean decrypt_with_passphrase(in Bundle params, out Bundle return_vals); } \ No newline at end of file diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 174bce5dc..6234e1b88 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -1,14 +1,14 @@ package org.thialfihar.android.apg.utils; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.ArrayList; import android.content.Context; import android.content.ComponentName; import android.content.ServiceConnection; import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; +import android.os.Parcelable; import android.util.Log; import org.thialfihar.android.apg.IApgService; @@ -25,6 +25,11 @@ public class ApgCon { private final Context mContext; + private Bundle result = new Bundle(); + private Bundle args = new Bundle(); + private ArrayList error_list = new ArrayList(); + private ArrayList warning_list = new ArrayList(); + /** Remote service for decrypting and encrypting data */ private IApgService apgService = null; @@ -41,13 +46,6 @@ public class ApgCon { } }; - /** Possible fields which are returned to the application */ - public static enum retKey { - ERROR, // error enum, see below - ERROR_DESC, // human readable description - RESULT, // if everything went fine, result - } - public static enum error { GENERIC, // no special type CANNOT_BIND_TO_APG, // connection to apg service not possible @@ -101,35 +99,78 @@ public class ApgCon { return true; } - public boolean call(String function, Map return_map, String... function_params) { + public boolean call(String function) { + return this.call(function, args, result); + } + + public boolean call(String function, Bundle pArgs) { + return this.call(function, pArgs, result); + } + + public boolean call(String function, Bundle pArgs, Bundle pReturn) { if (!initialize()) { - return_map.put(retKey.ERROR, error.CANNOT_BIND_TO_APG); + error_list.add("CLASS: Cannot bind to ApgService"); + pReturn.putInt("CLASS_ERROR", error.CANNOT_BIND_TO_APG.ordinal()); return false; } if (function == null || function.length() == 0) { - return_map.put(retKey.ERROR, error.CALL_MISSING); + error_list.add("CLASS: Function to call missing"); + pReturn.putInt("CLASS_ERROR", error.CALL_MISSING.ordinal()); return false; } try { - List params_list = Arrays.asList(function_params); - return_map.put(retKey.RESULT, IApgService.class.getMethod(function, List.class).invoke(apgService, params_list)); + Boolean ret = (Boolean) IApgService.class.getMethod(function, Bundle.class, Bundle.class).invoke(apgService, pArgs, pReturn); + error_list = new ArrayList(pReturn.getStringArrayList("ERRORS")); + warning_list = new ArrayList(pReturn.getStringArrayList("WARNINGS")); + return ret; } catch (NoSuchMethodException e) { Log.d(TAG, e.getMessage()); - return_map.put(retKey.ERROR, error.CALL_NOT_KNOWN); - return_map.put(retKey.ERROR_DESC, e.getMessage()); + error_list.add("CLASS: " + e.getMessage()); + pReturn.putInt("CLASS_ERROR", error.CALL_NOT_KNOWN.ordinal()); return false; } catch (Exception e) { Log.d(TAG, e.getMessage()); - return_map.put(retKey.ERROR, error.GENERIC); - return_map.put(retKey.ERROR_DESC, e.getMessage()); + error_list.add("CLASS: " + e.getMessage()); + pReturn.putInt("CLASS_ERROR", error.GENERIC.ordinal()); return false; } - return true; + } + public void set_arg(String key, String val) { + args.putString(key, val); + } + + public void set_arg(String key, boolean val) { + args.putBoolean(key, val); + } + + public Object get_arg(String key) { + return args.get(key); + } + + public String get_next_error() { + String bla = "abc"; + return error_list.remove(0); + } + + public boolean has_next_error() { + return error_list.size() != 0; + } + + public String get_next_warning() { + return warning_list.remove(0); + } + + public boolean has_next_warning() { + return warning_list.size() != 0; + } + + public String get_result() { + return result.getString("RESULT"); } private void disconnect() { From b1e8194ce24377528d1f36e578bb2e80e0051239 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 17:17:08 +0000 Subject: [PATCH 11/69] Remove weird line --- src/org/thialfihar/android/apg/utils/ApgCon.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 6234e1b88..6aadcefff 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -153,7 +153,6 @@ public class ApgCon { } public String get_next_error() { - String bla = "abc"; return error_list.remove(0); } From 91da2dd2ea59463d5502febf0909f2e64bf519df Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 17:17:18 +0000 Subject: [PATCH 12/69] Remove obsolete import --- src/org/thialfihar/android/apg/utils/ApgCon.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 6aadcefff..a93103581 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -8,7 +8,6 @@ import android.content.ServiceConnection; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; -import android.os.Parcelable; import android.util.Log; import org.thialfihar.android.apg.IApgService; From a29dfc0addb5b2eac07e29633f044c4690559f1a Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 17:17:27 +0000 Subject: [PATCH 13/69] Reset errors before calling, make some vars final, minor cleanups --- .../thialfihar/android/apg/utils/ApgCon.java | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index a93103581..9e8fd2381 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -20,14 +20,14 @@ import org.thialfihar.android.apg.IApgService; */ public class ApgCon { - private String TAG = "ApgCon"; + private final static String TAG = "ApgCon"; private final Context mContext; - private Bundle result = new Bundle(); - private Bundle args = new Bundle(); - private ArrayList error_list = new ArrayList(); - private ArrayList warning_list = new ArrayList(); + private final Bundle result = new Bundle(); + private final Bundle args = new Bundle(); + private final ArrayList error_list = new ArrayList(); + private final ArrayList warning_list = new ArrayList(); /** Remote service for decrypting and encrypting data */ private IApgService apgService = null; @@ -108,6 +108,9 @@ public class ApgCon { public boolean call(String function, Bundle pArgs, Bundle pReturn) { + error_list.clear(); + warning_list.clear(); + if (!initialize()) { error_list.add("CLASS: Cannot bind to ApgService"); pReturn.putInt("CLASS_ERROR", error.CANNOT_BIND_TO_APG.ordinal()); @@ -122,8 +125,8 @@ public class ApgCon { try { Boolean ret = (Boolean) IApgService.class.getMethod(function, Bundle.class, Bundle.class).invoke(apgService, pArgs, pReturn); - error_list = new ArrayList(pReturn.getStringArrayList("ERRORS")); - warning_list = new ArrayList(pReturn.getStringArrayList("WARNINGS")); + error_list.addAll(pReturn.getStringArrayList("ERRORS")); + warning_list.addAll(pReturn.getStringArrayList("WARNINGS")); return ret; } catch (NoSuchMethodException e) { Log.d(TAG, e.getMessage()); @@ -142,7 +145,7 @@ public class ApgCon { public void set_arg(String key, String val) { args.putString(key, val); } - + public void set_arg(String key, boolean val) { args.putBoolean(key, val); } @@ -152,7 +155,10 @@ public class ApgCon { } public String get_next_error() { - return error_list.remove(0); + if (error_list.size() != 0) + return error_list.remove(0); + else + return null; } public boolean has_next_error() { @@ -160,7 +166,10 @@ public class ApgCon { } public String get_next_warning() { - return warning_list.remove(0); + if (warning_list.size() != 0) + return warning_list.remove(0); + else + return null; } public boolean has_next_warning() { From 9e089f03b6efb656650be7fa465833f189398af5 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 19:16:22 +0000 Subject: [PATCH 14/69] Prefix local vars with "_" --- .../thialfihar/android/apg/ApgService.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 316e9a22c..ec744448b 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -50,9 +50,9 @@ public class ApgService extends Service { } if (!pArgs.isEmpty()) { - Iterator iter = pArgs.keySet().iterator(); - while (iter.hasNext()) { - warnings.add("Unknown key: " + iter.next()); + Iterator _iter = pArgs.keySet().iterator(); + while (_iter.hasNext()) { + warnings.add("Unknown key: " + _iter.next()); } } @@ -61,24 +61,24 @@ public class ApgService extends Service { return false; } - Preferences mPreferences = Preferences.getPreferences(getBaseContext(), true); - InputStream inStream = new ByteArrayInputStream(msg.getBytes()); - InputData in = new InputData(inStream, 9999); - OutputStream out = new ByteArrayOutputStream(); - long enc_keys[] = {}; + Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true); + InputStream _inStream = new ByteArrayInputStream(msg.getBytes()); + InputData _in = new InputData(_inStream, 9999); + OutputStream _out = new ByteArrayOutputStream(); + long _enc_keys[] = {}; Apg.initialize(getApplicationContext()); try { Apg.encrypt(getApplicationContext(), // context - in, // input stream - out, // output stream + _in, // input stream + _out, // output stream true, // armored - enc_keys, // encryption keys + _enc_keys, // encryption keys 0, // signature key null, // signature passphrase null, // progress - mPreferences.getDefaultEncryptionAlgorithm(), // encryption - mPreferences.getDefaultHashAlgorithm(), // hash + _mPreferences.getDefaultEncryptionAlgorithm(), // encryption + _mPreferences.getDefaultHashAlgorithm(), // hash Id.choice.compression.none, // compression false, // mPreferences.getForceV3Signatures(), passphrase // passPhrase @@ -92,7 +92,7 @@ public class ApgService extends Service { } Log.d(TAG, "Encrypted"); - pReturn.putString("RESULT", out.toString()); + pReturn.putString("RESULT", _out.toString()); return true; } @@ -105,7 +105,7 @@ public class ApgService extends Service { String encrypted_msg = pArgs.getString("MSG"); pArgs.remove("MSG"); - + String passphrase = pArgs.getString("SYM_KEY"); pArgs.remove("SYM_KEY"); From c84c449035db1498414486b13e63e590ddf49a58 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 19:16:45 +0000 Subject: [PATCH 15/69] Respect options but allow to overwrite them for each call By default the values set in APG's options are respected now. But they can be overwritten by special parameters passed through. --- .../thialfihar/android/apg/ApgService.java | 99 ++++++++++++++++--- 1 file changed, 84 insertions(+), 15 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index ec744448b..4d38f9693 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import android.content.Intent; @@ -13,7 +14,7 @@ import android.os.IBinder; import android.util.Log; public class ApgService extends Service { - static String TAG = "ApgService"; + final static String TAG = "ApgService"; @Override public IBinder onBind(Intent intent) { @@ -26,21 +27,89 @@ public class ApgService extends Service { APG_FAILURE } + /** a map from ApgService parameters to function calls to get the default */ + static final HashMap FUNCTIONS_DEFAULTS = new HashMap(); + 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"); + } + + /** + * Add default arguments if missing + * + * @param args + * the bundle to add default parameters to if missing + * + */ + private void add_defaults(Bundle args) { + Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true); + + Iterator _iter = FUNCTIONS_DEFAULTS.keySet().iterator(); + while (_iter.hasNext()) { + String _current_key = _iter.next(); + if (!args.containsKey(_current_key)) { + String _current_function_name = FUNCTIONS_DEFAULTS.get(_current_key); + try { + @SuppressWarnings("unchecked") + Class _ret_type = Preferences.class.getMethod(_current_function_name).getReturnType(); + if (_ret_type == String.class) { + args.putString(_current_key, (String) Preferences.class.getMethod(_current_function_name).invoke(_mPreferences)); + } else if (_ret_type == boolean.class) { + args.putBoolean(_current_key, (Boolean) Preferences.class.getMethod(_current_function_name).invoke(_mPreferences)); + } else if (_ret_type == int.class) { + args.putInt(_current_key, (Integer) Preferences.class.getMethod(_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_defaults " + e.getMessage()); + } + } + } + } + private final IApgService.Stub mBinder = new IApgService.Stub() { public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { + ArrayList errors = new ArrayList(); ArrayList warnings = new ArrayList(); pReturn.putStringArrayList("ERRORS", errors); pReturn.putStringArrayList("WARNINGS", warnings); - String msg = pArgs.getString("MSG"); - pArgs.remove("MSG"); + Bundle _my_args = new Bundle(pArgs); - String passphrase = pArgs.getString("SYM_KEY"); - pArgs.remove("SYM_KEY"); + /* add default values if missing */ + add_defaults(_my_args); + /* required args */ + String msg = _my_args.getString("MSG"); + _my_args.remove("MSG"); + + String passphrase = _my_args.getString("SYM_KEY"); + _my_args.remove("SYM_KEY"); + + /* optional args */ + Boolean armored = _my_args.getBoolean("ARMORED"); + _my_args.remove("ARMORED"); + + int encryption_algorithm = _my_args.getInt("ENCRYPTION_ALGO"); + _my_args.remove("ENCRYPTION_ALGO"); + + int hash_algorithm = _my_args.getInt("HASH_ALGO"); + _my_args.remove("HASH_ALGO"); + + int compression = _my_args.getInt("COMPRESSION"); + _my_args.remove("COMPRESSION"); + + Boolean force_v3_signatures = _my_args.getBoolean("FORCE_V3_SIG"); + _my_args.remove("FORCE_V3_SIG"); + + /* check required args */ if (msg == null) { errors.add("Message to encrypt (MSG) missing"); } @@ -49,38 +118,38 @@ public class ApgService extends Service { errors.add("Symmetric key (SYM_KEY) missing"); } - if (!pArgs.isEmpty()) { - Iterator _iter = pArgs.keySet().iterator(); + /* check for unknown args and add to warning */ + if (!_my_args.isEmpty()) { + Iterator _iter = _my_args.keySet().iterator(); while (_iter.hasNext()) { warnings.add("Unknown key: " + _iter.next()); } } + /* return if errors happened */ if (errors.size() != 0) { pReturn.putInt("ERROR", error.ARGUMENTS_MISSING.ordinal()); return false; } - Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true); InputStream _inStream = new ByteArrayInputStream(msg.getBytes()); InputData _in = new InputData(_inStream, 9999); OutputStream _out = new ByteArrayOutputStream(); - long _enc_keys[] = {}; Apg.initialize(getApplicationContext()); try { Apg.encrypt(getApplicationContext(), // context _in, // input stream _out, // output stream - true, // armored - _enc_keys, // encryption keys + armored, // armored + new long[0], // encryption keys 0, // signature key null, // signature passphrase null, // progress - _mPreferences.getDefaultEncryptionAlgorithm(), // encryption - _mPreferences.getDefaultHashAlgorithm(), // hash - Id.choice.compression.none, // compression - false, // mPreferences.getForceV3Signatures(), + encryption_algorithm, // encryption + hash_algorithm, // hash + compression, // compression + force_v3_signatures, // mPreferences.getForceV3Signatures(), passphrase // passPhrase ); } catch (Exception e) { From def11ad18f0394adaf61c0cf53647f5583e5b8b6 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 19:16:54 +0000 Subject: [PATCH 16/69] Document new args in AIDL --- src/org/thialfihar/android/apg/IApgService.aidl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index f31265f8e..2c7ffb875 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -14,11 +14,16 @@ interface IApgService { * Bundle params: * (optional/required) TYPE "STRING KEY" = EXPLANATION * - * (required) String "MSG" = Message to encrypt - * (required) String "SYM_KEY" = Symmetric key to use + * (required) String "MSG" = Message to encrypt + * (required) String "SYM_KEY" = Symmetric key to use + * (optional) int "ENCRYPTION_ALGO" = Encryption Algorithm + * (optional) int "HASH_ALGO" = Hash Algorithm + * (optional) Boolean "ARMORED" = Armor output + * (optional) Boolean "FORCE_V3_SIG" = Force V3 Signatures + * (optional) int "COMPRESSION" = Compression to use * * Bundle return_vals (in addition to the ERRORS/WARNINGS above): - * String "RESULT" = Encrypted MSG + * String "RESULT" = Encrypted MSG */ boolean encrypt_with_passphrase(in Bundle params, out Bundle return_vals); From 3f0c80882e39881d6c93596ce498e50144836eae Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 20:12:03 +0000 Subject: [PATCH 17/69] Explain AIDL options a little bit more in detail --- src/org/thialfihar/android/apg/IApgService.aidl | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index 2c7ffb875..2bd3f8dcf 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -11,16 +11,24 @@ interface IApgService { /** Encrypt something with a symmetric key * - * Bundle params: - * (optional/required) TYPE "STRING KEY" = EXPLANATION + * Bundle params' keys: + * (optional/required) TYPE "STRING KEY" = EXPLANATION / VALUES * * (required) String "MSG" = Message to encrypt * (required) String "SYM_KEY" = Symmetric key to use * (optional) int "ENCRYPTION_ALGO" = 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_ALGO" = 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" = Armor output * (optional) Boolean "FORCE_V3_SIG" = Force V3 Signatures * (optional) int "COMPRESSION" = Compression to use + 0x21070001: none, 1: Zip, 2: Zlib, + 3: BZip2 * * Bundle return_vals (in addition to the ERRORS/WARNINGS above): * String "RESULT" = Encrypted MSG From 51b63d099c6794b01ae8cbdbdd56c9fe673e4e8a Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 20:12:12 +0000 Subject: [PATCH 18/69] Allow helper to clear args and set booleans --- src/org/thialfihar/android/apg/utils/ApgCon.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 9e8fd2381..959e38ac2 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -149,6 +149,14 @@ public class ApgCon { public void set_arg(String key, boolean val) { args.putBoolean(key, val); } + + public void set_arg(String key, int val) { + args.putInt(key, val); + } + + public void clear_args() { + args.clear(); + } public Object get_arg(String key) { return args.get(key); From d367bc12f833bed8082c99936e0ac5b86a95faf7 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 11 Jan 2011 17:58:13 +0000 Subject: [PATCH 19/69] Make some things static *Should* speed up encryption, or better: does not make encryption using AIDL slower than using APG directly. --- .../thialfihar/android/apg/ApgService.java | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 4d38f9693..717383b98 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -37,6 +38,34 @@ public class ApgService extends Service { FUNCTIONS_DEFAULTS.put("COMPRESSION", "getDefaultMessageCompression"); } + /** a map the default functions to their return types */ + static final HashMap FUNCTIONS_DEFAULTS_TYPES = new HashMap(); + 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 */ + static final HashMap FUNCTIONS_DEFAULTS_METHODS = new HashMap(); + 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()); + } + } + /** * Add default arguments if missing * @@ -54,13 +83,13 @@ public class ApgService extends Service { String _current_function_name = FUNCTIONS_DEFAULTS.get(_current_key); try { @SuppressWarnings("unchecked") - Class _ret_type = Preferences.class.getMethod(_current_function_name).getReturnType(); + Class _ret_type = FUNCTIONS_DEFAULTS_TYPES.get(_current_function_name); if (_ret_type == String.class) { - args.putString(_current_key, (String) Preferences.class.getMethod(_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) { - args.putBoolean(_current_key, (Boolean) Preferences.class.getMethod(_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) { - args.putInt(_current_key, (Integer) Preferences.class.getMethod(_current_function_name).invoke(_mPreferences)); + 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"); } @@ -133,7 +162,8 @@ public class ApgService extends Service { } InputStream _inStream = new ByteArrayInputStream(msg.getBytes()); - InputData _in = new InputData(_inStream, 9999); + InputData _in = new InputData(_inStream, 0); // XXX Size second + // param? OutputStream _out = new ByteArrayOutputStream(); Apg.initialize(getApplicationContext()); @@ -200,7 +230,7 @@ public class ApgService extends Service { } InputStream inStream = new ByteArrayInputStream(encrypted_msg.getBytes()); - InputData in = new InputData(inStream, 9999); // XXX what size in + InputData in = new InputData(inStream, 0); // XXX what size in // second parameter? OutputStream out = new ByteArrayOutputStream(); try { From fc05dfd8b7260ed042a4c78f66256d775bd6e9d2 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 11 Jan 2011 22:24:08 +0000 Subject: [PATCH 20/69] Prevent null pointer exception Error-msg should be better, though. --- src/org/thialfihar/android/apg/utils/ApgCon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 959e38ac2..6b74dca0a 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -134,7 +134,7 @@ public class ApgCon { pReturn.putInt("CLASS_ERROR", error.CALL_NOT_KNOWN.ordinal()); return false; } catch (Exception e) { - Log.d(TAG, e.getMessage()); + Log.d(TAG, ""+e.getMessage()); error_list.add("CLASS: " + e.getMessage()); pReturn.putInt("CLASS_ERROR", error.GENERIC.ordinal()); return false; From 45e4897dc7f05f1f270f4993cc3060f654e2f3a9 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 11 Jan 2011 22:24:20 +0000 Subject: [PATCH 21/69] Redefine many internals of ApgService This helps to add new function calls easily. Some of the new enums could be exported to other files to be included by other projects later on. Next step is asymmetric encryption. --- .../thialfihar/android/apg/ApgService.java | 280 +++++++++++------- 1 file changed, 173 insertions(+), 107 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 } - /** a map from ApgService parameters to function calls to get the default */ - static final HashMap FUNCTIONS_DEFAULTS = new HashMap(); + /** 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> FUNCTIONS_REQUIRED_ARGS = new HashMap>(); 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"); + HashSet args = new HashSet(); + 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(); + 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> FUNCTIONS_OPTIONAL_ARGS = new HashMap>(); + static { + HashSet args = new HashSet(); + 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 */ + private static final HashMap FUNCTIONS_DEFAULTS = new HashMap(); + static { + 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 FUNCTIONS_DEFAULTS_TYPES = new HashMap(); + private static final HashMap> FUNCTIONS_DEFAULTS_TYPES = new HashMap>(); 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 FUNCTIONS_DEFAULTS_METHODS = new HashMap(); + private static final HashMap FUNCTIONS_DEFAULTS_METHODS = new HashMap(); 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 _iter = FUNCTIONS_DEFAULTS.keySet().iterator(); + Iterator _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()); } } } } + /** + * updates a Bundle with default return values + * + * @param pReturn + * the Bundle to update + */ + private void add_default_returns(Bundle pReturn) { + ArrayList errors = new ArrayList(); + ArrayList warnings = new ArrayList(); + + 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 check_required_args(String function, Bundle pArgs, Bundle pReturn) { + Iterator _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); + } + } + } + + /** + * 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 all_args = new HashSet(FUNCTIONS_REQUIRED_ARGS.get(function)); + all_args.addAll(FUNCTIONS_OPTIONAL_ARGS.get(function)); + + Iterator _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); + } + + } + } + private final IApgService.Stub mBinder = new IApgService.Stub() { public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { + /* add default return values for all functions */ + add_default_returns(pReturn); - ArrayList errors = new ArrayList(); - ArrayList warnings = new ArrayList(); + /* add default arguments if missing */ + add_default_arguments(pArgs); + Log.d(TAG, "add_default_arguments"); - pReturn.putStringArrayList("ERRORS", errors); - pReturn.putStringArrayList("WARNINGS", warnings); + /* check for required arguments */ + check_required_args("encrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_required_args"); - Bundle _my_args = new Bundle(pArgs); - - /* add default values if missing */ - add_defaults(_my_args); - - /* required args */ - String msg = _my_args.getString("MSG"); - _my_args.remove("MSG"); - - String passphrase = _my_args.getString("SYM_KEY"); - _my_args.remove("SYM_KEY"); - - /* optional args */ - Boolean armored = _my_args.getBoolean("ARMORED"); - _my_args.remove("ARMORED"); - - int encryption_algorithm = _my_args.getInt("ENCRYPTION_ALGO"); - _my_args.remove("ENCRYPTION_ALGO"); - - int hash_algorithm = _my_args.getInt("HASH_ALGO"); - _my_args.remove("HASH_ALGO"); - - int compression = _my_args.getInt("COMPRESSION"); - _my_args.remove("COMPRESSION"); - - Boolean force_v3_signatures = _my_args.getBoolean("FORCE_V3_SIG"); - _my_args.remove("FORCE_V3_SIG"); - - /* check required args */ - if (msg == null) { - errors.add("Message to encrypt (MSG) missing"); - } - - if (passphrase == null) { - errors.add("Symmetric key (SYM_KEY) missing"); - } - - /* check for unknown args and add to warning */ - if (!_my_args.isEmpty()) { - Iterator _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 errors = new ArrayList(); - ArrayList warnings = new ArrayList(); + /* add default return values for all functions */ + add_default_returns(pReturn); - pReturn.putStringArrayList("ERRORS", errors); - pReturn.putStringArrayList("WARNINGS", warnings); + /* add default arguments if missing */ + add_default_arguments(pArgs); + Log.d(TAG, "add_default_arguments"); - String encrypted_msg = pArgs.getString("MSG"); - pArgs.remove("MSG"); - String passphrase = pArgs.getString("SYM_KEY"); - pArgs.remove("SYM_KEY"); + /* check required args */ + check_required_args("decrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_required_args"); - if (encrypted_msg == null) { - errors.add("Message to decrypt (MSG) missing"); - } - if (passphrase == null) { - errors.add("Symmetric key (SYM_KEY) missing"); - } + /* check for unknown args and add to warning */ + check_unknown_args("decrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_unknown_args"); - if (!pArgs.isEmpty()) { - Iterator iter = pArgs.keySet().iterator(); - while (iter.hasNext()) { - warnings.add("Unknown key: " + iter.next()); - } - } - - 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; } }; From 8b352296503b555bc8d7e0fa7fff2f66ad5a8701 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 11 Jan 2011 22:31:35 +0000 Subject: [PATCH 22/69] Actually check for unknown args for function --- src/org/thialfihar/android/apg/ApgService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index ff2fb8ad8..a298cca8e 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -205,7 +205,10 @@ public class ApgService extends Service { while (_iter.hasNext()) { String _cur_key = _iter.next(); try { - arg.valueOf(_cur_key); + arg _cur_arg = arg.valueOf(_cur_key); + if( !all_args.contains(_cur_arg)) { + pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key); + } } catch (Exception e) { pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key); } From 9c06bb03b66c80742715935e7aacb6b519c87f51 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 13 Jan 2011 20:12:02 +0000 Subject: [PATCH 23/69] Prepare ApgCon for asymetric enc and clean up --- .../thialfihar/android/apg/utils/ApgCon.java | 57 ++++++++++++++----- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 6b74dca0a..0ad92fcbb 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -53,35 +53,34 @@ public class ApgCon { } public ApgCon(Context ctx) { - Log.d(TAG, "EncryptionService created"); + Log.v(TAG, "EncryptionService created"); mContext = ctx; } /** try to connect to the apg service */ private boolean connect() { - Log.d(TAG, "trying to bind the apgService to context"); + Log.v(TAG, "trying to bind the apgService to context"); if (apgService != null) { - Log.d(TAG, "allready connected"); + Log.v(TAG, "allready connected"); return true; } try { mContext.bindService(new Intent(IApgService.class.getName()), apgConnection, Context.BIND_AUTO_CREATE); } catch (Exception e) { - Log.d(TAG, "could not bind APG service"); + Log.v(TAG, "could not bind APG service"); return false; } int wait_count = 0; while (apgService == null && wait_count++ < 15) { - Log.d(TAG, "sleeping 1 second to wait for apg"); + Log.v(TAG, "sleeping 1 second to wait for apg"); android.os.SystemClock.sleep(1000); } - ; if (wait_count >= 15) { - Log.d(TAG, "slept waiting for nothing!"); + Log.v(TAG, "slept waiting for nothing!"); return false; } @@ -91,7 +90,7 @@ public class ApgCon { private boolean initialize() { if (apgService == null) { if (!connect()) { - Log.d(TAG, "connection to apg service failed"); + Log.v(TAG, "connection to apg service failed"); return false; } } @@ -129,12 +128,12 @@ public class ApgCon { warning_list.addAll(pReturn.getStringArrayList("WARNINGS")); return ret; } catch (NoSuchMethodException e) { - Log.d(TAG, e.getMessage()); + Log.e(TAG, e.getMessage()); error_list.add("CLASS: " + e.getMessage()); pReturn.putInt("CLASS_ERROR", error.CALL_NOT_KNOWN.ordinal()); return false; } catch (Exception e) { - Log.d(TAG, ""+e.getMessage()); + Log.e(TAG, "" + e.getMessage()); error_list.add("CLASS: " + e.getMessage()); pReturn.putInt("CLASS_ERROR", error.GENERIC.ordinal()); return false; @@ -146,14 +145,30 @@ public class ApgCon { args.putString(key, val); } + public void set_arg(String key, String vals[]) { + ArrayList list = new ArrayList(); + for (String val : vals) { + list.add(val); + } + args.putStringArrayList(key, list); + } + public void set_arg(String key, boolean val) { args.putBoolean(key, val); } - + public void set_arg(String key, int val) { args.putInt(key, val); } - + + public void set_arg(String key, int vals[]) { + ArrayList list = new ArrayList(); + for (int val : vals) { + list.add(val); + } + args.putIntegerArrayList(key, list); + } + public void clear_args() { args.clear(); } @@ -188,8 +203,22 @@ public class ApgCon { return result.getString("RESULT"); } - private void disconnect() { - Log.d(TAG, "disconnecting apgService"); + public void clear_errors() { + error_list.clear(); + } + + public void clear_warnings() { + warning_list.clear(); + } + + public void reset() { + clear_errors(); + clear_warnings(); + clear_args(); + } + + public void disconnect() { + Log.v(TAG, "disconnecting apgService"); if (apgService != null) { mContext.unbindService(apgConnection); apgService = null; From a1c75dd47ce4a72f516366b24c9e00d270a187b6 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 13 Jan 2011 20:12:10 +0000 Subject: [PATCH 24/69] Add asymmetric encryption --- .../thialfihar/android/apg/ApgService.java | 264 ++++++++++++------ .../thialfihar/android/apg/IApgService.aidl | 20 +- 2 files changed, 194 insertions(+), 90 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index a298cca8e..796a42913 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -6,12 +6,19 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import org.thialfihar.android.apg.provider.KeyRings; +import org.thialfihar.android.apg.provider.Keys; +import org.thialfihar.android.apg.provider.UserIds; + import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteQueryBuilder; import android.os.Bundle; import android.os.IBinder; import android.util.Log; @@ -28,7 +35,8 @@ public class ApgService extends Service { /** error status */ private enum error { ARGUMENTS_MISSING, - APG_FAILURE + APG_FAILURE, + NO_MATCHING_SECRET_KEY } /** all arguments that can be passed by calling application */ @@ -46,10 +54,11 @@ public class ApgService extends Service { /** all things that might be returned */ private enum ret { - ERRORS, - WARNINGS, - ERROR, + ERRORS, // string array list with errors + WARNINGS, // string array list with warnings + ERROR, // numeric error RESULT + // en-/decrypted test } /** required arguments for each AIDL function */ @@ -59,12 +68,16 @@ public class ApgService extends Service { 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(); args.add(arg.PUBLIC_KEYS); args.add(arg.MSG); FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_public_key", args); + + args = new HashSet(); + args.add(arg.MSG); + FUNCTIONS_REQUIRED_ARGS.put("decrypt", args); + } /** optional arguments for each AIDL function */ @@ -78,7 +91,11 @@ public class ApgService extends Service { 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); + + args = new HashSet(); + args.add(arg.SYM_KEY); + args.add(arg.PUBLIC_KEYS); + FUNCTIONS_OPTIONAL_ARGS.put("decrypt", args); } /** a map from ApgService parameters to function calls to get the default */ @@ -119,6 +136,56 @@ public class ApgService extends Service { } } + /** + * 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[] get_master_key(ArrayList search_keys) { + + 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 = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC"; + + long now = new Date().getTime() / 1000; + Cursor mCursor = qb.query(Apg.getDatabase().db(), new String[] { + KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0 + KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1 + UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2 + "(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " + "tmp." + Keys.KEY_RING_ID + " = " + KeyRings.TABLE_NAME + + "." + KeyRings._ID + " AND " + "tmp." + Keys.IS_REVOKED + " = '0' AND " + "tmp." + Keys.CAN_ENCRYPT + " = '1')", // 3 + "(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " + "tmp." + Keys.KEY_RING_ID + " = " + KeyRings.TABLE_NAME + + "." + KeyRings._ID + " AND " + "tmp." + Keys.IS_REVOKED + " = '0' AND " + "tmp." + Keys.CAN_ENCRYPT + " = '1' AND " + "tmp." + + Keys.CREATION + " <= '" + now + "' AND " + "(tmp." + Keys.EXPIRY + " IS NULL OR " + "tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4 + }, KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?", new String[] { "" + Id.database.type_public }, null, null, orderBy); + + ArrayList _master_keys = new ArrayList(); + while (mCursor.moveToNext()) { + long _cur_mkey = mCursor.getLong(1); + String _cur_user = mCursor.getString(2); + Log.d(TAG, "current master key: " + _cur_mkey + " from " + _cur_user); + if (search_keys.contains(Apg.getSmallFingerPrint(_cur_mkey)) || search_keys.contains(_cur_user)) { + Log.d(TAG, "master key found for: " + Apg.getSmallFingerPrint(_cur_mkey)); + _master_keys.add(_cur_mkey); + } + } + mCursor.close(); + + long[] _master_longs = new long[_master_keys.size()]; + int i = 0; + for (Long _key : _master_keys) { + _master_longs[i++] = _key; + } + return _master_longs; + } + /** * Add default arguments if missing * @@ -126,14 +193,14 @@ public class ApgService extends Service { * the bundle to add default parameters to if missing * */ - private void add_default_arguments(Bundle args) { + private void add_default_arguments(String call, Bundle args) { Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true); Iterator _iter = FUNCTIONS_DEFAULTS.keySet().iterator(); while (_iter.hasNext()) { arg _current_arg = _iter.next(); String _current_key = _current_arg.name(); - if (!args.containsKey(_current_key)) { + 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); @@ -201,101 +268,123 @@ public class ApgService extends Service { HashSet all_args = new HashSet(FUNCTIONS_REQUIRED_ARGS.get(function)); all_args.addAll(FUNCTIONS_OPTIONAL_ARGS.get(function)); + ArrayList _unknown_args = new ArrayList(); Iterator _iter = pArgs.keySet().iterator(); while (_iter.hasNext()) { String _cur_key = _iter.next(); try { arg _cur_arg = arg.valueOf(_cur_key); - if( !all_args.contains(_cur_arg)) { + if (!all_args.contains(_cur_arg)) { pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key); + _unknown_args.add(_cur_key); } } catch (Exception e) { pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key); + _unknown_args.add(_cur_key); } - } + + // remove unknown arguments so our bundle has just what we need + for (String _arg : _unknown_args) { + pArgs.remove(_arg); + } + } + + private boolean prepare_args(String call, Bundle pArgs, Bundle pReturn) { + Apg.initialize(getBaseContext()); + + /* add default return values for all functions */ + add_default_returns(pReturn); + + /* add default arguments if missing */ + add_default_arguments(call, pArgs); + Log.d(TAG, "add_default_arguments"); + + /* check for required arguments */ + check_required_args(call, pArgs, pReturn); + Log.d(TAG, "check_required_args"); + + /* check for unknown arguments and add to warning if found */ + check_unknown_args(call, pArgs, pReturn); + Log.d(TAG, "check_unknown_args"); + + /* return if errors happened */ + if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { + pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.ordinal()); + return false; + } + Log.d(TAG, "error return"); + + return true; + } + + private boolean encrypt(Bundle pArgs, Bundle pReturn) { + + long _pub_master_keys[] = {}; + if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) { + ArrayList _list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name()); + ArrayList _pub_keys = new ArrayList(); + Log.d(TAG, "Long size: " + _list.size()); + Iterator _iter = _list.iterator(); + while (_iter.hasNext()) { + _pub_keys.add(_iter.next()); + } + _pub_master_keys = get_master_key(_pub_keys); + } + + InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); + InputData _in = new InputData(_inStream, 0); // XXX Size second + // param? + + OutputStream _out = new ByteArrayOutputStream(); + try { + Apg.encrypt(getBaseContext(), // context + _in, // input stream + _out, // output stream + pArgs.getBoolean(arg.ARMORED.name()), // armored + _pub_master_keys, // encryption keys + 0, // signature key + null, // signature passphrase + null, // progress + 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"); + pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when encrypting: " + e.getMessage()); + + pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); + return false; + } + Log.d(TAG, "Encrypted"); + pReturn.putString(ret.RESULT.name(), _out.toString()); + return true; } private final IApgService.Stub mBinder = new IApgService.Stub() { - public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { - /* add default return values for all functions */ - add_default_returns(pReturn); - - /* add default arguments if missing */ - add_default_arguments(pArgs); - Log.d(TAG, "add_default_arguments"); - - /* check for required arguments */ - check_required_args("encrypt_with_passphrase", pArgs, pReturn); - Log.d(TAG, "check_required_args"); - - /* 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 (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { - pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.ordinal()); + public boolean encrypt_with_public_key(Bundle pArgs, Bundle pReturn) { + if (!prepare_args("encrypt_with_public_key", pArgs, pReturn)) { return false; } - Log.d(TAG, "error return"); - InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); - InputData _in = new InputData(_inStream, 0); // XXX Size second - // param? - OutputStream _out = new ByteArrayOutputStream(); - - Apg.initialize(getApplicationContext()); - try { - Apg.encrypt(getApplicationContext(), // context - _in, // input stream - _out, // output stream - pArgs.getBoolean(arg.ARMORED.name()), // armored - new long[0], // encryption keys - 0, // signature key - null, // signature passphrase - null, // progress - 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"); - pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure in APG when encrypting: " + e.getMessage()); - - pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); - return false; - } - Log.d(TAG, "Encrypted"); - pReturn.putString(ret.RESULT.name(), _out.toString()); - return true; + return encrypt(pArgs, pReturn); } - public boolean decrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { - /* add default return values for all functions */ - add_default_returns(pReturn); + public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { + if (!prepare_args("encrypt_with_passphrase", pArgs, pReturn)) { + return false; + } - /* add default arguments if missing */ - add_default_arguments(pArgs); - Log.d(TAG, "add_default_arguments"); + return encrypt(pArgs, pReturn); + } - /* check required args */ - check_required_args("decrypt_with_passphrase", pArgs, pReturn); - Log.d(TAG, "check_required_args"); - - - /* check for unknown args and add to warning */ - check_unknown_args("decrypt_with_passphrase", pArgs, pReturn); - Log.d(TAG, "check_unknown_args"); - - - /* return if errors happened */ - if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { - pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.ordinal()); + public boolean decrypt(Bundle pArgs, Bundle pReturn) { + if (!prepare_args("decrypt", pArgs, pReturn)) { return false; } @@ -304,14 +393,19 @@ public class ApgService extends Service { // second parameter? OutputStream out = new ByteArrayOutputStream(); try { - Apg.decrypt(getApplicationContext(), in, out, pArgs.getString(arg.SYM_KEY.name()), null, // progress - true // symmetric + Apg.decrypt(getBaseContext(), in, out, pArgs.getString(arg.SYM_KEY.name()), null, // progress + pArgs.getString(arg.SYM_KEY.name()) != null // symmetric ); } catch (Exception e) { Log.d(TAG, "Exception in decrypt"); - pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure in APG when decrypting: " + e.getMessage()); - - pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); + if (e.getMessage() == getBaseContext().getString(R.string.error_noSecretKeyFound)) { + pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot decrypt: " + e.getMessage()); + pReturn.putInt(ret.ERROR.name(), error.NO_MATCHING_SECRET_KEY.ordinal()); + } else { + pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when decrypting: " + e.getMessage()); + e.printStackTrace(); + pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); + } return false; } diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index 2bd3f8dcf..be38c3367 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -9,13 +9,12 @@ interface IApgService { * int "ERROR" = Numeric representation of error */ - /** Encrypt something with a symmetric key + /** Encryption function's arguments * * Bundle params' keys: * (optional/required) TYPE "STRING KEY" = EXPLANATION / VALUES * * (required) String "MSG" = Message to encrypt - * (required) String "SYM_KEY" = Symmetric key to use * (optional) int "ENCRYPTION_ALGO" = Encryption Algorithm * 7: AES-128, 8: AES-192, 9: AES-256, 4: Blowfish, 10: Twofish, 3: CAST5, @@ -33,16 +32,27 @@ interface IApgService { * Bundle return_vals (in addition to the ERRORS/WARNINGS above): * String "RESULT" = Encrypted MSG */ + + /* Additional argument: + * (required) String "SYM_KEY" = Symmetric key to use + */ boolean encrypt_with_passphrase(in Bundle params, out Bundle return_vals); + + /* Additional argument: + * (required) ArrayList "PUBLIC_KEYS" = Public keys (8char fingerprint "123ABC12" OR + * complete id "Alice Meyer ") + */ + boolean encrypt_with_public_key(in Bundle params, out Bundle return_vals); + - /** Decrypt something with a symmetric key + /** Decrypt something * * Bundle params: * (required) String "MSG" = Message to decrypt - * (required) String "SYM_KEY" = Symmetric key to use + * (optional) String "SYM_KEY" = Symmetric key to use if encryption is symmetric * * Bundle return_vals: * String "RESULT" = Decrypted MSG */ - boolean decrypt_with_passphrase(in Bundle params, out Bundle return_vals); + boolean decrypt(in Bundle params, out Bundle return_vals); } \ No newline at end of file From 9fb631d599d9c375b83a5b2a682a4ff58cc23b79 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 13 Jan 2011 20:28:08 +0000 Subject: [PATCH 25/69] Clear result, too --- src/org/thialfihar/android/apg/utils/ApgCon.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 0ad92fcbb..e1a753dbc 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -210,11 +210,16 @@ public class ApgCon { public void clear_warnings() { warning_list.clear(); } + + public void clear_result() { + result.clear(); + } public void reset() { clear_errors(); clear_warnings(); clear_args(); + clear_result(); } public void disconnect() { From 7bf8649d9537bc6d51a199cf8ecd79d9c022a34d Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Mon, 17 Jan 2011 21:15:31 +0000 Subject: [PATCH 26/69] Update version information to reflect branch --- AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0ece93e55..4f946300e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,7 +17,7 @@ Date: Mon, 17 Jan 2011 22:16:49 +0000 Subject: [PATCH 27/69] Allow to sign and specify passphrase on decrypting --- .../thialfihar/android/apg/ApgService.java | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 796a42913..0cfb065db 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -48,8 +48,9 @@ public class ApgService extends Service { 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 + COMPRESSION, // what compression to use for encrypted output + SIGNATURE_KEY, // key for signing + PRIVATE_KEY_PASS, // passphrase for encrypted private key } /** all things that might be returned */ @@ -57,8 +58,7 @@ public class ApgService extends Service { ERRORS, // string array list with errors WARNINGS, // string array list with warnings ERROR, // numeric error - RESULT - // en-/decrypted test + RESULT, // en-/decrypted test } /** required arguments for each AIDL function */ @@ -89,12 +89,15 @@ public class ApgService extends Service { args.add(arg.ARMORED); args.add(arg.FORCE_V3_SIG); args.add(arg.COMPRESSION); + args.add(arg.PRIVATE_KEY_PASS); + args.add(arg.SIGNATURE_KEY); FUNCTIONS_OPTIONAL_ARGS.put("encrypt_with_passphrase", args); FUNCTIONS_OPTIONAL_ARGS.put("encrypt_with_public_key", args); args = new HashSet(); args.add(arg.SYM_KEY); args.add(arg.PUBLIC_KEYS); + args.add(arg.PRIVATE_KEY_PASS); FUNCTIONS_OPTIONAL_ARGS.put("decrypt", args); } @@ -136,6 +139,23 @@ public class ApgService extends Service { } } + /** + * 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 + */ + private static long get_master_key(String search_key) { + ArrayList tmp = new ArrayList(); + tmp.add(search_key); + long[] _keys = get_master_key(tmp); + if (_keys.length > 0) + return _keys[0]; + else + return 0; + } + /** * maps fingerprints or user ids of keys to master keys in database * @@ -164,7 +184,9 @@ public class ApgService extends Service { "(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " + "tmp." + Keys.KEY_RING_ID + " = " + KeyRings.TABLE_NAME + "." + KeyRings._ID + " AND " + "tmp." + Keys.IS_REVOKED + " = '0' AND " + "tmp." + Keys.CAN_ENCRYPT + " = '1' AND " + "tmp." + Keys.CREATION + " <= '" + now + "' AND " + "(tmp." + Keys.EXPIRY + " IS NULL OR " + "tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4 - }, KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?", new String[] { "" + Id.database.type_public }, null, null, orderBy); + }, KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?", new String[] { + "" + Id.database.type_public + }, null, null, orderBy); ArrayList _master_keys = new ArrayList(); while (mCursor.moveToNext()) { @@ -191,7 +213,6 @@ public class ApgService extends Service { * * @param args * the bundle to add default parameters to if missing - * */ private void add_default_arguments(String call, Bundle args) { Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true); @@ -333,8 +354,7 @@ public class ApgService extends Service { } InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); - InputData _in = new InputData(_inStream, 0); // XXX Size second - // param? + InputData _in = new InputData(_inStream, 0); // XXX Size second param? OutputStream _out = new ByteArrayOutputStream(); try { @@ -343,8 +363,8 @@ public class ApgService extends Service { _out, // output stream pArgs.getBoolean(arg.ARMORED.name()), // armored _pub_master_keys, // encryption keys - 0, // signature key - null, // signature passphrase + get_master_key(pArgs.getString(arg.SIGNATURE_KEY.name())), // signature key + pArgs.getString(arg.PRIVATE_KEY_PASS.name()), // signature passphrase null, // progress pArgs.getInt(arg.ENCRYPTION_ALGO.name()), // encryption pArgs.getInt(arg.HASH_ALGO.name()), // hash @@ -388,12 +408,14 @@ public class ApgService extends Service { return false; } + String _passphrase = pArgs.getString(arg.SYM_KEY.name()) != null ? pArgs.getString(arg.SYM_KEY.name()) : pArgs.getString(arg.PRIVATE_KEY_PASS + .name()); + InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); - InputData in = new InputData(inStream, 0); // XXX what size in - // second parameter? + InputData in = new InputData(inStream, 0); // XXX what size in second parameter? OutputStream out = new ByteArrayOutputStream(); try { - Apg.decrypt(getBaseContext(), in, out, pArgs.getString(arg.SYM_KEY.name()), null, // progress + Apg.decrypt(getBaseContext(), in, out, _passphrase, null, // progress pArgs.getString(arg.SYM_KEY.name()) != null // symmetric ); } catch (Exception e) { From dc02a74d52f66ebf7e4b3592ad7af09ce883f734 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Mon, 17 Jan 2011 22:16:57 +0000 Subject: [PATCH 28/69] Update AIDL-Doc --- .../thialfihar/android/apg/IApgService.aidl | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index be38c3367..94f37949e 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -2,39 +2,41 @@ package org.thialfihar.android.apg; interface IApgService { - /** All functions fill the return_vals Bundle with the following keys: + /* All functions fill the return_vals Bundle with the following keys: * * ArrayList "WARNINGS" = Warnings, if any * ArrayList "ERRORS" = Human readable error descriptions, why function call failed * int "ERROR" = Numeric representation of error */ - /** Encryption function's arguments + /* Encryption function's arguments * * Bundle params' keys: - * (optional/required) TYPE "STRING KEY" = EXPLANATION / VALUES + * (optional/required) TYPE "STRING KEY" = EXPLANATION / VALUES * - * (required) String "MSG" = Message to encrypt - * (optional) int "ENCRYPTION_ALGO" = 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_ALGO" = 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" = Armor output - * (optional) Boolean "FORCE_V3_SIG" = Force V3 Signatures - * (optional) int "COMPRESSION" = Compression to use - 0x21070001: none, 1: Zip, 2: Zlib, - 3: BZip2 + * (required) String "MSG" = Message to encrypt + * (optional) int "ENCRYPTION_ALGO" = 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_ALGO" = 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" = Armor output + * (optional) Boolean "FORCE_V3_SIG" = 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 "SIGNATURE_KEY_PASS" = Passphrase for signing key * * Bundle return_vals (in addition to the ERRORS/WARNINGS above): - * String "RESULT" = Encrypted MSG + * String "RESULT" = Encrypted MSG */ /* Additional argument: - * (required) String "SYM_KEY" = Symmetric key to use + * (required) String "SYM_KEY" = Symmetric key to use */ boolean encrypt_with_passphrase(in Bundle params, out Bundle return_vals); @@ -45,14 +47,15 @@ interface IApgService { boolean encrypt_with_public_key(in Bundle params, out Bundle return_vals); - /** Decrypt something + /* Decrypt something * * Bundle params: - * (required) String "MSG" = Message to decrypt - * (optional) String "SYM_KEY" = Symmetric key to use if encryption is symmetric + * (required) String "MSG" = Message to decrypt + * (optional) String "SYM_KEY" = Symmetric key to use if encryption is symmetric + * (optional) String "PRIVATE_KEY_PASS" = Private keys's passphrase on asymmetric encryption * * Bundle return_vals: - * String "RESULT" = Decrypted MSG + * String "RESULT" = Decrypted MSG */ boolean decrypt(in Bundle params, out Bundle return_vals); } \ No newline at end of file From eb75eea64fbb0c9bfb86ed1fc1ef5dc1248144e0 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Mon, 17 Jan 2011 22:21:41 +0000 Subject: [PATCH 29/69] Allow get_master_key to accept null string Return earlier on wrong length, too. --- src/org/thialfihar/android/apg/ApgService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 0cfb065db..e395a808d 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -147,6 +147,9 @@ public class ApgService extends Service { * @return master key if found, or 0 */ private static long get_master_key(String search_key) { + if (search_key == null || search_key.length() != 8) { + return 0; + } ArrayList tmp = new ArrayList(); tmp.add(search_key); long[] _keys = get_master_key(tmp); From 5eaea519adfda20246d11b380048adfc83f1ff37 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 20:35:33 +0000 Subject: [PATCH 30/69] Refactor some log prios --- .../thialfihar/android/apg/ApgService.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index e395a808d..b10de694a 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -24,7 +24,7 @@ import android.os.IBinder; import android.util.Log; public class ApgService extends Service { - final static String TAG = "ApgService"; + private final static String TAG = "ApgService"; @Override public IBinder onBind(Intent intent) { @@ -322,22 +322,22 @@ public class ApgService extends Service { /* add default arguments if missing */ add_default_arguments(call, pArgs); - Log.d(TAG, "add_default_arguments"); + Log.v(TAG, "add_default_arguments"); /* check for required arguments */ check_required_args(call, pArgs, pReturn); - Log.d(TAG, "check_required_args"); + Log.v(TAG, "check_required_args"); /* check for unknown arguments and add to warning if found */ check_unknown_args(call, pArgs, pReturn); - Log.d(TAG, "check_unknown_args"); + Log.v(TAG, "check_unknown_args"); /* return if errors happened */ if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.ordinal()); return false; } - Log.d(TAG, "error return"); + Log.v(TAG, "error return"); return true; } @@ -348,7 +348,7 @@ public class ApgService extends Service { if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) { ArrayList _list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name()); ArrayList _pub_keys = new ArrayList(); - Log.d(TAG, "Long size: " + _list.size()); + Log.v(TAG, "Long size: " + _list.size()); Iterator _iter = _list.iterator(); while (_iter.hasNext()) { _pub_keys.add(_iter.next()); @@ -376,13 +376,13 @@ public class ApgService extends Service { pArgs.getString(arg.SYM_KEY.name()) // passPhrase ); } catch (Exception e) { - Log.d(TAG, "Exception in encrypt"); + Log.e(TAG, "Exception in encrypt"); pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when encrypting: " + e.getMessage()); pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); return false; } - Log.d(TAG, "Encrypted"); + Log.v(TAG, "Encrypted"); pReturn.putString(ret.RESULT.name(), _out.toString()); return true; } @@ -422,13 +422,12 @@ public class ApgService extends Service { pArgs.getString(arg.SYM_KEY.name()) != null // symmetric ); } catch (Exception e) { - Log.d(TAG, "Exception in decrypt"); + Log.e(TAG, "Exception in decrypt"); if (e.getMessage() == getBaseContext().getString(R.string.error_noSecretKeyFound)) { pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot decrypt: " + e.getMessage()); pReturn.putInt(ret.ERROR.name(), error.NO_MATCHING_SECRET_KEY.ordinal()); } else { pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when decrypting: " + e.getMessage()); - e.printStackTrace(); pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); } return false; From 79238cbcce46c9623214a9d0a895cf1a7bc64867 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 20:35:41 +0000 Subject: [PATCH 31/69] Rename parameters Writing them out should make them clearer --- .../thialfihar/android/apg/ApgService.java | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index b10de694a..fe32e01b5 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -41,16 +41,16 @@ public class ApgService extends Service { /** 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 + MESSAGE, // message to encrypt or to decrypt + SYMMETRIC_PASSPHRASE, // 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 + 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_PASS, // passphrase for encrypted private key + PRIVATE_KEY_PASSPHRASE // passphrase for encrypted private key } /** all things that might be returned */ @@ -58,24 +58,24 @@ public class ApgService extends Service { ERRORS, // string array list with errors WARNINGS, // string array list with warnings ERROR, // numeric error - RESULT, // en-/decrypted test + RESULT // en-/decrypted } /** required arguments for each AIDL function */ private static final HashMap> FUNCTIONS_REQUIRED_ARGS = new HashMap>(); static { HashSet args = new HashSet(); - args.add(arg.SYM_KEY); - args.add(arg.MSG); + args.add(arg.SYMMETRIC_PASSPHRASE); + args.add(arg.MESSAGE); FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_passphrase", args); args = new HashSet(); args.add(arg.PUBLIC_KEYS); - args.add(arg.MSG); + args.add(arg.MESSAGE); FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_public_key", args); args = new HashSet(); - args.add(arg.MSG); + args.add(arg.MESSAGE); FUNCTIONS_REQUIRED_ARGS.put("decrypt", args); } @@ -84,30 +84,30 @@ public class ApgService extends Service { private static final HashMap> FUNCTIONS_OPTIONAL_ARGS = new HashMap>(); static { HashSet args = new HashSet(); - args.add(arg.ENCRYPTION_ALGO); - args.add(arg.HASH_ALGO); - args.add(arg.ARMORED); - args.add(arg.FORCE_V3_SIG); + 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_PASS); + args.add(arg.PRIVATE_KEY_PASSPHRASE); args.add(arg.SIGNATURE_KEY); FUNCTIONS_OPTIONAL_ARGS.put("encrypt_with_passphrase", args); FUNCTIONS_OPTIONAL_ARGS.put("encrypt_with_public_key", args); args = new HashSet(); - args.add(arg.SYM_KEY); + args.add(arg.SYMMETRIC_PASSPHRASE); args.add(arg.PUBLIC_KEYS); - args.add(arg.PRIVATE_KEY_PASS); + args.add(arg.PRIVATE_KEY_PASSPHRASE); FUNCTIONS_OPTIONAL_ARGS.put("decrypt", args); } /** a map from ApgService parameters to function calls to get the default */ private static final HashMap FUNCTIONS_DEFAULTS = new HashMap(); static { - 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.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"); } @@ -356,7 +356,7 @@ public class ApgService extends Service { _pub_master_keys = get_master_key(_pub_keys); } - InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); + InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); InputData _in = new InputData(_inStream, 0); // XXX Size second param? OutputStream _out = new ByteArrayOutputStream(); @@ -364,16 +364,16 @@ public class ApgService extends Service { Apg.encrypt(getBaseContext(), // context _in, // input stream _out, // output stream - pArgs.getBoolean(arg.ARMORED.name()), // armored + pArgs.getBoolean(arg.ARMORED_OUTPUT.name()), // ARMORED_OUTPUT _pub_master_keys, // encryption keys get_master_key(pArgs.getString(arg.SIGNATURE_KEY.name())), // signature key - pArgs.getString(arg.PRIVATE_KEY_PASS.name()), // signature passphrase + pArgs.getString(arg.PRIVATE_KEY_PASSPHRASE.name()), // signature passphrase null, // progress - pArgs.getInt(arg.ENCRYPTION_ALGO.name()), // encryption - pArgs.getInt(arg.HASH_ALGO.name()), // hash + 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_SIG.name()), // mPreferences.getForceV3Signatures(), - pArgs.getString(arg.SYM_KEY.name()) // passPhrase + 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"); @@ -411,15 +411,15 @@ public class ApgService extends Service { return false; } - String _passphrase = pArgs.getString(arg.SYM_KEY.name()) != null ? pArgs.getString(arg.SYM_KEY.name()) : pArgs.getString(arg.PRIVATE_KEY_PASS + String _passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs.getString(arg.PRIVATE_KEY_PASSPHRASE .name()); - InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); + InputStream 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(); try { Apg.decrypt(getBaseContext(), in, out, _passphrase, null, // progress - pArgs.getString(arg.SYM_KEY.name()) != null // symmetric + pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null // symmetric ); } catch (Exception e) { Log.e(TAG, "Exception in decrypt"); From 3f703fa4ea5ffb59def408455399cc1ea43b0434 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 21:17:05 +0000 Subject: [PATCH 32/69] More finegrained errors --- .../thialfihar/android/apg/ApgService.java | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index fe32e01b5..72f0e5dcc 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -36,7 +36,9 @@ public class ApgService extends Service { private enum error { ARGUMENTS_MISSING, APG_FAILURE, - NO_MATCHING_SECRET_KEY + NO_MATCHING_SECRET_KEY, + PRIVATE_KEY_PASSPHRASE_WRONG, + PRIVATE_KEY_PASSPHRASE_MISSING } /** all arguments that can be passed by calling application */ @@ -50,7 +52,8 @@ public class ApgService extends Service { 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 + PRIVATE_KEY_PASSPHRASE + // passphrase for encrypted private key } /** all things that might be returned */ @@ -58,7 +61,8 @@ public class ApgService extends Service { ERRORS, // string array list with errors WARNINGS, // string array list with warnings ERROR, // numeric error - RESULT // en-/decrypted + RESULT + // en-/decrypted } /** required arguments for each AIDL function */ @@ -377,9 +381,17 @@ public class ApgService extends Service { ); } catch (Exception e) { Log.e(TAG, "Exception in encrypt"); - pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when encrypting: " + e.getMessage()); - - pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); + String _msg = e.getMessage(); + if (_msg == 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.ordinal()); + } else if (_msg == 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.ordinal()); + } 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.ordinal()); + } return false; } Log.v(TAG, "Encrypted"); @@ -411,8 +423,8 @@ public class ApgService extends Service { return false; } - String _passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs.getString(arg.PRIVATE_KEY_PASSPHRASE - .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 = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); InputData in = new InputData(inStream, 0); // XXX what size in second parameter? @@ -423,11 +435,15 @@ public class ApgService extends Service { ); } catch (Exception e) { Log.e(TAG, "Exception in decrypt"); - if (e.getMessage() == getBaseContext().getString(R.string.error_noSecretKeyFound)) { - pReturn.getStringArrayList(ret.ERRORS.name()).add("Cannot decrypt: " + e.getMessage()); + String _msg = e.getMessage(); + if (_msg == 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.ordinal()); + } else if (_msg == 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.ordinal()); } else { - pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when decrypting: " + e.getMessage()); + pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when decrypting: " + _msg); pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); } return false; From 10e0dd0237f2072bb2862772f8bb2997b3747926 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 21:17:14 +0000 Subject: [PATCH 33/69] Update AIDL to reflect new argument names In addition redesign the comments a little bit. Still doesn't look good, but at least a bit better. --- .../thialfihar/android/apg/IApgService.aidl | 70 ++++++++++++------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index 94f37949e..89ea62827 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -12,37 +12,52 @@ interface IApgService { /* Encryption function's arguments * * Bundle params' keys: - * (optional/required) TYPE "STRING KEY" = EXPLANATION / VALUES + * (optional/required) + * TYPE "STRING KEY" = EXPLANATION / VALUES * - * (required) String "MSG" = Message to encrypt - * (optional) int "ENCRYPTION_ALGO" = 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_ALGO" = 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" = Armor output - * (optional) Boolean "FORCE_V3_SIG" = 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 "SIGNATURE_KEY_PASS" = Passphrase for signing key + * (required) + * String "MESSAGE" = Message to encrypt + * + * (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 "SIGNATURE_KEY_PASSPHRASE" = Passphrase for signing key * * Bundle return_vals (in addition to the ERRORS/WARNINGS above): - * String "RESULT" = Encrypted MSG + * String "RESULT" = Encrypted message */ /* Additional argument: - * (required) String "SYM_KEY" = Symmetric key to use + * (required) + * String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase to use */ boolean encrypt_with_passphrase(in Bundle params, out Bundle return_vals); /* Additional argument: - * (required) ArrayList "PUBLIC_KEYS" = Public keys (8char fingerprint "123ABC12" OR - * complete id "Alice Meyer ") + * (required) + * ArrayList "PUBLIC_KEYS" = Public keys (8char fingerprint "123ABC12" OR + * complete id "Alice Meyer ") */ boolean encrypt_with_public_key(in Bundle params, out Bundle return_vals); @@ -50,12 +65,17 @@ interface IApgService { /* Decrypt something * * Bundle params: - * (required) String "MSG" = Message to decrypt - * (optional) String "SYM_KEY" = Symmetric key to use if encryption is symmetric - * (optional) String "PRIVATE_KEY_PASS" = Private keys's passphrase on asymmetric encryption + * (required) + * String "MESSAGE" = Message to decrypt + * + * (optional) + * String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase for decryption + * + * (optional) + * String "PRIVATE_KEY_PASSPHRASE" = Private keys's passphrase on asymmetric encryption * * Bundle return_vals: - * String "RESULT" = Decrypted MSG + * String "RESULT" = Decrypted message */ boolean decrypt(in Bundle params, out Bundle return_vals); } \ No newline at end of file From e6ece71fa0d9500bea7e110cb66db08e354d3738 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 22:08:56 +0000 Subject: [PATCH 34/69] Add AIDL API version --- AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 4f946300e..a6580a57c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -199,6 +199,7 @@ + Date: Tue, 18 Jan 2011 22:09:05 +0000 Subject: [PATCH 35/69] Check for AIDL Api version and ApgService This prints out errors on console when APG cannot work with the help. It will initialize correctly, though. --- .../thialfihar/android/apg/utils/ApgCon.java | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index e1a753dbc..749ee69c7 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -6,6 +6,8 @@ import android.content.Context; import android.content.ComponentName; import android.content.ServiceConnection; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.IBinder; import android.util.Log; @@ -15,12 +17,12 @@ import org.thialfihar.android.apg.IApgService; /** * This class can be used by other projects to simplify connecting to the * APG-Service. Kind of wrapper of for AIDL. - * * It is not used in this project. */ public class ApgCon { private final static String TAG = "ApgCon"; + private final static int api_version = 1; // aidl api-version it expects private final Context mContext; @@ -55,6 +57,35 @@ public class ApgCon { public ApgCon(Context ctx) { Log.v(TAG, "EncryptionService created"); mContext = ctx; + + try { + ServiceInfo apg_services[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg", + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services; + if (apg_services == null) { + Log.e(TAG, "Could not fetch services"); + } else { + boolean apg_service_found = false; + for (ServiceInfo inf : apg_services) { + Log.v(TAG, "Found service of APG: " + inf.name); + if (inf.name.equals("org.thialfihar.android.apg.ApgService")) { + apg_service_found = true; + if (inf.metaData == null) { + Log.w(TAG, "Could not determine ApgService API"); + Log.w(TAG, "This probably won't work!"); + } 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!"); + } + } + } + + if (!apg_service_found) { + Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work"); + } + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Could not find APG, is it installed?"); + } } /** try to connect to the apg service */ @@ -210,7 +241,7 @@ public class ApgCon { public void clear_warnings() { warning_list.clear(); } - + public void clear_result() { result.clear(); } From 209b300638d70caa10d4ac9a79be46123a8f7f91 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 22:12:47 +0000 Subject: [PATCH 36/69] Print api_version if matching --- src/org/thialfihar/android/apg/utils/ApgCon.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 749ee69c7..e2e503781 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -75,6 +75,8 @@ public class ApgCon { } 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!"); + } else { + Log.v(TAG, "Found api_version "+api_version+", everything should work"); } } } From 945e8bb25bd3bff3b03be3061113895ab78033a9 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 22:19:48 +0000 Subject: [PATCH 37/69] Add another verbose hint for ApgCon constructor --- src/org/thialfihar/android/apg/utils/ApgCon.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index e2e503781..3d9795a0f 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -59,6 +59,7 @@ public class ApgCon { mContext = ctx; try { + Log.v(TAG, "Searching for the right APG version"); ServiceInfo apg_services[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg", PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services; if (apg_services == null) { From 79cf07f1e23f5b19c151b360cc25fc9c5a62589f Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 22:24:28 +0000 Subject: [PATCH 38/69] Compare strings like they should be compared --- src/org/thialfihar/android/apg/ApgService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 72f0e5dcc..fe9e84d4b 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -382,10 +382,10 @@ public class ApgService extends Service { } catch (Exception e) { Log.e(TAG, "Exception in encrypt"); String _msg = e.getMessage(); - if (_msg == getBaseContext().getString(R.string.error_noSignaturePassPhrase)) { + 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.ordinal()); - } else if (_msg == getBaseContext().getString(R.string.error_couldNotExtractPrivateKey)) { + } 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.ordinal()); } else { @@ -436,10 +436,10 @@ public class ApgService extends Service { } catch (Exception e) { Log.e(TAG, "Exception in decrypt"); String _msg = e.getMessage(); - if (_msg == getBaseContext().getString(R.string.error_noSecretKeyFound)) { + 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.ordinal()); - } else if (_msg == getBaseContext().getString(R.string.error_wrongPassPhrase)) { + } 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.ordinal()); } else { From be2476e0ba56241c4681be11371177cfd4d5d876 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 19 Jan 2011 22:33:06 +0000 Subject: [PATCH 39/69] Allow async execution of an AIDL call Calls can now be executed asyncronously. Callback methods are supported, too. See comments of "set_callback()". First tries with javadoc. --- .../thialfihar/android/apg/utils/ApgCon.java | 159 ++++++++++++++++-- 1 file changed, 141 insertions(+), 18 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 3d9795a0f..ac94f27be 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -8,6 +8,7 @@ import android.content.ServiceConnection; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; +import android.os.AsyncTask; import android.os.Bundle; import android.os.IBinder; import android.util.Log; @@ -21,10 +22,41 @@ import org.thialfihar.android.apg.IApgService; */ public class ApgCon { + public class call_async extends AsyncTask { + + @Override + protected Void doInBackground(String... arg) { + Log.d(TAG, "Async execution starting"); + call(arg[0]); + return null; + } + + protected void onPostExecute(Void result) { + Log.d(TAG, "Async execution finished"); + async_running = false; + if (callback_object != null && callback_method != null) { + try { + callback_object.getClass().getMethod(callback_method).invoke(callback_object); + Log.d(TAG, "Callback executed"); + } catch (NoSuchMethodException e) { + Log.w(TAG, "Exception in callback: Method '" + callback_method + "' not found"); + warning_list.add("LOCAL: Could not execute callback, method '" + callback_method + "' not found"); + } catch (Exception e) { + Log.w(TAG, "Exception on callback: " + e.getMessage()); + warning_list.add("LOCAL: Could not execute callback"); + } + } + } + + } + private final static String TAG = "ApgCon"; private final static int api_version = 1; // aidl api-version it expects private final Context mContext; + private boolean async_running = false; + private Object callback_object; + private String callback_method; private final Bundle result = new Bundle(); private final Bundle args = new Bundle(); @@ -77,7 +109,7 @@ public class ApgCon { Log.w(TAG, "Found ApgService API version" + inf.metaData.getInt("api_version") + " but exspected " + api_version); Log.w(TAG, "This probably won't work!"); } else { - Log.v(TAG, "Found api_version "+api_version+", everything should work"); + Log.v(TAG, "Found api_version " + api_version + ", everything should work"); } } } @@ -121,6 +153,14 @@ public class ApgCon { return true; } + public void disconnect() { + Log.v(TAG, "disconnecting apgService"); + if (apgService != null) { + mContext.unbindService(apgConnection); + apgService = null; + } + } + private boolean initialize() { if (apgService == null) { if (!connect()) { @@ -135,6 +175,11 @@ public class ApgCon { return this.call(function, args, result); } + public void call_async(String function) { + async_running = true; + new call_async().execute(function); + } + public boolean call(String function, Bundle pArgs) { return this.call(function, pArgs, result); } @@ -145,14 +190,14 @@ public class ApgCon { warning_list.clear(); if (!initialize()) { - error_list.add("CLASS: Cannot bind to ApgService"); - pReturn.putInt("CLASS_ERROR", error.CANNOT_BIND_TO_APG.ordinal()); + error_list.add("LOCAL: Cannot bind to ApgService"); + pReturn.putInt("LOCAL_ERROR", error.CANNOT_BIND_TO_APG.ordinal()); return false; } if (function == null || function.length() == 0) { - error_list.add("CLASS: Function to call missing"); - pReturn.putInt("CLASS_ERROR", error.CALL_MISSING.ordinal()); + error_list.add("LOCAL: Function to call missing"); + pReturn.putInt("LOCAL_ERROR", error.CALL_MISSING.ordinal()); return false; } @@ -163,13 +208,13 @@ public class ApgCon { return ret; } catch (NoSuchMethodException e) { Log.e(TAG, e.getMessage()); - error_list.add("CLASS: " + e.getMessage()); - pReturn.putInt("CLASS_ERROR", error.CALL_NOT_KNOWN.ordinal()); + error_list.add("LOCAL: " + e.getMessage()); + pReturn.putInt("LOCAL_ERROR", error.CALL_NOT_KNOWN.ordinal()); return false; } catch (Exception e) { Log.e(TAG, "" + e.getMessage()); - error_list.add("CLASS: " + e.getMessage()); - pReturn.putInt("CLASS_ERROR", error.GENERIC.ordinal()); + error_list.add("LOCAL: " + e.getMessage()); + pReturn.putInt("LOCAL_ERROR", error.GENERIC.ordinal()); return false; } @@ -184,7 +229,11 @@ public class ApgCon { for (String val : vals) { list.add(val); } - args.putStringArrayList(key, list); + set_arg(key, list); + } + + public void set_arg(String key, ArrayList vals) { + args.putStringArrayList(key, vals); } public void set_arg(String key, boolean val) { @@ -249,19 +298,93 @@ public class ApgCon { result.clear(); } + /** + * Set a callback object and method + * + *

After an async execution is finished, obj.meth() will be called. You can + * use this in order to get notified, when encrypting/decrypting of long + * data finishes and do not have to poll {@link #is_running()} in your + * thread. Note, that if the call of the method fails for whatever reason, + * you won't get notified in any way - so you still should check + * {@link #is_running()} from time to time.

+ * + *

It produces a warning fetchable with {@link #get_next_warning()} when the callback fails.

+ * + *
+     * 
+     * .... your class ...
+     * public void callback() {
+     *   // do something after encryption finished
+     * }
+     * 
+     * public void encrypt() {
+     *   ApgCon mEnc = new ApgCon(context);
+     *   // set parameters
+     *   mEnc.set_arg(key, value);
+     *   ...
+     *   
+     *   // set callback object and method 
+     *   mEnc.set_callback( this, "callback" );
+     *   
+     *   // start asynchronous call
+     *   mEnc.call_async( call );
+     *   
+     *   // when the call_async finishes, the method "callback()" will be called automatically
+     * }
+     * 
+     * 
+ * + * @param obj + * The object, which has the public method meth + * @param meth + * Method to call on the object obj + */ + public void set_callback(Object obj, String meth) { + set_callback_object(obj); + set_callback_method(meth); + } + + /** + * Set a callback object + * + * @param obj + * a object to call back after async execution + * @see #set_callback(Object, String) + */ + public void set_callback_object(Object obj) { + callback_object = obj; + } + + /** + * Set a callback method + * + * @param meth + * a method to call on a callback object after async execution + * @see #set_callback(Object, String) + */ + public void set_callback_method(String meth) { + callback_method = meth; + } + + public void clear_callback_object() { + callback_object = null; + } + + public void clear_callback_method() { + callback_method = null; + } + + public boolean is_running() { + return async_running; + } + public void reset() { clear_errors(); clear_warnings(); clear_args(); clear_result(); - } - - public void disconnect() { - Log.v(TAG, "disconnecting apgService"); - if (apgService != null) { - mContext.unbindService(apgConnection); - apgService = null; - } + clear_callback_object(); + clear_callback_method(); } } From e73794a5cc1f1c78485cce4282f5b2ecef549fe2 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 11:55:36 +0000 Subject: [PATCH 40/69] Add javadoc on public things Small other changes, too. --- .../thialfihar/android/apg/utils/ApgCon.java | 334 +++++++++++++++++- 1 file changed, 320 insertions(+), 14 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index ac94f27be..296c966a5 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -18,11 +18,12 @@ import org.thialfihar.android.apg.IApgService; /** * This class can be used by other projects to simplify connecting to the * APG-Service. Kind of wrapper of for AIDL. + * * It is not used in this project. */ public class ApgCon { - public class call_async extends AsyncTask { + private class call_async extends AsyncTask { @Override protected Void doInBackground(String... arg) { @@ -86,6 +87,17 @@ public class ApgCon { CALL_NOT_KNOWN, // apg service does not know what to do } + /** + * Constructor + * + *

+ * Creates a new ApgCon object and searches for the right APG version on + * initialization. If not found, errors are printed to the error log. + *

+ * + * @param ctx + * the running context + */ public ApgCon(Context ctx) { Log.v(TAG, "EncryptionService created"); mContext = ctx; @@ -153,6 +165,20 @@ public class ApgCon { return true; } + /** + * Disconnects ApgCon from Apg + * + *

+ * 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. + *

+ * + *

+ * Also, if you destroy you end using your ApgCon-instance, this must be + * called or else the connection to APG is leaked + *

+ */ public void disconnect() { Log.v(TAG, "disconnecting apgService"); if (apgService != null) { @@ -171,20 +197,66 @@ public class ApgCon { return true; } + /** + * Calls a function from APG's AIDL-interface + * + *

+ * After you have set up everything with {@link #set_arg(String, String)} + * (and variants), you can call a function from the AIDL-interface. This + * will + *

    + *
  • start connection to the remote interface (if not already connected)
  • + *
  • call the passed function with all set up parameters synchronously
  • + *
  • set up everything to retrieve the result and/or warnings/errors
  • + *
+ *

+ * + *

+ * Note your thread will be blocked during execution - if you want to call + * the function asynchronously, see {@link #call_async(String)}. + *

+ * + * @param function + * a remote function to call + * @return true, if call successful (= no errors), else false + * + * @see #call_async(String) + * @see #set_arg(String, String) + */ public boolean call(String function) { return this.call(function, args, result); } + /** + * Calls a function from remote interface asynchronously + * + *

+ * 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. + *

+ * + *

+ * To see whether the task is finished, you have to possibilities: + *

    + *
  • In your thread, poll {@link #is_running()}
  • + *
  • Supply a callback with {@link #set_callback(Object, String)}
  • + *
+ *

+ * + * @param function + * a remote function to call + * + * @see #call(String) + * @see #is_running() + * @see #set_callback(Object, String) + */ public void call_async(String function) { async_running = true; new call_async().execute(function); } - public boolean call(String function, Bundle pArgs) { - return this.call(function, pArgs, result); - } - - public boolean call(String function, Bundle pArgs, Bundle pReturn) { + private boolean call(String function, Bundle pArgs, Bundle pReturn) { error_list.clear(); warning_list.clear(); @@ -220,30 +292,106 @@ public class ApgCon { } + /** + * Set a string argument for APG + * + *

+ * This defines a string argument for APG's AIDL-interface. + *

+ * + *

+ * To know what key-value-pairs are possible (or required), take a look into + * the IApgService.aidl + *

+ * + *

+ * Note, that the parameters are not deleted after a call, so you have to + * reset ({@link #clear_args()}) them manually if you want to. + *

+ * + * + * @param key + * the key + * @param val + * the value + * + * @see #clear_args() + */ public void set_arg(String key, String val) { args.putString(key, val); } + /** + * Set a string-array argument for APG + * + *

+ * If the AIDL-parameter is an {@literal ArrayList}, you have to use + * this function. + *

+ * + * + *
+     * set_arg("a key", new String[]{ "entry 1", "entry 2" });
+     * 
+ *
+ * + * @param key + * the key + * @param vals + * the value + * + * @see #set_arg(String, String) + */ public void set_arg(String key, String vals[]) { ArrayList list = new ArrayList(); for (String val : vals) { list.add(val); } - set_arg(key, list); - } - - public void set_arg(String key, ArrayList vals) { - args.putStringArrayList(key, vals); + args.putStringArrayList(key, list); } + /** + * Set up a boolean argument for APG + * + * @param key + * the key + * @param vals + * the value + * + * @see #set_arg(String, String) + */ public void set_arg(String key, boolean val) { args.putBoolean(key, val); } + /** + * Set up a int argument for APG + * + * @param key + * the key + * @param vals + * the value + * + * @see #set_arg(String, String) + */ public void set_arg(String key, int val) { args.putInt(key, val); } + /** + * Set up a int-array argument for APG + *

+ * If the AIDL-parameter is an {@literal ArrayList}, you have to + * use this function. + *

+ * + * @param key + * the key + * @param vals + * the value + * + * @see #set_arg(String, String) + */ public void set_arg(String key, int vals[]) { ArrayList list = new ArrayList(); for (int val : vals) { @@ -252,14 +400,50 @@ public class ApgCon { args.putIntegerArrayList(key, list); } + /** + * Clears all arguments + * + *

+ * Anything the has been set up with the various + * {@link #set_arg(String, String)} functions, is cleared. + *

+ *

+ * Note, that any warning, error, callback, result etc. is not cleared with + * this. + *

+ * + * @see #reset() + */ public void clear_args() { args.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 get_arg(String key) { return args.get(key); } + /** + * Iterates through the errors + * + *

+ * 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. + *

+ * + * @return a human readable description of a error that happened, or null if + * no more errors + * + * @see #has_next_error() + * @see #clear_errors() + */ public String get_next_error() { if (error_list.size() != 0) return error_list.remove(0); @@ -267,10 +451,32 @@ public class ApgCon { return null; } + /** + * Check, if there are any new errors + * + * @return true, if there are unreturned errors, false otherwise + * + * @see #get_next_error() + */ public boolean has_next_error() { return error_list.size() != 0; } + /** + * Iterates through the warnings + * + *

+ * With this method, you can iterate through all warnings. The warnings are + * only returned once and deleted immediately afterwards, so you can only + * return each warning once. + *

+ * + * @return a human readable description of a warning that happened, or null + * if no more warnings + * + * @see #has_next_warning() + * @see #clear_warnings() + */ public String get_next_warning() { if (warning_list.size() != 0) return warning_list.remove(0); @@ -278,22 +484,68 @@ public class ApgCon { return null; } + /** + * Check, if there are any new warnings + * + * @return true, if there are unreturned warnings, false otherwise + * + * @see #get_next_warning() + */ public boolean has_next_warning() { return warning_list.size() != 0; } + /** + * Get the result + * + *

+ * This gets your result. After doing anything with APG, you get the output + * with this function + *

+ *

+ * Note, that 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 #clear_result()}) + * your instance before each new call or always check that + * {@link #has_next_error()} is false. + *

+ * + * @return the result of the last {@link #call(String)} or + * {@link #call_asinc(String)}. + * + * @see #reset() + * @see #clear_result() + */ public String get_result() { return result.getString("RESULT"); } + /** + * Clears all unfetched errors + * + * @see #get_next_error() + * @see #has_next_error() + */ public void clear_errors() { error_list.clear(); } + /** + * Clears all unfetched warnings + * + * @see #get_next_warning() + * @see #has_next_warning() + */ public void clear_warnings() { warning_list.clear(); } + /** + * Clears the last result + * + * @see #get_result() + */ public void clear_result() { result.clear(); } @@ -301,14 +553,19 @@ public class ApgCon { /** * Set a callback object and method * - *

After an async execution is finished, obj.meth() will be called. You can + *

+ * After an async execution is finished, obj.meth() will be called. You can * use this in order to get notified, when encrypting/decrypting of long * data finishes and do not have to poll {@link #is_running()} in your * thread. Note, that if the call of the method fails for whatever reason, * you won't get notified in any way - so you still should check - * {@link #is_running()} from time to time.

+ * {@link #is_running()} from time to time. + *

* - *

It produces a warning fetchable with {@link #get_next_warning()} when the callback fails.

+ *

+ * It produces a warning fetchable with {@link #get_next_warning()} when the + * callback fails. + *

* *
      * 
@@ -366,18 +623,67 @@ public class ApgCon {
         callback_method = meth;
     }
 
+    /**
+     * Clears any callback object
+     * 
+     * @see #set_callback(Object, String)
+     */
     public void clear_callback_object() {
         callback_object = null;
     }
 
+    /**
+     * Clears any callback method
+     * 
+     * @see #set_callback(Object, String)
+     */
     public void clear_callback_method() {
         callback_method = null;
     }
 
+    /**
+     * Clears any callback method and object
+     * 
+     * @see #set_callback(Object, String)
+     */
+    public void clear_callback() {
+        clear_callback_object();
+        clear_callback_method();
+    }
+
+    /**
+     * Checks, whether an async execution is running
+     * 
+     * 

+ * If you started something with {@link #call_async(String)}, this will + * return true if the task is still running + *

+ * + * @return true, if an async task is still running, false otherwise + * + * @see #call_async(String) + */ public boolean is_running() { return async_running; } + /** + * Completely resets your instance + * + *

+ * This currently resets everything in this instance. Errors, warnings, + * results, callbacks, ... are removed. Any connection to the remote + * interface is upheld, though. + *

+ * + *

+ * Note, that when an async execution ({@link #call_async(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 on finishing the async execution any defined callback will + * NOT BE TRIGGERED. + *

+ */ public void reset() { clear_errors(); clear_warnings(); From 15bf93de348410fe3bad0aae9d869f04676ffb06 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 12:49:49 +0000 Subject: [PATCH 41/69] Fix wrong param in doc --- src/org/thialfihar/android/apg/IApgService.aidl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index 89ea62827..896314635 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -42,7 +42,7 @@ interface IApgService { * String "SIGNATURE_KEY" = Key to sign with * * (optional) - * String "SIGNATURE_KEY_PASSPHRASE" = Passphrase for signing key + * String "PRIVATE_KEY_PASSPHRASE" = Passphrase for signing key * * Bundle return_vals (in addition to the ERRORS/WARNINGS above): * String "RESULT" = Encrypted message From 3e158d0afc585e9fddd202c0fb7ddbe3f215fc30 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 16:36:03 +0000 Subject: [PATCH 42/69] Some better errors (hopefully more information) Some smaller fixes and some new functions/doc, too --- .../thialfihar/android/apg/utils/ApgCon.java | 108 +++++++++++++++--- 1 file changed, 89 insertions(+), 19 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 296c966a5..9c47f111e 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -37,14 +37,15 @@ public class ApgCon { async_running = false; if (callback_object != null && callback_method != null) { try { + Log.d(TAG, "About to execute callback"); callback_object.getClass().getMethod(callback_method).invoke(callback_object); Log.d(TAG, "Callback executed"); } catch (NoSuchMethodException e) { Log.w(TAG, "Exception in callback: Method '" + callback_method + "' not found"); - warning_list.add("LOCAL: Could not execute callback, method '" + callback_method + "' not found"); + warning_list.add("(LOCAL) Could not execute callback, method '" + callback_method + "' not found"); } catch (Exception e) { - Log.w(TAG, "Exception on callback: " + e.getMessage()); - warning_list.add("LOCAL: Could not execute callback"); + Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage()); + warning_list.add("(LOCAL) Could not execute callback"); } } } @@ -63,6 +64,7 @@ public class ApgCon { private final Bundle args = new Bundle(); private final ArrayList error_list = new ArrayList(); private final ArrayList warning_list = new ArrayList(); + private error local_error; /** Remote service for decrypting and encrypting data */ private IApgService apgService = null; @@ -85,6 +87,16 @@ public class ApgCon { CANNOT_BIND_TO_APG, // connection to apg service not possible CALL_MISSING, // function to call not provided CALL_NOT_KNOWN, // apg service does not know what to do + APG_NOT_FOUND, // could not find APG installed + APG_AIDL_MISSING, // found APG but without AIDL interface + } + + public static enum ret { + ERROR, // returned from AIDL + RESULT, // returned from AIDL + WARNINGS, // mixed AIDL and LOCAL + ERRORS, // mixed AIDL and LOCAL + LOCAL_ERROR, // LOCAL error } /** @@ -117,9 +129,11 @@ public class ApgCon { if (inf.metaData == null) { Log.w(TAG, "Could not determine ApgService API"); Log.w(TAG, "This probably won't work!"); + warning_list.add("(LOCAL) Could not determine ApgService API"); } 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!"); + warning_list.add("(LOCAL) Found ApgService API version" + inf.metaData.getInt("api_version") + " but exspected " + api_version); } else { Log.v(TAG, "Found api_version " + api_version + ", everything should work"); } @@ -128,10 +142,14 @@ public class ApgCon { if (!apg_service_found) { Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work"); + error_list.add("(LOCAL) Could not find APG with AIDL interface, this probably won't work"); + local_error = error.APG_AIDL_MISSING; } } } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not find APG, is it installed?"); + error_list.add("(LOCAL) Could not find APG, is it installed?"); + local_error = error.APG_NOT_FOUND; } } @@ -262,31 +280,33 @@ public class ApgCon { warning_list.clear(); if (!initialize()) { - error_list.add("LOCAL: Cannot bind to ApgService"); - pReturn.putInt("LOCAL_ERROR", error.CANNOT_BIND_TO_APG.ordinal()); + error_list.add("(LOCAL) Cannot bind to ApgService"); + local_error = error.CANNOT_BIND_TO_APG; return false; } if (function == null || function.length() == 0) { - error_list.add("LOCAL: Function to call missing"); - pReturn.putInt("LOCAL_ERROR", error.CALL_MISSING.ordinal()); + error_list.add("(LOCAL) Function to call missing"); + local_error = error.CALL_MISSING; return false; } try { - Boolean ret = (Boolean) IApgService.class.getMethod(function, Bundle.class, Bundle.class).invoke(apgService, pArgs, pReturn); - error_list.addAll(pReturn.getStringArrayList("ERRORS")); - warning_list.addAll(pReturn.getStringArrayList("WARNINGS")); - return ret; + Boolean success = (Boolean) IApgService.class.getMethod(function, Bundle.class, Bundle.class).invoke(apgService, pArgs, pReturn); + error_list.addAll(pReturn.getStringArrayList(ret.ERRORS.name())); + warning_list.addAll(pReturn.getStringArrayList(ret.WARNINGS.name())); + pReturn.remove(ret.ERRORS.name()); + pReturn.remove(ret.WARNINGS.name()); + return success; } catch (NoSuchMethodException e) { - Log.e(TAG, e.getMessage()); - error_list.add("LOCAL: " + e.getMessage()); - pReturn.putInt("LOCAL_ERROR", error.CALL_NOT_KNOWN.ordinal()); + Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage()); + error_list.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage()); + local_error = error.CALL_NOT_KNOWN; return false; } catch (Exception e) { Log.e(TAG, "" + e.getMessage()); - error_list.add("LOCAL: " + e.getMessage()); - pReturn.putInt("LOCAL_ERROR", error.GENERIC.ordinal()); + error_list.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); + local_error = error.GENERIC; return false; } @@ -462,6 +482,54 @@ public class ApgCon { return error_list.size() != 0; } + /** + * Returns the type of error happened + * + *

+ * Currently, two error types are possible: + *

    + *
  • ret.LOCAL_ERROR: An error that happened on the caller site. This + * might be something like connection to AIDL not possible or the funciton + * call not know by AIDL. This means, the instance is not set up correctly + * or prerequisites to use APG with AIDL are not met.
  • + *
  • ret.ERROR: Connection to APG was successful, and the call started but + * failed. Mostly this is because of wrong or missing parameters for APG.
  • + *
+ *

+ * + * @return the type of error that happend: ret.LOCAL_ERROR or ret.ERROR, or + * null if none happend + */ + public ret get_error_type() { + if (local_error != null) { + return ret.LOCAL_ERROR; + } else if (result.containsKey(ret.ERROR.name())) { + return ret.ERROR; + } else { + return null; + } + } + + public error get_local_error() { + return local_error; + } + + public void clear_local_error() { + local_error = null; + } + + public int get_remote_error() { + if (result.containsKey(ret.ERROR.name())) { + return result.getInt(ret.ERROR.name()); + } else { + return -1; + } + } + + public void clear_remote_error() { + result.remove(ret.ERROR.name()); + } + /** * Iterates through the warnings * @@ -518,7 +586,7 @@ public class ApgCon { * @see #clear_result() */ public String get_result() { - return result.getString("RESULT"); + return result.getString(ret.RESULT.name()); } /** @@ -529,6 +597,8 @@ public class ApgCon { */ public void clear_errors() { error_list.clear(); + result.remove(ret.ERROR.name()); + clear_local_error(); } /** @@ -547,7 +617,7 @@ public class ApgCon { * @see #get_result() */ public void clear_result() { - result.clear(); + result.remove(ret.RESULT.name()); } /** @@ -688,9 +758,9 @@ public class ApgCon { clear_errors(); clear_warnings(); clear_args(); - clear_result(); clear_callback_object(); clear_callback_method(); + result.clear(); } } From 72ab7fb25ffe193aa418ba0ba31fc292d8235e62 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 16:40:45 +0000 Subject: [PATCH 43/69] Some more error output --- src/org/thialfihar/android/apg/utils/ApgCon.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 9c47f111e..16ba94a1f 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -45,7 +45,7 @@ public class ApgCon { warning_list.add("(LOCAL) Could not execute callback, method '" + callback_method + "' not found"); } catch (Exception e) { Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage()); - warning_list.add("(LOCAL) Could not execute callback"); + warning_list.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); } } } @@ -304,7 +304,7 @@ public class ApgCon { local_error = error.CALL_NOT_KNOWN; return false; } catch (Exception e) { - Log.e(TAG, "" + e.getMessage()); + Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage()); error_list.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); local_error = error.GENERIC; return false; @@ -525,7 +525,7 @@ public class ApgCon { return -1; } } - + public void clear_remote_error() { result.remove(ret.ERROR.name()); } From d4901f5999b51398b3a2ff43ba82f356225f4fef Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 16:53:51 +0000 Subject: [PATCH 44/69] Catch callback's and apg-call's (are there any?) exceptions --- src/org/thialfihar/android/apg/utils/ApgCon.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 16ba94a1f..4852ad548 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -1,5 +1,6 @@ package org.thialfihar.android.apg.utils; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import android.content.Context; @@ -42,7 +43,12 @@ public class ApgCon { Log.d(TAG, "Callback executed"); } catch (NoSuchMethodException e) { Log.w(TAG, "Exception in callback: Method '" + callback_method + "' not found"); - warning_list.add("(LOCAL) Could not execute callback, method '" + callback_method + "' not found"); + warning_list.add("(LOCAL) Could not execute callback, method '" + callback_method + "()' not found"); + } catch (InvocationTargetException e) { + Throwable orig = e.getTargetException(); + Log.w(TAG, "Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" + orig.getMessage()); + warning_list.add("(LOCAL) Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" + + orig.getMessage()); } catch (Exception e) { Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage()); warning_list.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); @@ -303,8 +309,13 @@ public class ApgCon { error_list.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage()); local_error = error.CALL_NOT_KNOWN; return false; + } catch (InvocationTargetException e) { + Throwable orig = e.getTargetException(); + Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "':" + orig.getMessage()); + error_list.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()); + Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage()); error_list.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); local_error = error.GENERIC; return false; From dfb4f4e03050757c9226f0a3b089cb18ab29c6f5 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 17:38:25 +0000 Subject: [PATCH 45/69] Allow at compile time to enable stacktraces on exceptions --- .../thialfihar/android/apg/utils/ApgCon.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 4852ad548..5277222eb 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -24,6 +24,11 @@ import org.thialfihar.android.apg.IApgService; */ public class ApgCon { + /** + * Put stacktraces into the log? + */ + private final boolean stacktraces = true; + private class call_async extends AsyncTask { @Override @@ -42,14 +47,20 @@ public class ApgCon { callback_object.getClass().getMethod(callback_method).invoke(callback_object); Log.d(TAG, "Callback executed"); } catch (NoSuchMethodException e) { + if (stacktraces) + e.printStackTrace(); Log.w(TAG, "Exception in callback: Method '" + callback_method + "' not found"); warning_list.add("(LOCAL) Could not execute callback, method '" + callback_method + "()' not found"); } catch (InvocationTargetException e) { + if (stacktraces) + e.printStackTrace(); Throwable orig = e.getTargetException(); Log.w(TAG, "Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" + orig.getMessage()); warning_list.add("(LOCAL) Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" + orig.getMessage()); } catch (Exception e) { + if (stacktraces) + e.printStackTrace(); Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage()); warning_list.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); } @@ -153,6 +164,8 @@ public class ApgCon { } } } catch (PackageManager.NameNotFoundException e) { + if (stacktraces) + e.printStackTrace(); Log.e(TAG, "Could not find APG, is it installed?"); error_list.add("(LOCAL) Could not find APG, is it installed?"); local_error = error.APG_NOT_FOUND; @@ -171,6 +184,8 @@ public class ApgCon { try { mContext.bindService(new Intent(IApgService.class.getName()), apgConnection, Context.BIND_AUTO_CREATE); } catch (Exception e) { + if (stacktraces) + e.printStackTrace(); Log.v(TAG, "could not bind APG service"); return false; } @@ -305,16 +320,22 @@ public class ApgCon { pReturn.remove(ret.WARNINGS.name()); return success; } catch (NoSuchMethodException e) { + if (stacktraces) + e.printStackTrace(); Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage()); error_list.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage()); local_error = error.CALL_NOT_KNOWN; return false; } catch (InvocationTargetException e) { + if (stacktraces) + e.printStackTrace(); Throwable orig = e.getTargetException(); - Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "':" + orig.getMessage()); - error_list.add("(LOCAL) Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "':" + orig.getMessage()); + Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage()); + error_list.add("(LOCAL) Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage()); return false; } catch (Exception e) { + if (stacktraces) + e.printStackTrace(); Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage()); error_list.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); local_error = error.GENERIC; From 730b44bc73ca25cf0a5747f401bda18d0d010ee7 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 18:19:34 +0000 Subject: [PATCH 46/69] Make the stacktrace enabler static --- src/org/thialfihar/android/apg/utils/ApgCon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 5277222eb..e05c7e8da 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -27,7 +27,7 @@ public class ApgCon { /** * Put stacktraces into the log? */ - private final boolean stacktraces = true; + private final static boolean stacktraces = true; private class call_async extends AsyncTask { From 05627fbd623411e0c138d5e182b207c222e46e31 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 18:19:42 +0000 Subject: [PATCH 47/69] Print some info about keys on asymmetric encryption --- src/org/thialfihar/android/apg/ApgService.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index fe9e84d4b..4e55f80d7 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -199,10 +199,15 @@ public class ApgService extends Service { while (mCursor.moveToNext()) { long _cur_mkey = mCursor.getLong(1); String _cur_user = mCursor.getString(2); + + String _cur_fprint = Apg.getSmallFingerPrint(_cur_mkey); Log.d(TAG, "current master key: " + _cur_mkey + " from " + _cur_user); - if (search_keys.contains(Apg.getSmallFingerPrint(_cur_mkey)) || search_keys.contains(_cur_user)) { - Log.d(TAG, "master key found for: " + Apg.getSmallFingerPrint(_cur_mkey)); + if (search_keys.contains(_cur_fprint) || search_keys.contains(_cur_user)) { + Log.v(TAG, "master key found for: " + _cur_fprint); _master_keys.add(_cur_mkey); + search_keys.remove(_cur_fprint); + } else { + Log.v(TAG, "Installed key "+_cur_fprint+" is not in the list of public keys to encrypt with"); } } mCursor.close(); @@ -212,6 +217,15 @@ public class ApgService extends Service { for (Long _key : _master_keys) { _master_longs[i++] = _key; } + + if( i == 0) { + Log.e(TAG, "Found no public key to encrypt with, APG will error out"); + } + + for( String _key : search_keys) { + Log.w(TAG, "Cannot encrypt with key "+_key+": cannot find it in APG"); + } + return _master_longs; } From 1af5a985b5db356860a622dacda767c85ef444e6 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 18:25:38 +0000 Subject: [PATCH 48/69] Redefine some log-msges --- src/org/thialfihar/android/apg/ApgService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 4e55f80d7..b7c4f0d4a 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -195,13 +195,14 @@ public class ApgService extends Service { "" + Id.database.type_public }, null, null, orderBy); + Log.v(TAG, "going through installed user keys"); ArrayList _master_keys = new ArrayList(); while (mCursor.moveToNext()) { long _cur_mkey = mCursor.getLong(1); String _cur_user = mCursor.getString(2); String _cur_fprint = Apg.getSmallFingerPrint(_cur_mkey); - Log.d(TAG, "current master key: " + _cur_mkey + " from " + _cur_user); + Log.v(TAG, "current user: "+_cur_user+" ("+_cur_fprint+")"); if (search_keys.contains(_cur_fprint) || search_keys.contains(_cur_user)) { Log.v(TAG, "master key found for: " + _cur_fprint); _master_keys.add(_cur_mkey); From 392969629c9fb4953a0a257e866d8538515faa50 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 18:38:15 +0000 Subject: [PATCH 49/69] Some better (non-misleading) error msgs Also some reindentation --- .../thialfihar/android/apg/ApgService.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index b7c4f0d4a..fc6742445 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -150,13 +150,13 @@ public class ApgService extends Service { * fingerprint or user id to search for * @return master key if found, or 0 */ - private static long get_master_key(String search_key) { + private static long get_master_key(String search_key, Bundle pReturn) { if (search_key == null || search_key.length() != 8) { return 0; } ArrayList tmp = new ArrayList(); tmp.add(search_key); - long[] _keys = get_master_key(tmp); + long[] _keys = get_master_key(tmp, pReturn); if (_keys.length > 0) return _keys[0]; else @@ -171,7 +171,7 @@ public class ApgService extends Service { * database * @return an array of master keys */ - private static long[] get_master_key(ArrayList search_keys) { + private static long[] get_master_key(ArrayList search_keys, Bundle pReturn) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " + "(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME @@ -200,15 +200,15 @@ public class ApgService extends Service { while (mCursor.moveToNext()) { long _cur_mkey = mCursor.getLong(1); String _cur_user = mCursor.getString(2); - + String _cur_fprint = Apg.getSmallFingerPrint(_cur_mkey); - Log.v(TAG, "current user: "+_cur_user+" ("+_cur_fprint+")"); + Log.v(TAG, "current user: " + _cur_user + " (" + _cur_fprint + ")"); if (search_keys.contains(_cur_fprint) || search_keys.contains(_cur_user)) { Log.v(TAG, "master key found for: " + _cur_fprint); _master_keys.add(_cur_mkey); search_keys.remove(_cur_fprint); } else { - Log.v(TAG, "Installed key "+_cur_fprint+" is not in the list of public keys to encrypt with"); + Log.v(TAG, "Installed key " + _cur_fprint + " is not in the list of public keys to encrypt with"); } } mCursor.close(); @@ -218,15 +218,17 @@ public class ApgService extends Service { for (Long _key : _master_keys) { _master_longs[i++] = _key; } - - if( i == 0) { - Log.e(TAG, "Found no public key to encrypt with, APG will error out"); + + 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 : search_keys) { - Log.w(TAG, "Cannot encrypt with key "+_key+": cannot find it in APG"); + + 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"); } - + return _master_longs; } @@ -372,7 +374,7 @@ public class ApgService extends Service { while (_iter.hasNext()) { _pub_keys.add(_iter.next()); } - _pub_master_keys = get_master_key(_pub_keys); + _pub_master_keys = get_master_key(_pub_keys, pReturn); } InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); @@ -385,7 +387,7 @@ public class ApgService extends Service { _out, // output stream pArgs.getBoolean(arg.ARMORED_OUTPUT.name()), // ARMORED_OUTPUT _pub_master_keys, // encryption keys - get_master_key(pArgs.getString(arg.SIGNATURE_KEY.name())), // signature key + get_master_key(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 From c9f6f56827ce7b368a009c153d1f9995651f6522 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 20:00:28 +0000 Subject: [PATCH 50/69] Work on errors and documentation - once more --- .../thialfihar/android/apg/ApgService.java | 20 +-- .../thialfihar/android/apg/IApgService.aidl | 9 +- .../thialfihar/android/apg/utils/ApgCon.java | 117 +++++++++--------- 3 files changed, 77 insertions(+), 69 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index fc6742445..c4a348cb4 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -38,7 +38,11 @@ public class ApgService extends Service { APG_FAILURE, NO_MATCHING_SECRET_KEY, PRIVATE_KEY_PASSPHRASE_WRONG, - PRIVATE_KEY_PASSPHRASE_MISSING + PRIVATE_KEY_PASSPHRASE_MISSING; + + public int shifted_ordinal() { + return ordinal() + 100; + } } /** all arguments that can be passed by calling application */ @@ -355,7 +359,7 @@ public class ApgService extends Service { /* return if errors happened */ if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { - pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.ordinal()); + pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.shifted_ordinal()); return false; } Log.v(TAG, "error return"); @@ -401,13 +405,13 @@ public class ApgService extends Service { 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.ordinal()); + pReturn.putInt(ret.ERROR.name(), error.PRIVATE_KEY_PASSPHRASE_MISSING.shifted_ordinal()); } 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.ordinal()); + pReturn.putInt(ret.ERROR.name(), error.PRIVATE_KEY_PASSPHRASE_WRONG.shifted_ordinal()); } 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.ordinal()); + pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shifted_ordinal()); } return false; } @@ -455,13 +459,13 @@ public class ApgService extends Service { 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.ordinal()); + pReturn.putInt(ret.ERROR.name(), error.NO_MATCHING_SECRET_KEY.shifted_ordinal()); } 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.ordinal()); + pReturn.putInt(ret.ERROR.name(), error.PRIVATE_KEY_PASSPHRASE_WRONG.shifted_ordinal()); } else { pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure (" + e.getClass() + ") in APG when decrypting: " + _msg); - pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); + pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shifted_ordinal()); } return false; } diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index 896314635..c35e82df7 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -5,8 +5,13 @@ interface IApgService { /* All functions fill the return_vals Bundle with the following keys: * * ArrayList "WARNINGS" = Warnings, if any - * ArrayList "ERRORS" = Human readable error descriptions, why function call failed - * int "ERROR" = Numeric representation of error + * ArrayList "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 function's arguments diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index e05c7e8da..b80b66daa 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -17,10 +17,20 @@ import android.util.Log; import org.thialfihar.android.apg.IApgService; /** - * This class can be used by other projects to simplify connecting to the - * APG-Service. Kind of wrapper of for AIDL. + * A APG-AIDL-Wrapper * + *

+ * This class can be used by other projects to simplify connecting to the + * APG-AIDL-Service. Kind of wrapper of for AIDL. + *

+ * + *

* It is not used in this project. + *

+ * + * @author Markus Doits + * @version 0.9 + * */ public class ApgCon { @@ -81,7 +91,6 @@ public class ApgCon { private final Bundle args = new Bundle(); private final ArrayList error_list = new ArrayList(); private final ArrayList warning_list = new ArrayList(); - private error local_error; /** Remote service for decrypting and encrypting data */ private IApgService apgService = null; @@ -99,21 +108,44 @@ public class ApgCon { } }; + /** + * Different types of local errors + * + * @author markus + * + */ public static enum error { - GENERIC, // no special type - CANNOT_BIND_TO_APG, // connection to apg service not possible - CALL_MISSING, // function to call not provided - CALL_NOT_KNOWN, // apg service does not know what to do - APG_NOT_FOUND, // could not find APG installed - APG_AIDL_MISSING, // found APG but without AIDL interface + /** + * 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 } - public static enum ret { + private static enum ret { ERROR, // returned from AIDL RESULT, // returned from AIDL WARNINGS, // mixed AIDL and LOCAL ERRORS, // mixed AIDL and LOCAL - LOCAL_ERROR, // LOCAL error } /** @@ -160,7 +192,7 @@ public class ApgCon { if (!apg_service_found) { Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work"); error_list.add("(LOCAL) Could not find APG with AIDL interface, this probably won't work"); - local_error = error.APG_AIDL_MISSING; + result.putInt(ret.ERROR.name(), error.APG_AIDL_MISSING.ordinal()); } } } catch (PackageManager.NameNotFoundException e) { @@ -168,7 +200,7 @@ public class ApgCon { e.printStackTrace(); Log.e(TAG, "Could not find APG, is it installed?"); error_list.add("(LOCAL) Could not find APG, is it installed?"); - local_error = error.APG_NOT_FOUND; + result.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal()); } } @@ -297,18 +329,15 @@ public class ApgCon { private boolean call(String function, Bundle pArgs, Bundle pReturn) { - error_list.clear(); - warning_list.clear(); - if (!initialize()) { error_list.add("(LOCAL) Cannot bind to ApgService"); - local_error = error.CANNOT_BIND_TO_APG; + result.putInt(ret.ERROR.name(), error.CANNOT_BIND_TO_APG.ordinal()); return false; } if (function == null || function.length() == 0) { error_list.add("(LOCAL) Function to call missing"); - local_error = error.CALL_MISSING; + result.putInt(ret.ERROR.name(), error.CALL_MISSING.ordinal()); return false; } @@ -324,7 +353,7 @@ public class ApgCon { e.printStackTrace(); Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage()); error_list.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage()); - local_error = error.CALL_NOT_KNOWN; + result.putInt(ret.ERROR.name(), error.CALL_NOT_KNOWN.ordinal()); return false; } catch (InvocationTargetException e) { if (stacktraces) @@ -338,7 +367,7 @@ public class ApgCon { e.printStackTrace(); Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage()); error_list.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); - local_error = error.GENERIC; + result.putInt(ret.ERROR.name(), error.GENERIC.ordinal()); return false; } @@ -515,51 +544,22 @@ public class ApgCon { } /** - * Returns the type of error happened + * Get the numeric representation of the last error * *

- * Currently, two error types are possible: - *

    - *
  • ret.LOCAL_ERROR: An error that happened on the caller site. This - * might be something like connection to AIDL not possible or the funciton - * call not know by AIDL. This means, the instance is not set up correctly - * or prerequisites to use APG with AIDL are not met.
  • - *
  • ret.ERROR: Connection to APG was successful, and the call started but - * failed. Mostly this is because of wrong or missing parameters for APG.
  • - *
+ * 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 #get_next_error()}) for what + * errors >=100 mean. *

* - * @return the type of error that happend: ret.LOCAL_ERROR or ret.ERROR, or - * null if none happend + * @return the id of the error that happened */ - public ret get_error_type() { - if (local_error != null) { - return ret.LOCAL_ERROR; - } else if (result.containsKey(ret.ERROR.name())) { - return ret.ERROR; - } else { - return null; - } - } - - public error get_local_error() { - return local_error; - } - - public void clear_local_error() { - local_error = null; - } - - public int get_remote_error() { - if (result.containsKey(ret.ERROR.name())) { + public int get_error() { + if (result.containsKey(ret.ERROR.name())) return result.getInt(ret.ERROR.name()); - } else { + else return -1; - } - } - - public void clear_remote_error() { - result.remove(ret.ERROR.name()); } /** @@ -630,7 +630,6 @@ public class ApgCon { public void clear_errors() { error_list.clear(); result.remove(ret.ERROR.name()); - clear_local_error(); } /** From b5097b7a417b13c288adfbd1c0ea4f6d86715cf1 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 20:23:13 +0000 Subject: [PATCH 51/69] Some more verbose logs --- src/org/thialfihar/android/apg/ApgService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index c4a348cb4..b36b5cd0a 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -385,6 +385,7 @@ public class ApgService extends Service { InputData _in = new InputData(_inStream, 0); // XXX Size second param? OutputStream _out = new ByteArrayOutputStream(); + Log.v(TAG, "About to encrypt"); try { Apg.encrypt(getBaseContext(), // context _in, // input stream @@ -450,6 +451,7 @@ public class ApgService extends Service { InputStream 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(); + Log.v(TAG, "About to decrypt"); try { Apg.decrypt(getBaseContext(), in, out, _passphrase, null, // progress pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null // symmetric @@ -469,6 +471,7 @@ public class ApgService extends Service { } return false; } + Log.v(TAG, "Decrypted"); pReturn.putString(ret.RESULT.name(), out.toString()); return true; From 4b882fa90bd59765d27f8462c505315233d4475c Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:20 +0000 Subject: [PATCH 52/69] Other applications must user permission to read key details to connect to AIDL interface This is necessary, because upcoming version of the aidl-interface will be able to return fingerprints and user ids to applications. --- AndroidManifest.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a6580a57c..937eb488a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -195,7 +195,12 @@ android:configChanges="keyboardHidden|orientation|keyboard"/> - + From 6b7db8161a158e12344145815534f6552797cf6d Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:27 +0000 Subject: [PATCH 53/69] Don't query things we don't need --- src/org/thialfihar/android/apg/ApgService.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index b36b5cd0a..3fa88673f 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -6,7 +6,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -185,16 +184,9 @@ public class ApgService extends Service { String orderBy = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC"; - long now = new Date().getTime() / 1000; Cursor mCursor = qb.query(Apg.getDatabase().db(), new String[] { - KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0 - KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1 - UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2 - "(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " + "tmp." + Keys.KEY_RING_ID + " = " + KeyRings.TABLE_NAME - + "." + KeyRings._ID + " AND " + "tmp." + Keys.IS_REVOKED + " = '0' AND " + "tmp." + Keys.CAN_ENCRYPT + " = '1')", // 3 - "(SELECT COUNT(tmp." + Keys._ID + ") FROM " + Keys.TABLE_NAME + " AS tmp WHERE " + "tmp." + Keys.KEY_RING_ID + " = " + KeyRings.TABLE_NAME - + "." + KeyRings._ID + " AND " + "tmp." + Keys.IS_REVOKED + " = '0' AND " + "tmp." + Keys.CAN_ENCRYPT + " = '1' AND " + "tmp." - + Keys.CREATION + " <= '" + now + "' AND " + "(tmp." + Keys.EXPIRY + " IS NULL OR " + "tmp." + Keys.EXPIRY + " >= '" + now + "'))", // 4 + KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0 + UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1 }, KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?", new String[] { "" + Id.database.type_public }, null, null, orderBy); @@ -202,8 +194,8 @@ public class ApgService extends Service { Log.v(TAG, "going through installed user keys"); ArrayList _master_keys = new ArrayList(); while (mCursor.moveToNext()) { - long _cur_mkey = mCursor.getLong(1); - String _cur_user = mCursor.getString(2); + long _cur_mkey = mCursor.getLong(0); + String _cur_user = mCursor.getString(1); String _cur_fprint = Apg.getSmallFingerPrint(_cur_mkey); Log.v(TAG, "current user: " + _cur_user + " (" + _cur_fprint + ")"); From 1ec5fc05412c6d7019dd40497a81397752bee602 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:35 +0000 Subject: [PATCH 54/69] Allow to retrieve fingerprints and user ids through AIDL Update ApgCon and doc accordingly. Not very tested. --- .../thialfihar/android/apg/ApgService.java | 148 ++++++++++++------ .../thialfihar/android/apg/IApgService.aidl | 33 +++- .../thialfihar/android/apg/utils/ApgCon.java | 4 + 3 files changed, 136 insertions(+), 49 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 3fa88673f..20bd1b1e3 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -9,7 +9,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.Set; import org.thialfihar.android.apg.provider.KeyRings; import org.thialfihar.android.apg.provider.Keys; @@ -38,7 +37,7 @@ public class ApgService extends Service { NO_MATCHING_SECRET_KEY, PRIVATE_KEY_PASSPHRASE_WRONG, PRIVATE_KEY_PASSPHRASE_MISSING; - + public int shifted_ordinal() { return ordinal() + 100; } @@ -55,8 +54,8 @@ public class ApgService extends Service { 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 + PRIVATE_KEY_PASSPHRASE, // passphrase for encrypted private key + KEY_TYPE, // type of key (private or public) } /** all things that might be returned */ @@ -64,12 +63,13 @@ public class ApgService extends Service { ERRORS, // string array list with errors WARNINGS, // string array list with warnings ERROR, // numeric error - RESULT - // en-/decrypted + RESULT, // en-/decrypted + FINGERPRINTS, // fingerprints of keys + USER_IDS, // user ids } /** required arguments for each AIDL function */ - private static final HashMap> FUNCTIONS_REQUIRED_ARGS = new HashMap>(); + private static final HashMap> FUNCTIONS_REQUIRED_ARGS = new HashMap>(); static { HashSet args = new HashSet(); args.add(arg.SYMMETRIC_PASSPHRASE); @@ -85,10 +85,14 @@ public class ApgService extends Service { args.add(arg.MESSAGE); FUNCTIONS_REQUIRED_ARGS.put("decrypt", args); + args = new HashSet(); + args.add(arg.KEY_TYPE); + FUNCTIONS_REQUIRED_ARGS.put("get_keys", args); + } /** optional arguments for each AIDL function */ - private static final HashMap> FUNCTIONS_OPTIONAL_ARGS = new HashMap>(); + private static final HashMap> FUNCTIONS_OPTIONAL_ARGS = new HashMap>(); static { HashSet args = new HashSet(); args.add(arg.ENCRYPTION_ALGORYTHM); @@ -166,6 +170,26 @@ public class ApgService extends Service { return 0; } + private static Cursor get_key_entries(HashMap 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 * @@ -176,20 +200,14 @@ public class ApgService extends Service { */ private static long[] get_master_key(ArrayList search_keys, Bundle pReturn) { - 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 = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC"; - - Cursor mCursor = qb.query(Apg.getDatabase().db(), new String[] { + HashMap qParams = new HashMap(); + qParams.put("columns", new String[] { KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 0 UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 1 - }, KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?", new String[] { - "" + Id.database.type_public - }, null, null, orderBy); + }); + qParams.put("key_type", Id.database.type_public); + + Cursor mCursor = get_key_entries(qParams); Log.v(TAG, "going through installed user keys"); ArrayList _master_keys = new ArrayList(); @@ -235,27 +253,30 @@ public class ApgService extends Service { * the bundle to add default parameters to if missing */ 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 _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"); + Iterator _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()); } - } 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 */ private void check_required_args(String function, Bundle pArgs, Bundle pReturn) { - Iterator _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); + if (FUNCTIONS_REQUIRED_ARGS.containsKey(function)) { + Iterator _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); + } } } } @@ -306,8 +329,14 @@ public class ApgService extends Service { * the bundle to write warnings to */ private void check_unknown_args(String function, Bundle pArgs, Bundle pReturn) { - HashSet all_args = new HashSet(FUNCTIONS_REQUIRED_ARGS.get(function)); - all_args.addAll(FUNCTIONS_OPTIONAL_ARGS.get(function)); + + HashSet all_args = new HashSet(); + 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 _unknown_args = new ArrayList(); Iterator _iter = pArgs.keySet().iterator(); @@ -415,6 +444,32 @@ public class ApgService extends Service { private final IApgService.Stub mBinder = new IApgService.Stub() { + public boolean get_keys(Bundle pArgs, Bundle pReturn) { + + prepare_args("get_keys", pArgs, pReturn); + + HashMap qParams = new HashMap(); + 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 fprints = new ArrayList(); + ArrayList ids = new ArrayList(); + 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) { if (!prepare_args("encrypt_with_public_key", pArgs, pReturn)) { return false; @@ -468,5 +523,6 @@ public class ApgService extends Service { pReturn.putString(ret.RESULT.name(), out.toString()); return true; } + }; } diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index c35e82df7..0eb1307b8 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -1,7 +1,7 @@ package org.thialfihar.android.apg; interface IApgService { - + /* All functions fill the return_vals Bundle with the following keys: * * ArrayList "WARNINGS" = Warnings, if any @@ -14,7 +14,12 @@ interface IApgService { * 104: Private key's passphrase missing */ - /* Encryption function's arguments + /* ******************************************************* + * Encrypting and decrypting + * ********************************************************/ + + + /* All encryption function's arguments * * Bundle params' keys: * (optional/required) @@ -82,5 +87,27 @@ interface IApgService { * Bundle return_vals: * 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); + } \ No newline at end of file diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index b80b66daa..225320108 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -327,6 +327,10 @@ public class ApgCon { 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) { if (!initialize()) { From efc5575d56e4888f8335a76a7a44472aa53965ea Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:44 +0000 Subject: [PATCH 55/69] Change the way the complete result can be retrieved --- .../thialfihar/android/apg/utils/ApgCon.java | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 225320108..9a0ccb44b 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -327,10 +327,6 @@ public class ApgCon { 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) { if (!initialize()) { @@ -603,8 +599,8 @@ public class ApgCon { * Get the result * *

- * This gets your result. After doing anything with APG, you get the output - * with this function + * This gets your result. After doing an encryption or decryption with APG, + * you get the output with this function. *

*

* Note, that when your last remote call is unsuccessful, the result will @@ -620,11 +616,35 @@ public class ApgCon { * * @see #reset() * @see #clear_result() + * @see #get_result_bundle() */ public String get_result() { return result.getString(ret.RESULT.name()); } + /** + * Get the result bundle + * + *

+ * Unlike {@link #get_result()}, 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. + *

+ *

+ * For warnings and errors it is suggested to use the functions that are + * provided here, namely {@link #get_error()}, {@link #get_next_error()}, + * {@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. + *

+ * + * @return the complete result-bundle of the last call to apg + */ + public Bundle get_result_bundle() { + return result; + } + /** * Clears all unfetched errors * From cb4f1933d55abeda08623115464e393a886b8032 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:51 +0000 Subject: [PATCH 56/69] Dont remove result and warnings from result Some more debug output, too --- src/org/thialfihar/android/apg/ApgService.java | 2 ++ src/org/thialfihar/android/apg/utils/ApgCon.java | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 20bd1b1e3..87437e629 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -380,6 +380,7 @@ public class ApgService extends Service { /* return if errors happened */ if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { + Log.v(TAG, "Errors after preparing, not executing "+call); pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.shifted_ordinal()); return false; } @@ -460,6 +461,7 @@ public class ApgService extends Service { ArrayList fprints = new ArrayList(); ArrayList ids = new ArrayList(); while (mCursor.moveToNext()) { + Log.v(TAG, "adding key "+Apg.getSmallFingerPrint(mCursor.getLong(0))); fprints.add(Apg.getSmallFingerPrint(mCursor.getLong(0))); ids.add(mCursor.getString(1)); } diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 9a0ccb44b..0388f4d18 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -345,8 +345,6 @@ public class ApgCon { Boolean success = (Boolean) IApgService.class.getMethod(function, Bundle.class, Bundle.class).invoke(apgService, pArgs, pReturn); error_list.addAll(pReturn.getStringArrayList(ret.ERRORS.name())); warning_list.addAll(pReturn.getStringArrayList(ret.WARNINGS.name())); - pReturn.remove(ret.ERRORS.name()); - pReturn.remove(ret.WARNINGS.name()); return success; } catch (NoSuchMethodException e) { if (stacktraces) From 66263ab6e3d9ce3a67e5f10496c0b99a0dcd1752 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:59 +0000 Subject: [PATCH 57/69] Allow to return itself on callback --- .../thialfihar/android/apg/utils/ApgCon.java | 68 +++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 0388f4d18..09e183a96 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -54,7 +54,11 @@ public class ApgCon { if (callback_object != null && callback_method != null) { try { Log.d(TAG, "About to execute callback"); - callback_object.getClass().getMethod(callback_method).invoke(callback_object); + if (callback_return_self) { + callback_object.getClass().getMethod(callback_method, ApgCon.class).invoke(callback_object, get_self()); + } else { + callback_object.getClass().getMethod(callback_method).invoke(callback_object); + } Log.d(TAG, "Callback executed"); } catch (NoSuchMethodException e) { if (stacktraces) @@ -86,6 +90,8 @@ public class ApgCon { private boolean async_running = false; private Object callback_object; private String callback_method; + public static final boolean default_callback_return_self = false; + private boolean callback_return_self = default_callback_return_self; private final Bundle result = new Bundle(); private final Bundle args = new Bundle(); @@ -718,10 +724,38 @@ public class ApgCon { * The object, which has the public method meth * @param meth * Method to call on the object obj + * + * @see #set_callback(Object, String, boolean) */ public void set_callback(Object obj, String meth) { + set_callback(obj, meth, default_callback_return_self); + } + + /** + * Set a callback and whether to return self as a additional parameter + * + *

+ * This does the same as {@link #set_callback(Object, String)} with one + * Additionally parameter return_self. + *

+ *

+ * The additional parameter controls, whether to return itself as a + * parameter to the callback method meth (in order to go on working after + * async execution has finished). This means, your callback method must have + * one parameter of the type ApgCon. + *

+ * + * @param obj + * The object, which has the public method meth + * @param meth + * Method to call on the object obj + * @param return_self + * Whether to return itself as an parameter to meth + */ + public void set_callback(Object obj, String meth, boolean return_self) { set_callback_object(obj); set_callback_method(meth); + set_callback_return_self(return_self); } /** @@ -746,6 +780,17 @@ public class ApgCon { callback_method = meth; } + /** + * Set whether to return self on callback + * + * @param arg + * set results as param for callback method + * @see #set_callback(Object, String) + */ + public void set_callback_return_self(boolean arg) { + callback_return_self = arg; + } + /** * Clears any callback object * @@ -765,13 +810,24 @@ public class ApgCon { } /** - * Clears any callback method and object + * Sets to default value of whether to return self on callback + * + * @see #set_callback(Object, String, boolean) + * @see #default_callback_return_self + */ + public void clear_callback_return_self() { + callback_return_self = default_callback_return_self; + } + + /** + * Clears anything related to callback * * @see #set_callback(Object, String) */ public void clear_callback() { clear_callback_object(); clear_callback_method(); + clear_callback_return_self(); } /** @@ -785,6 +841,7 @@ public class ApgCon { * @return true, if an async task is still running, false otherwise * * @see #call_async(String) + * */ public boolean is_running() { return async_running; @@ -811,9 +868,12 @@ public class ApgCon { clear_errors(); clear_warnings(); clear_args(); - clear_callback_object(); - clear_callback_method(); + clear_callback(); result.clear(); } + public ApgCon get_self() { + return this; + } + } From 3372e571577481bfa62140a131f5c0dea35936fc Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:37:06 +0000 Subject: [PATCH 58/69] Allow to retrieve connection status This tells, if a connection to APG *might* be possible (right version of APG found) --- .../thialfihar/android/apg/utils/ApgCon.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 09e183a96..5572dcdb5 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -29,7 +29,7 @@ import org.thialfihar.android.apg.IApgService; *

* * @author Markus Doits - * @version 0.9 + * @version 0.9.1 * */ public class ApgCon { @@ -87,6 +87,7 @@ public class ApgCon { private final static int api_version = 1; // aidl api-version it expects private final Context mContext; + private final error connection_status; private boolean async_running = false; private Object callback_object; private String callback_method; @@ -121,6 +122,7 @@ public class ApgCon { * */ public static enum error { + NO_ERROR, /** * generic error */ @@ -144,7 +146,8 @@ public class ApgCon { /** * found APG but without AIDL interface */ - APG_AIDL_MISSING + APG_AIDL_MISSING, + APG_API_MISSMATCH } private static enum ret { @@ -169,12 +172,14 @@ public class ApgCon { Log.v(TAG, "EncryptionService created"); mContext = ctx; + error tmp_connection_status = null; try { Log.v(TAG, "Searching for the right APG version"); ServiceInfo apg_services[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg", PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services; if (apg_services == null) { Log.e(TAG, "Could not fetch services"); + tmp_connection_status = error.GENERIC; } else { boolean apg_service_found = false; for (ServiceInfo inf : apg_services) { @@ -185,12 +190,15 @@ public class ApgCon { Log.w(TAG, "Could not determine ApgService API"); Log.w(TAG, "This probably won't work!"); warning_list.add("(LOCAL) Could not determine ApgService API"); + tmp_connection_status = 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!"); warning_list.add("(LOCAL) Found ApgService API version" + inf.metaData.getInt("api_version") + " but exspected " + api_version); + tmp_connection_status = error.APG_API_MISSMATCH; } else { Log.v(TAG, "Found api_version " + api_version + ", everything should work"); + tmp_connection_status = error.NO_ERROR; } } } @@ -199,6 +207,7 @@ public class ApgCon { Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work"); error_list.add("(LOCAL) Could not find APG with AIDL interface, this probably won't work"); result.putInt(ret.ERROR.name(), error.APG_AIDL_MISSING.ordinal()); + tmp_connection_status = error.APG_NOT_FOUND; } } } catch (PackageManager.NameNotFoundException e) { @@ -207,7 +216,10 @@ public class ApgCon { Log.e(TAG, "Could not find APG, is it installed?"); error_list.add("(LOCAL) Could not find APG, is it installed?"); result.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal()); + tmp_connection_status = error.APG_NOT_FOUND; } + + connection_status = tmp_connection_status; } /** try to connect to the apg service */ @@ -648,6 +660,10 @@ public class ApgCon { public Bundle get_result_bundle() { return result; } + + public error get_connection_status() { + return connection_status; + } /** * Clears all unfetched errors From 1036eb6bd5f89844cf71f171d89f48c342aee217 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 25 Jan 2011 19:38:56 +0000 Subject: [PATCH 59/69] Log stacktraces the android way --- .../thialfihar/android/apg/utils/ApgCon.java | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 5572dcdb5..3e0b75524 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -34,11 +34,6 @@ import org.thialfihar.android.apg.IApgService; */ public class ApgCon { - /** - * Put stacktraces into the log? - */ - private final static boolean stacktraces = true; - private class call_async extends AsyncTask { @Override @@ -61,21 +56,15 @@ public class ApgCon { } Log.d(TAG, "Callback executed"); } catch (NoSuchMethodException e) { - if (stacktraces) - e.printStackTrace(); - Log.w(TAG, "Exception in callback: Method '" + callback_method + "' not found"); + Log.w(TAG, "Exception in callback: Method '" + callback_method + "' not found", e); warning_list.add("(LOCAL) Could not execute callback, method '" + callback_method + "()' not found"); } catch (InvocationTargetException e) { - if (stacktraces) - e.printStackTrace(); Throwable orig = e.getTargetException(); - Log.w(TAG, "Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" + orig.getMessage()); + Log.w(TAG, "Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" + orig.getMessage(), orig); warning_list.add("(LOCAL) Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" + orig.getMessage()); } catch (Exception e) { - if (stacktraces) - e.printStackTrace(); - Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage()); + Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage(), e); warning_list.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); } } @@ -211,9 +200,7 @@ public class ApgCon { } } } catch (PackageManager.NameNotFoundException e) { - if (stacktraces) - e.printStackTrace(); - Log.e(TAG, "Could not find APG, is it installed?"); + Log.e(TAG, "Could not find APG, is it installed?", e); error_list.add("(LOCAL) Could not find APG, is it installed?"); result.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal()); tmp_connection_status = error.APG_NOT_FOUND; @@ -234,9 +221,7 @@ public class ApgCon { try { mContext.bindService(new Intent(IApgService.class.getName()), apgConnection, Context.BIND_AUTO_CREATE); } catch (Exception e) { - if (stacktraces) - e.printStackTrace(); - Log.v(TAG, "could not bind APG service"); + Log.e(TAG, "could not bind APG service", e); return false; } @@ -365,23 +350,17 @@ public class ApgCon { warning_list.addAll(pReturn.getStringArrayList(ret.WARNINGS.name())); return success; } catch (NoSuchMethodException e) { - if (stacktraces) - e.printStackTrace(); - Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage()); + Log.e(TAG, "Remote call not known (" + function + "): " + e.getMessage(), e); error_list.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage()); result.putInt(ret.ERROR.name(), error.CALL_NOT_KNOWN.ordinal()); return false; } catch (InvocationTargetException e) { - if (stacktraces) - e.printStackTrace(); Throwable orig = e.getTargetException(); - Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage()); + Log.w(TAG, "Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage(), orig); error_list.add("(LOCAL) Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage()); return false; } catch (Exception e) { - if (stacktraces) - e.printStackTrace(); - Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage()); + Log.e(TAG, "Generic error (" + e.getClass() + "): " + e.getMessage(), e); error_list.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); result.putInt(ret.ERROR.name(), error.GENERIC.ordinal()); return false; From 7278932990d1014bb635905de05ade429f826849 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 25 Jan 2011 19:39:07 +0000 Subject: [PATCH 60/69] Make callback use an interface 'the java way'_tm --- .../thialfihar/android/apg/utils/ApgCon.java | 211 +++--------------- .../android/apg/utils/ApgConInterface.java | 9 + 2 files changed, 42 insertions(+), 178 deletions(-) create mode 100644 src/org/thialfihar/android/apg/utils/ApgConInterface.java diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 3e0b75524..8a11b8cac 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -15,6 +15,7 @@ import android.os.IBinder; import android.util.Log; import org.thialfihar.android.apg.IApgService; +import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener; /** * A APG-AIDL-Wrapper @@ -29,7 +30,7 @@ import org.thialfihar.android.apg.IApgService; *

* * @author Markus Doits - * @version 0.9.1 + * @version 0.9.9 * */ public class ApgCon { @@ -43,31 +44,10 @@ public class ApgCon { return null; } - protected void onPostExecute(Void result) { + protected void onPostExecute(Void res) { Log.d(TAG, "Async execution finished"); async_running = false; - if (callback_object != null && callback_method != null) { - try { - Log.d(TAG, "About to execute callback"); - if (callback_return_self) { - callback_object.getClass().getMethod(callback_method, ApgCon.class).invoke(callback_object, get_self()); - } else { - callback_object.getClass().getMethod(callback_method).invoke(callback_object); - } - Log.d(TAG, "Callback executed"); - } catch (NoSuchMethodException e) { - Log.w(TAG, "Exception in callback: Method '" + callback_method + "' not found", e); - warning_list.add("(LOCAL) Could not execute callback, method '" + callback_method + "()' not found"); - } catch (InvocationTargetException e) { - Throwable orig = e.getTargetException(); - Log.w(TAG, "Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" + orig.getMessage(), orig); - warning_list.add("(LOCAL) Exception of type '" + orig.getClass() + "' in callback's method '" + callback_method + "()':" - + orig.getMessage()); - } catch (Exception e) { - Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage(), e); - warning_list.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); - } - } + } } @@ -78,10 +58,7 @@ public class ApgCon { private final Context mContext; private final error connection_status; private boolean async_running = false; - private Object callback_object; - private String callback_method; - public static final boolean default_callback_return_self = false; - private boolean callback_return_self = default_callback_return_self; + private OnCallFinishListener onCallFinishListener; private final Bundle result = new Bundle(); private final Bundle args = new Bundle(); @@ -205,7 +182,7 @@ public class ApgCon { result.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal()); tmp_connection_status = error.APG_NOT_FOUND; } - + connection_status = tmp_connection_status; } @@ -282,6 +259,7 @@ public class ApgCon { *
  • start connection to the remote interface (if not already connected)
  • *
  • call the passed function with all set up parameters synchronously
  • *
  • set up everything to retrieve the result and/or warnings/errors
  • + *
  • call the callback if provided * *

    * @@ -296,9 +274,21 @@ public class ApgCon { * * @see #call_async(String) * @see #set_arg(String, String) + * @see #set_onCallFinishListener(OnCallFinishListener) */ public boolean call(String function) { - return this.call(function, args, result); + boolean success = this.call(function, args, result); + if (onCallFinishListener != null) { + try { + Log.d(TAG, "About to execute callback"); + onCallFinishListener.onCallFinish(result); + Log.d(TAG, "Callback executed"); + } catch (Exception e) { + Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage(), e); + warning_list.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); + } + } + return success; } /** @@ -314,7 +304,7 @@ public class ApgCon { * To see whether the task is finished, you have to possibilities: *
      *
    • In your thread, poll {@link #is_running()}
    • - *
    • Supply a callback with {@link #set_callback(Object, String)}
    • + *
    • Supply a callback with {@link #set_onCallFinishListener(OnCallFinishListener)}
    • *
    *

    * @@ -323,7 +313,7 @@ public class ApgCon { * * @see #call(String) * @see #is_running() - * @see #set_callback(Object, String) + * @see #set_onCallFinishListener(OnCallFinishListener) */ public void call_async(String function) { async_running = true; @@ -484,7 +474,7 @@ public class ApgCon { * {@link #set_arg(String, String)} functions, is cleared. *

    *

    - * Note, that any warning, error, callback, result etc. is not cleared with + * Note, that any warning, error, callback, result, etc. is not cleared with * this. *

    * @@ -639,7 +629,7 @@ public class ApgCon { public Bundle get_result_bundle() { return result; } - + public error get_connection_status() { return connection_status; } @@ -675,154 +665,23 @@ public class ApgCon { } /** - * Set a callback object and method - * - *

    - * After an async execution is finished, obj.meth() will be called. You can - * use this in order to get notified, when encrypting/decrypting of long - * data finishes and do not have to poll {@link #is_running()} in your - * thread. Note, that if the call of the method fails for whatever reason, - * you won't get notified in any way - so you still should check - * {@link #is_running()} from time to time. - *

    - * - *

    - * It produces a warning fetchable with {@link #get_next_warning()} when the - * callback fails. - *

    - * - *
    -     * 
    -     * .... your class ...
    -     * public void callback() {
    -     *   // do something after encryption finished
    -     * }
    -     * 
    -     * public void encrypt() {
    -     *   ApgCon mEnc = new ApgCon(context);
    -     *   // set parameters
    -     *   mEnc.set_arg(key, value);
    -     *   ...
    -     *   
    -     *   // set callback object and method 
    -     *   mEnc.set_callback( this, "callback" );
    -     *   
    -     *   // start asynchronous call
    -     *   mEnc.call_async( call );
    -     *   
    -     *   // when the call_async finishes, the method "callback()" will be called automatically
    -     * }
    -     * 
    -     * 
    - * - * @param obj - * The object, which has the public method meth - * @param meth - * Method to call on the object obj - * - * @see #set_callback(Object, String, boolean) - */ - public void set_callback(Object obj, String meth) { - set_callback(obj, meth, default_callback_return_self); - } - - /** - * Set a callback and whether to return self as a additional parameter - * - *

    - * This does the same as {@link #set_callback(Object, String)} with one - * Additionally parameter return_self. - *

    - *

    - * The additional parameter controls, whether to return itself as a - * parameter to the callback method meth (in order to go on working after - * async execution has finished). This means, your callback method must have - * one parameter of the type ApgCon. - *

    - * - * @param obj - * The object, which has the public method meth - * @param meth - * Method to call on the object obj - * @param return_self - * Whether to return itself as an parameter to meth - */ - public void set_callback(Object obj, String meth, boolean return_self) { - set_callback_object(obj); - set_callback_method(meth); - set_callback_return_self(return_self); - } - - /** - * Set a callback object + * Set a callback listener when call to AIDL finishes * * @param obj * a object to call back after async execution - * @see #set_callback(Object, String) + * @see ApgConInterface */ - public void set_callback_object(Object obj) { - callback_object = obj; - } - - /** - * Set a callback method - * - * @param meth - * a method to call on a callback object after async execution - * @see #set_callback(Object, String) - */ - public void set_callback_method(String meth) { - callback_method = meth; - } - - /** - * Set whether to return self on callback - * - * @param arg - * set results as param for callback method - * @see #set_callback(Object, String) - */ - public void set_callback_return_self(boolean arg) { - callback_return_self = arg; + public void set_onCallFinishListener(OnCallFinishListener lis) { + onCallFinishListener = lis; } /** * Clears any callback object * - * @see #set_callback(Object, String) + * @see #set_onCallFinishListener(OnCallFinishListener) */ - public void clear_callback_object() { - callback_object = null; - } - - /** - * Clears any callback method - * - * @see #set_callback(Object, String) - */ - public void clear_callback_method() { - callback_method = null; - } - - /** - * Sets to default value of whether to return self on callback - * - * @see #set_callback(Object, String, boolean) - * @see #default_callback_return_self - */ - public void clear_callback_return_self() { - callback_return_self = default_callback_return_self; - } - - /** - * Clears anything related to callback - * - * @see #set_callback(Object, String) - */ - public void clear_callback() { - clear_callback_object(); - clear_callback_method(); - clear_callback_return_self(); + public void clear_onCallFinishListener() { + onCallFinishListener = null; } /** @@ -855,7 +714,7 @@ public class ApgCon { * Note, that when an async execution ({@link #call_async(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 on finishing the async execution any defined callback will + * reseted, so on finishing the execution any before defined callback will * NOT BE TRIGGERED. *

    */ @@ -863,12 +722,8 @@ public class ApgCon { clear_errors(); clear_warnings(); clear_args(); - clear_callback(); + clear_onCallFinishListener(); result.clear(); } - public ApgCon get_self() { - return this; - } - } diff --git a/src/org/thialfihar/android/apg/utils/ApgConInterface.java b/src/org/thialfihar/android/apg/utils/ApgConInterface.java new file mode 100644 index 000000000..57ef0d9c4 --- /dev/null +++ b/src/org/thialfihar/android/apg/utils/ApgConInterface.java @@ -0,0 +1,9 @@ +package org.thialfihar.android.apg.utils; + +import android.os.Bundle; + +public interface ApgConInterface { + public static interface OnCallFinishListener { + public abstract void onCallFinish(Bundle result); + } +} From c497e48817141589624b933cffb6e9e714942818 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 25 Jan 2011 19:51:35 +0000 Subject: [PATCH 61/69] Define interface without imports --- src/org/thialfihar/android/apg/utils/ApgConInterface.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgConInterface.java b/src/org/thialfihar/android/apg/utils/ApgConInterface.java index 57ef0d9c4..27254fe95 100644 --- a/src/org/thialfihar/android/apg/utils/ApgConInterface.java +++ b/src/org/thialfihar/android/apg/utils/ApgConInterface.java @@ -1,9 +1,7 @@ package org.thialfihar.android.apg.utils; -import android.os.Bundle; - public interface ApgConInterface { public static interface OnCallFinishListener { - public abstract void onCallFinish(Bundle result); + public abstract void onCallFinish(android.os.Bundle result); } } From 3be076d0245ceddb483e9972ea0662a8de665e52 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 18 May 2011 18:19:47 +0000 Subject: [PATCH 62/69] Little better log-managing for release-versions of ApgCon --- .../thialfihar/android/apg/utils/ApgCon.java | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 8a11b8cac..7ab2ea842 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2011 Markus Doits + * + * 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.utils; import java.lang.reflect.InvocationTargetException; @@ -34,18 +50,20 @@ import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener; * */ public class ApgCon { + private static final boolean LOCAL_LOGV = true; + private static final boolean LOCAL_LOGD = true; private class call_async extends AsyncTask { @Override protected Void doInBackground(String... arg) { - Log.d(TAG, "Async execution starting"); + if( LOCAL_LOGD ) Log.d(TAG, "Async execution starting"); call(arg[0]); return null; } protected void onPostExecute(Void res) { - Log.d(TAG, "Async execution finished"); + if( LOCAL_LOGD ) Log.d(TAG, "Async execution finished"); async_running = false; } @@ -71,12 +89,12 @@ public class ApgCon { /** Set apgService accordingly to connection status */ private ServiceConnection apgConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { - Log.d(TAG, "IApgService bound to apgService"); + if( LOCAL_LOGD ) Log.d(TAG, "IApgService bound to apgService"); apgService = IApgService.Stub.asInterface(service); } public void onServiceDisconnected(ComponentName className) { - Log.d(TAG, "IApgService disconnected"); + if( LOCAL_LOGD ) Log.d(TAG, "IApgService disconnected"); apgService = null; } }; @@ -135,12 +153,12 @@ public class ApgCon { * the running context */ public ApgCon(Context ctx) { - Log.v(TAG, "EncryptionService created"); + if( LOCAL_LOGV ) Log.v(TAG, "EncryptionService created"); mContext = ctx; error tmp_connection_status = null; try { - Log.v(TAG, "Searching for the right APG version"); + if( LOCAL_LOGV ) Log.v(TAG, "Searching for the right APG version"); ServiceInfo apg_services[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg", PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services; if (apg_services == null) { @@ -149,7 +167,7 @@ public class ApgCon { } else { boolean apg_service_found = false; for (ServiceInfo inf : apg_services) { - Log.v(TAG, "Found service of APG: " + inf.name); + if( LOCAL_LOGV ) Log.v(TAG, "Found service of APG: " + inf.name); if (inf.name.equals("org.thialfihar.android.apg.ApgService")) { apg_service_found = true; if (inf.metaData == null) { @@ -163,7 +181,7 @@ public class ApgCon { warning_list.add("(LOCAL) Found ApgService API version" + inf.metaData.getInt("api_version") + " but exspected " + api_version); tmp_connection_status = error.APG_API_MISSMATCH; } else { - Log.v(TAG, "Found api_version " + api_version + ", everything should work"); + if( LOCAL_LOGV ) Log.v(TAG, "Found api_version " + api_version + ", everything should work"); tmp_connection_status = error.NO_ERROR; } } @@ -188,10 +206,10 @@ public class ApgCon { /** try to connect to the apg service */ private boolean connect() { - Log.v(TAG, "trying to bind the apgService to context"); + if( LOCAL_LOGV ) Log.v(TAG, "trying to bind the apgService to context"); if (apgService != null) { - Log.v(TAG, "allready connected"); + if( LOCAL_LOGV ) Log.v(TAG, "allready connected"); return true; } @@ -204,12 +222,12 @@ public class ApgCon { int wait_count = 0; while (apgService == null && wait_count++ < 15) { - Log.v(TAG, "sleeping 1 second to wait for apg"); + if( LOCAL_LOGV ) Log.v(TAG, "sleeping 1 second to wait for apg"); android.os.SystemClock.sleep(1000); } if (wait_count >= 15) { - Log.v(TAG, "slept waiting for nothing!"); + if( LOCAL_LOGV ) Log.v(TAG, "slept waiting for nothing!"); return false; } @@ -231,7 +249,7 @@ public class ApgCon { *

    */ public void disconnect() { - Log.v(TAG, "disconnecting apgService"); + if( LOCAL_LOGV ) Log.v(TAG, "disconnecting apgService"); if (apgService != null) { mContext.unbindService(apgConnection); apgService = null; @@ -241,7 +259,7 @@ public class ApgCon { private boolean initialize() { if (apgService == null) { if (!connect()) { - Log.v(TAG, "connection to apg service failed"); + if( LOCAL_LOGV ) Log.v(TAG, "connection to apg service failed"); return false; } } @@ -280,9 +298,9 @@ public class ApgCon { boolean success = this.call(function, args, result); if (onCallFinishListener != null) { try { - Log.d(TAG, "About to execute callback"); + if( LOCAL_LOGD ) Log.d(TAG, "About to execute callback"); onCallFinishListener.onCallFinish(result); - Log.d(TAG, "Callback executed"); + if( LOCAL_LOGD ) Log.d(TAG, "Callback executed"); } catch (Exception e) { Log.w(TAG, "Exception on callback: (" + e.getClass() + ") " + e.getMessage(), e); warning_list.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); From 6502e58c26cddc8472b6b46932250eb1fca88156 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 5 Jun 2011 19:05:18 +0000 Subject: [PATCH 63/69] Possibility to not compile Log.d and Log.v in --- .../thialfihar/android/apg/ApgService.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 87437e629..34248c809 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -23,10 +23,12 @@ import android.util.Log; public class ApgService extends Service { private final static String TAG = "ApgService"; + private static final boolean LOCAL_LOGV = true; + private static final boolean LOCAL_LOGD = true; @Override public IBinder onBind(Intent intent) { - Log.d(TAG, "bound"); + if( LOCAL_LOGD ) Log.d(TAG, "bound"); return mBinder; } @@ -209,20 +211,20 @@ public class ApgService extends Service { Cursor mCursor = get_key_entries(qParams); - Log.v(TAG, "going through installed user keys"); + if( LOCAL_LOGV ) Log.v(TAG, "going through installed user keys"); ArrayList _master_keys = new ArrayList(); while (mCursor.moveToNext()) { long _cur_mkey = mCursor.getLong(0); String _cur_user = mCursor.getString(1); String _cur_fprint = Apg.getSmallFingerPrint(_cur_mkey); - Log.v(TAG, "current user: " + _cur_user + " (" + _cur_fprint + ")"); + if( LOCAL_LOGV ) Log.v(TAG, "current user: " + _cur_user + " (" + _cur_fprint + ")"); if (search_keys.contains(_cur_fprint) || search_keys.contains(_cur_user)) { - Log.v(TAG, "master key found for: " + _cur_fprint); + if( LOCAL_LOGV ) Log.v(TAG, "master key found for: " + _cur_fprint); _master_keys.add(_cur_mkey); search_keys.remove(_cur_fprint); } else { - Log.v(TAG, "Installed key " + _cur_fprint + " is not in the list of public keys to encrypt with"); + if( LOCAL_LOGV ) Log.v(TAG, "Installed key " + _cur_fprint + " is not in the list of public keys to encrypt with"); } } mCursor.close(); @@ -368,23 +370,23 @@ public class ApgService extends Service { /* add default arguments if missing */ add_default_arguments(call, pArgs); - Log.v(TAG, "add_default_arguments"); + if( LOCAL_LOGV ) Log.v(TAG, "add_default_arguments"); /* check for required arguments */ check_required_args(call, pArgs, pReturn); - Log.v(TAG, "check_required_args"); + if( LOCAL_LOGV ) Log.v(TAG, "check_required_args"); /* check for unknown arguments and add to warning if found */ check_unknown_args(call, pArgs, pReturn); - Log.v(TAG, "check_unknown_args"); + if( LOCAL_LOGV ) Log.v(TAG, "check_unknown_args"); /* return if errors happened */ if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { - Log.v(TAG, "Errors after preparing, not executing "+call); + if( LOCAL_LOGV ) Log.v(TAG, "Errors after preparing, not executing "+call); pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.shifted_ordinal()); return false; } - Log.v(TAG, "error return"); + if( LOCAL_LOGV ) Log.v(TAG, "error return"); return true; } @@ -395,7 +397,7 @@ public class ApgService extends Service { if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) { ArrayList _list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name()); ArrayList _pub_keys = new ArrayList(); - Log.v(TAG, "Long size: " + _list.size()); + if( LOCAL_LOGV ) Log.v(TAG, "Long size: " + _list.size()); Iterator _iter = _list.iterator(); while (_iter.hasNext()) { _pub_keys.add(_iter.next()); @@ -407,7 +409,7 @@ public class ApgService extends Service { InputData _in = new InputData(_inStream, 0); // XXX Size second param? OutputStream _out = new ByteArrayOutputStream(); - Log.v(TAG, "About to encrypt"); + if( LOCAL_LOGV ) Log.v(TAG, "About to encrypt"); try { Apg.encrypt(getBaseContext(), // context _in, // input stream @@ -438,7 +440,7 @@ public class ApgService extends Service { } return false; } - Log.v(TAG, "Encrypted"); + if( LOCAL_LOGV ) Log.v(TAG, "Encrypted"); pReturn.putString(ret.RESULT.name(), _out.toString()); return true; } @@ -461,7 +463,7 @@ public class ApgService extends Service { ArrayList fprints = new ArrayList(); ArrayList ids = new ArrayList(); while (mCursor.moveToNext()) { - Log.v(TAG, "adding key "+Apg.getSmallFingerPrint(mCursor.getLong(0))); + if( LOCAL_LOGV ) Log.v(TAG, "adding key "+Apg.getSmallFingerPrint(mCursor.getLong(0))); fprints.add(Apg.getSmallFingerPrint(mCursor.getLong(0))); ids.add(mCursor.getString(1)); } @@ -500,7 +502,7 @@ public class ApgService extends Service { InputStream 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(); - Log.v(TAG, "About to decrypt"); + if( LOCAL_LOGV ) Log.v(TAG, "About to decrypt"); try { Apg.decrypt(getBaseContext(), in, out, _passphrase, null, // progress pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null // symmetric @@ -520,7 +522,7 @@ public class ApgService extends Service { } return false; } - Log.v(TAG, "Decrypted"); + if( LOCAL_LOGV ) Log.v(TAG, "Decrypted"); pReturn.putString(ret.RESULT.name(), out.toString()); return true; From 24205b8dbc6487ee066fec07c9c0840a3be30bb7 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 5 Jun 2011 19:05:57 +0000 Subject: [PATCH 64/69] Cleanup of code, AIDL-calls renamed! --- .../thialfihar/android/apg/ApgService.java | 316 ++++++++-------- .../thialfihar/android/apg/IApgService.aidl | 48 +-- .../thialfihar/android/apg/utils/ApgCon.java | 353 +++++++++--------- 3 files changed, 355 insertions(+), 362 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 34248c809..0a25c6055 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -40,7 +40,7 @@ public class ApgService extends Service { PRIVATE_KEY_PASSPHRASE_WRONG, PRIVATE_KEY_PASSPHRASE_MISSING; - public int shifted_ordinal() { + public int shiftedOrdinal() { return ordinal() + 100; } } @@ -90,7 +90,6 @@ public class ApgService extends Service { args = new HashSet(); args.add(arg.KEY_TYPE); FUNCTIONS_REQUIRED_ARGS.put("get_keys", args); - } /** optional arguments for each AIDL function */ @@ -124,21 +123,7 @@ public class ApgService extends Service { FUNCTIONS_DEFAULTS.put(arg.COMPRESSION, "getDefaultMessageCompression"); } - /** a map the default functions to their return types */ - private static final HashMap> FUNCTIONS_DEFAULTS_TYPES = new HashMap>(); - 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 */ + /** a map of the default function names to their method */ private static final HashMap FUNCTIONS_DEFAULTS_METHODS = new HashMap(); static { try { @@ -152,46 +137,47 @@ public class ApgService extends Service { } } - /** - * 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 - */ - private static long get_master_key(String search_key, Bundle pReturn) { - if (search_key == null || search_key.length() != 8) { - return 0; - } - ArrayList tmp = new ArrayList(); - tmp.add(search_key); - long[] _keys = get_master_key(tmp, pReturn); - if (_keys.length > 0) - return _keys[0]; - else - return 0; - } - - private static Cursor get_key_entries(HashMap params) { + private static Cursor getKeyEntries(HashMap 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 = params.containsKey("order_by") ? (String) params.get("order_by") : UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC"; + String orderBy = pParams.containsKey("order_by") ? (String) pParams.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") + 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(Apg.getDatabase().db(), (String[]) params.get("columns"), type_where, type_val, null, null, orderBy); + return qb.query(Apg.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 keyList = new ArrayList(); + 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 * @@ -200,7 +186,7 @@ public class ApgService extends Service { * database * @return an array of master keys */ - private static long[] get_master_key(ArrayList search_keys, Bundle pReturn) { + private static long[] getMasterKey(ArrayList pSearchKeys, Bundle pReturn) { HashMap qParams = new HashMap(); qParams.put("columns", new String[] { @@ -209,30 +195,30 @@ public class ApgService extends Service { }); qParams.put("key_type", Id.database.type_public); - Cursor mCursor = get_key_entries(qParams); + Cursor mCursor = getKeyEntries(qParams); if( LOCAL_LOGV ) Log.v(TAG, "going through installed user keys"); - ArrayList _master_keys = new ArrayList(); + ArrayList masterKeys = new ArrayList(); while (mCursor.moveToNext()) { - long _cur_mkey = mCursor.getLong(0); - String _cur_user = mCursor.getString(1); + long curMkey = mCursor.getLong(0); + String curUser = mCursor.getString(1); - String _cur_fprint = Apg.getSmallFingerPrint(_cur_mkey); - if( LOCAL_LOGV ) Log.v(TAG, "current user: " + _cur_user + " (" + _cur_fprint + ")"); - if (search_keys.contains(_cur_fprint) || search_keys.contains(_cur_user)) { - if( LOCAL_LOGV ) Log.v(TAG, "master key found for: " + _cur_fprint); - _master_keys.add(_cur_mkey); - search_keys.remove(_cur_fprint); + String curFprint = Apg.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 " + _cur_fprint + " is not in the list of public keys to encrypt with"); + if( LOCAL_LOGV ) Log.v(TAG, "Installed key " + curFprint + " is not in the list of public keys to encrypt with"); } } mCursor.close(); - long[] _master_longs = new long[_master_keys.size()]; + long[] masterKeyLongs = new long[masterKeys.size()]; int i = 0; - for (Long _key : _master_keys) { - _master_longs[i++] = _key; + for (Long key : masterKeys) { + masterKeyLongs[i++] = key; } if (i == 0) { @@ -240,12 +226,12 @@ public class ApgService extends Service { pReturn.getStringArrayList(ret.WARNINGS.name()).add("Searched for public key(s) but found not one"); } - 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"); + 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 _master_longs; + return masterKeyLongs; } /** @@ -254,27 +240,27 @@ public class ApgService extends Service { * @param args * the bundle to add default parameters to if missing */ - private void add_default_arguments(String call, Bundle args) { + private void addDefaultArguments(String pCall, Bundle pArgs) { // check whether there are optional elements defined for that call - if (FUNCTIONS_OPTIONAL_ARGS.containsKey(call)) { - Preferences _mPreferences = Preferences.getPreferences(getBaseContext(), true); + if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pCall)) { + Preferences preferences = Preferences.getPreferences(getBaseContext(), true); - Iterator _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); + Iterator 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 _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)); + 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 " + _ret_type.toString() + " for default option"); + Log.e(TAG, "Unknown return type " + returnType.toString() + " for default option"); } } catch (Exception e) { Log.e(TAG, "Exception in add_default_arguments " + e.getMessage()); @@ -290,7 +276,7 @@ public class ApgService extends Service { * @param pReturn * the Bundle to update */ - private void add_default_returns(Bundle pReturn) { + private void addDefaultReturns(Bundle pReturn) { ArrayList errors = new ArrayList(); ArrayList warnings = new ArrayList(); @@ -308,13 +294,13 @@ public class ApgService extends Service { * @param pReturn * the bundle to write errors to */ - private void check_required_args(String function, Bundle pArgs, Bundle pReturn) { - if (FUNCTIONS_REQUIRED_ARGS.containsKey(function)) { - Iterator _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); + private void checkForRequiredArgs(String pFunction, Bundle pArgs, Bundle pReturn) { + if (FUNCTIONS_REQUIRED_ARGS.containsKey(pFunction)) { + Iterator 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); } } } @@ -330,60 +316,60 @@ public class ApgService extends Service { * @param pReturn * the bundle to write warnings to */ - private void check_unknown_args(String function, Bundle pArgs, Bundle pReturn) { + private void checkForUnknownArgs(String pFunction, Bundle pArgs, Bundle pReturn) { - HashSet all_args = new HashSet(); - if (FUNCTIONS_REQUIRED_ARGS.containsKey(function)) { - all_args.addAll(FUNCTIONS_REQUIRED_ARGS.get(function)); + HashSet allArgs = new HashSet(); + if (FUNCTIONS_REQUIRED_ARGS.containsKey(pFunction)) { + allArgs.addAll(FUNCTIONS_REQUIRED_ARGS.get(pFunction)); } - if (FUNCTIONS_OPTIONAL_ARGS.containsKey(function)) { - all_args.addAll(FUNCTIONS_OPTIONAL_ARGS.get(function)); + if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pFunction)) { + allArgs.addAll(FUNCTIONS_OPTIONAL_ARGS.get(pFunction)); } - ArrayList _unknown_args = new ArrayList(); - Iterator _iter = pArgs.keySet().iterator(); - while (_iter.hasNext()) { - String _cur_key = _iter.next(); + ArrayList unknownArgs = new ArrayList(); + Iterator iter = pArgs.keySet().iterator(); + while (iter.hasNext()) { + String curKey = iter.next(); try { - arg _cur_arg = arg.valueOf(_cur_key); - if (!all_args.contains(_cur_arg)) { - pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key); - _unknown_args.add(_cur_key); + 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: " + _cur_key); - _unknown_args.add(_cur_key); + 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 : _unknown_args) { - pArgs.remove(_arg); + for (String arg : unknownArgs) { + pArgs.remove(arg); } } - private boolean prepare_args(String call, Bundle pArgs, Bundle pReturn) { + private boolean prepareArgs(String pCall, Bundle pArgs, Bundle pReturn) { Apg.initialize(getBaseContext()); /* add default return values for all functions */ - add_default_returns(pReturn); + addDefaultReturns(pReturn); /* add default arguments if missing */ - add_default_arguments(call, pArgs); + addDefaultArguments(pCall, pArgs); if( LOCAL_LOGV ) Log.v(TAG, "add_default_arguments"); /* check for required arguments */ - check_required_args(call, pArgs, pReturn); + checkForRequiredArgs(pCall, pArgs, pReturn); if( LOCAL_LOGV ) Log.v(TAG, "check_required_args"); /* check for unknown arguments and add to warning if found */ - check_unknown_args(call, pArgs, pReturn); + 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 "+call); - pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.shifted_ordinal()); + 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"); @@ -393,30 +379,30 @@ public class ApgService extends Service { private boolean encrypt(Bundle pArgs, Bundle pReturn) { - long _pub_master_keys[] = {}; + long pubMasterKeys[] = {}; if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) { - ArrayList _list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name()); - ArrayList _pub_keys = new ArrayList(); - if( LOCAL_LOGV ) Log.v(TAG, "Long size: " + _list.size()); - Iterator _iter = _list.iterator(); - while (_iter.hasNext()) { - _pub_keys.add(_iter.next()); + ArrayList list = pArgs.getStringArrayList(arg.PUBLIC_KEYS.name()); + ArrayList pubKeys = new ArrayList(); + if( LOCAL_LOGV ) Log.v(TAG, "Long size: " + list.size()); + Iterator iter = list.iterator(); + while (iter.hasNext()) { + pubKeys.add(iter.next()); } - _pub_master_keys = get_master_key(_pub_keys, pReturn); + pubMasterKeys = getMasterKey(pubKeys, pReturn); } - InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); - InputData _in = new InputData(_inStream, 0); // XXX Size second param? + InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); + InputData in = new InputData(inStream, 0); // XXX Size second param? - OutputStream _out = new ByteArrayOutputStream(); + OutputStream out = new ByteArrayOutputStream(); if( LOCAL_LOGV ) Log.v(TAG, "About to encrypt"); try { Apg.encrypt(getBaseContext(), // context - _in, // input stream - _out, // output stream + in, // input stream + out, // output stream pArgs.getBoolean(arg.ARMORED_OUTPUT.name()), // ARMORED_OUTPUT - _pub_master_keys, // encryption keys - get_master_key(pArgs.getString(arg.SIGNATURE_KEY.name()), pReturn), // signature key + 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 @@ -427,29 +413,29 @@ public class ApgService extends Service { ); } 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.shifted_ordinal()); - } 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.shifted_ordinal()); + 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.shifted_ordinal()); + pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.shiftedOrdinal()); } return false; } if( LOCAL_LOGV ) Log.v(TAG, "Encrypted"); - pReturn.putString(ret.RESULT.name(), _out.toString()); + pReturn.putString(ret.RESULT.name(), out.toString()); return true; } private final IApgService.Stub mBinder = new IApgService.Stub() { - public boolean get_keys(Bundle pArgs, Bundle pReturn) { + public boolean getKeys(Bundle pArgs, Bundle pReturn) { - prepare_args("get_keys", pArgs, pReturn); + prepareArgs("get_keys", pArgs, pReturn); HashMap qParams = new HashMap(); qParams.put("columns", new String[] { @@ -459,31 +445,31 @@ public class ApgService extends Service { qParams.put("key_type", pArgs.getInt(arg.KEY_TYPE.name())); - Cursor mCursor = get_key_entries(qParams); - ArrayList fprints = new ArrayList(); + Cursor cursor = getKeyEntries(qParams); + ArrayList fPrints = new ArrayList(); ArrayList ids = new ArrayList(); - while (mCursor.moveToNext()) { - if( LOCAL_LOGV ) Log.v(TAG, "adding key "+Apg.getSmallFingerPrint(mCursor.getLong(0))); - fprints.add(Apg.getSmallFingerPrint(mCursor.getLong(0))); - ids.add(mCursor.getString(1)); + while (cursor.moveToNext()) { + if( LOCAL_LOGV ) Log.v(TAG, "adding key "+Apg.getSmallFingerPrint(cursor.getLong(0))); + fPrints.add(Apg.getSmallFingerPrint(cursor.getLong(0))); + ids.add(cursor.getString(1)); } - mCursor.close(); + cursor.close(); - pReturn.putStringArrayList(ret.FINGERPRINTS.name(), fprints); + 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) { - if (!prepare_args("encrypt_with_public_key", pArgs, pReturn)) { + public boolean encryptWithPublicKey(Bundle pArgs, Bundle pReturn) { + if (!prepareArgs("encrypt_with_public_key", pArgs, pReturn)) { return false; } return encrypt(pArgs, pReturn); } - public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { - if (!prepare_args("encrypt_with_passphrase", pArgs, pReturn)) { + public boolean encryptWithPassphrase(Bundle pArgs, Bundle pReturn) { + if (!prepareArgs("encrypt_with_passphrase", pArgs, pReturn)) { return false; } @@ -492,11 +478,11 @@ public class ApgService extends Service { } public boolean decrypt(Bundle pArgs, Bundle pReturn) { - if (!prepare_args("decrypt", pArgs, pReturn)) { + if (!prepareArgs("decrypt", pArgs, pReturn)) { return false; } - String _passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs + String passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs .getString(arg.PRIVATE_KEY_PASSPHRASE.name()); InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); @@ -504,21 +490,21 @@ public class ApgService extends Service { OutputStream out = new ByteArrayOutputStream(); if( LOCAL_LOGV ) Log.v(TAG, "About to decrypt"); try { - Apg.decrypt(getBaseContext(), in, out, _passphrase, null, // progress + Apg.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.shifted_ordinal()); - } 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.shifted_ordinal()); + 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.shifted_ordinal()); + 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; } diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index 0eb1307b8..df46805ac 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -1,12 +1,13 @@ package org.thialfihar.android.apg; interface IApgService { - - /* All functions fill the return_vals Bundle with the following keys: + + /* All functions fill the returnVals Bundle with the following keys: * * ArrayList "WARNINGS" = Warnings, if any * ArrayList "ERRORS" = Human readable error descriptions, if any - * int "ERROR" = Numeric representation of error, if any, starting with 100 + * 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 @@ -14,11 +15,10 @@ interface IApgService { * 104: Private key's passphrase missing */ - /* ******************************************************* - * Encrypting and decrypting + /* ******************************************************** + * Encryption * ********************************************************/ - /* All encryption function's arguments * * Bundle params' keys: @@ -54,27 +54,28 @@ interface IApgService { * (optional) * String "PRIVATE_KEY_PASSPHRASE" = Passphrase for signing key * - * Bundle return_vals (in addition to the ERRORS/WARNINGS above): + * Bundle returnVals (in addition to the ERRORS/WARNINGS above): * String "RESULT" = Encrypted message */ - - /* Additional argument: + + /* Additional argument for function below: * (required) * String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase to use */ - boolean encrypt_with_passphrase(in Bundle params, out Bundle return_vals); - + boolean encryptWithPassphrase(in Bundle params, out Bundle returnVals); + /* Additional argument: * (required) * ArrayList "PUBLIC_KEYS" = Public keys (8char fingerprint "123ABC12" OR * complete id "Alice Meyer ") */ - boolean encrypt_with_public_key(in Bundle params, out Bundle return_vals); - + boolean encryptWithPublicKey(in Bundle params, out Bundle returnVals); - /* Decrypt something - * - * Bundle params: + /* ******************************************************** + * Decryption + * ********************************************************/ + + /* Bundle params: * (required) * String "MESSAGE" = Message to decrypt * @@ -87,14 +88,12 @@ interface IApgService { * Bundle return_vals: * String "RESULT" = Decrypted message */ - - boolean decrypt(in Bundle params, out Bundle return_vals); - - - /* ******************************************************* + boolean decrypt(in Bundle params, out Bundle returnVals); + + /* ******************************************************** * Get key information * ********************************************************/ - + /* Get info about all available keys * * Bundle params: @@ -106,8 +105,9 @@ interface IApgService { * Returns: * StringArrayList "FINGERPRINTS" = Short fingerprints of keys * - * StringArrayList "USER_IDS" = User ids of corrosponding fingerprints (order is the same) + * StringArrayList "USER_IDS" = User ids of corresponding fingerprints + * (order is the same as in FINGERPRINTS) */ - boolean get_keys(in Bundle params, out Bundle return_vals); + boolean getKeys(in Bundle params, out Bundle returnVals); } \ No newline at end of file diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 7ab2ea842..0c216b547 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -46,14 +46,19 @@ import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener; *

    * * @author Markus Doits - * @version 0.9.9 + * @version 1.0rc1 * */ public class ApgCon { private static final boolean LOCAL_LOGV = true; private static final boolean LOCAL_LOGD = true; - private class call_async extends AsyncTask { + private final static String TAG = "ApgCon"; + private final static int API_VERSION = 1; // aidl api-version it expects + + public int secondsToWaitForConnection = 15; + + private class CallAsync extends AsyncTask { @Override protected Void doInBackground(String... arg) { @@ -64,48 +69,46 @@ public class ApgCon { protected void onPostExecute(Void res) { if( LOCAL_LOGD ) Log.d(TAG, "Async execution finished"); - async_running = false; + mAsyncRunning = false; } } - private final static String TAG = "ApgCon"; - private final static int api_version = 1; // aidl api-version it expects private final Context mContext; - private final error connection_status; - private boolean async_running = false; - private OnCallFinishListener onCallFinishListener; + private final error mConnectionStatus; + private boolean mAsyncRunning = false; + private OnCallFinishListener mOnCallFinishListener; - private final Bundle result = new Bundle(); - private final Bundle args = new Bundle(); - private final ArrayList error_list = new ArrayList(); - private final ArrayList warning_list = new ArrayList(); + private final Bundle mResult = new Bundle(); + private final Bundle mArgs = new Bundle(); + private final ArrayList mErrorList = new ArrayList(); + private final ArrayList mWarningList = new ArrayList(); /** Remote service for decrypting and encrypting data */ - private IApgService apgService = null; + private IApgService mApgService = null; /** Set apgService accordingly to connection status */ - private ServiceConnection apgConnection = new ServiceConnection() { + private ServiceConnection mApgConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { if( LOCAL_LOGD ) Log.d(TAG, "IApgService bound to apgService"); - apgService = IApgService.Stub.asInterface(service); + mApgService = IApgService.Stub.asInterface(service); } public void onServiceDisconnected(ComponentName className) { if( LOCAL_LOGD ) Log.d(TAG, "IApgService disconnected"); - apgService = null; + mApgService = null; } }; - + /** * Different types of local errors - * - * @author markus - * */ public static enum error { + /** + * no error + */ NO_ERROR, /** * generic error @@ -131,6 +134,9 @@ public class ApgCon { * found APG but without AIDL interface */ APG_AIDL_MISSING, + /** + * found APG but with wrong API + */ APG_API_MISSMATCH } @@ -156,77 +162,78 @@ public class ApgCon { if( LOCAL_LOGV ) Log.v(TAG, "EncryptionService created"); mContext = ctx; - error tmp_connection_status = null; + error tmpError = null; try { if( LOCAL_LOGV ) Log.v(TAG, "Searching for the right APG version"); - ServiceInfo apg_services[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg", + ServiceInfo apgServices[] = ctx.getPackageManager().getPackageInfo("org.thialfihar.android.apg", PackageManager.GET_SERVICES | PackageManager.GET_META_DATA).services; - if (apg_services == null) { + if (apgServices == null) { Log.e(TAG, "Could not fetch services"); - tmp_connection_status = error.GENERIC; + tmpError = error.GENERIC; } else { - boolean apg_service_found = false; - for (ServiceInfo inf : apg_services) { + 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")) { - apg_service_found = true; + apgServiceFound = true; if (inf.metaData == null) { Log.w(TAG, "Could not determine ApgService API"); Log.w(TAG, "This probably won't work!"); - warning_list.add("(LOCAL) Could not determine ApgService API"); - tmp_connection_status = 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); + 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!"); - warning_list.add("(LOCAL) Found ApgService API version" + inf.metaData.getInt("api_version") + " but exspected " + api_version); - tmp_connection_status = error.APG_API_MISSMATCH; + 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"); - tmp_connection_status = error.NO_ERROR; + if( LOCAL_LOGV ) Log.v(TAG, "Found api_version " + API_VERSION + ", everything should work"); + tmpError = error.NO_ERROR; } } } - if (!apg_service_found) { + if (!apgServiceFound) { Log.e(TAG, "Could not find APG with AIDL interface, this probably won't work"); - error_list.add("(LOCAL) Could not find APG with AIDL interface, this probably won't work"); - result.putInt(ret.ERROR.name(), error.APG_AIDL_MISSING.ordinal()); - tmp_connection_status = error.APG_NOT_FOUND; + 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); - error_list.add("(LOCAL) Could not find APG, is it installed?"); - result.putInt(ret.ERROR.name(), error.APG_NOT_FOUND.ordinal()); - tmp_connection_status = error.APG_NOT_FOUND; + 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; - connection_status = tmp_connection_status; } /** try to connect to the apg service */ private boolean connect() { if( LOCAL_LOGV ) Log.v(TAG, "trying to bind the apgService to context"); - if (apgService != null) { + if (mApgService != null) { if( LOCAL_LOGV ) Log.v(TAG, "allready connected"); return true; } try { - mContext.bindService(new Intent(IApgService.class.getName()), apgConnection, Context.BIND_AUTO_CREATE); + mContext.bindService(new Intent(IApgService.class.getName()), mApgConnection, Context.BIND_AUTO_CREATE); } catch (Exception e) { Log.e(TAG, "could not bind APG service", e); return false; } - int wait_count = 0; - while (apgService == null && wait_count++ < 15) { + 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 (wait_count >= 15) { + if (waitCount >= secondsToWaitForConnection) { if( LOCAL_LOGV ) Log.v(TAG, "slept waiting for nothing!"); return false; } @@ -250,14 +257,14 @@ public class ApgCon { */ public void disconnect() { if( LOCAL_LOGV ) Log.v(TAG, "disconnecting apgService"); - if (apgService != null) { - mContext.unbindService(apgConnection); - apgService = null; + if (mApgService != null) { + mContext.unbindService(mApgConnection); + mApgService = null; } } private boolean initialize() { - if (apgService == null) { + if (mApgService == null) { if (!connect()) { if( LOCAL_LOGV ) Log.v(TAG, "connection to apg service failed"); return false; @@ -270,40 +277,40 @@ public class ApgCon { * Calls a function from APG's AIDL-interface * *

    - * After you have set up everything with {@link #set_arg(String, String)} + * After you have set up everything with {@link #setArg(String, String)} * (and variants), you can call a function from the AIDL-interface. This * will *

      *
    • start connection to the remote interface (if not already connected)
    • *
    • call the passed function with all set up parameters synchronously
    • - *
    • set up everything to retrieve the result and/or warnings/errors
    • + *
    • set up everything to retrieve the mResult and/or warnings/errors
    • *
    • call the callback if provided *
    *

    * *

    * Note your thread will be blocked during execution - if you want to call - * the function asynchronously, see {@link #call_async(String)}. + * the function asynchronously, see {@link #callAsync(String)}. *

    * * @param function * a remote function to call * @return true, if call successful (= no errors), else false * - * @see #call_async(String) - * @see #set_arg(String, String) - * @see #set_onCallFinishListener(OnCallFinishListener) + * @see #callAsync(String) + * @see #setArg(String, String) + * @see #setOnCallFinishListener(OnCallFinishListener) */ public boolean call(String function) { - boolean success = this.call(function, args, result); - if (onCallFinishListener != null) { + boolean success = this.call(function, mArgs, mResult); + if (mOnCallFinishListener != null) { try { if( LOCAL_LOGD ) Log.d(TAG, "About to execute callback"); - onCallFinishListener.onCallFinish(result); + 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); - warning_list.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); + mWarningList.add("(LOCAL) Could not execute callback (" + e.getClass() + "): " + e.getMessage()); } } return success; @@ -321,8 +328,8 @@ public class ApgCon { *

    * To see whether the task is finished, you have to possibilities: *

      - *
    • In your thread, poll {@link #is_running()}
    • - *
    • Supply a callback with {@link #set_onCallFinishListener(OnCallFinishListener)}
    • + *
    • In your thread, poll {@link #isRunning()}
    • + *
    • Supply a callback with {@link #setOnCallFinishListener(OnCallFinishListener)}
    • *
    *

    * @@ -330,47 +337,47 @@ public class ApgCon { * a remote function to call * * @see #call(String) - * @see #is_running() - * @see #set_onCallFinishListener(OnCallFinishListener) + * @see #isRunning() + * @see #setOnCallFinishListener(OnCallFinishListener) */ - public void call_async(String function) { - async_running = true; - new call_async().execute(function); + public void callAsync(String function) { + mAsyncRunning = true; + new CallAsync().execute(function); } private boolean call(String function, Bundle pArgs, Bundle pReturn) { if (!initialize()) { - error_list.add("(LOCAL) Cannot bind to ApgService"); - result.putInt(ret.ERROR.name(), error.CANNOT_BIND_TO_APG.ordinal()); + 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) { - error_list.add("(LOCAL) Function to call missing"); - result.putInt(ret.ERROR.name(), error.CALL_MISSING.ordinal()); + mErrorList.add("(LOCAL) Function to call missing"); + mResult.putInt(ret.ERROR.name(), error.CALL_MISSING.ordinal()); return false; } try { - Boolean success = (Boolean) IApgService.class.getMethod(function, Bundle.class, Bundle.class).invoke(apgService, pArgs, pReturn); - error_list.addAll(pReturn.getStringArrayList(ret.ERRORS.name())); - warning_list.addAll(pReturn.getStringArrayList(ret.WARNINGS.name())); + Boolean success = (Boolean) IApgService.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); - error_list.add("(LOCAL) Remote call not known (" + function + "): " + e.getMessage()); - result.putInt(ret.ERROR.name(), error.CALL_NOT_KNOWN.ordinal()); + 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); - error_list.add("(LOCAL) Exception of type '" + orig.getClass() + "' on AIDL call '" + function + "': " + orig.getMessage()); + 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); - error_list.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); - result.putInt(ret.ERROR.name(), error.GENERIC.ordinal()); + mErrorList.add("(LOCAL) Generic error (" + e.getClass() + "): " + e.getMessage()); + mResult.putInt(ret.ERROR.name(), error.GENERIC.ordinal()); return false; } @@ -390,7 +397,7 @@ public class ApgCon { * *

    * Note, that the parameters are not deleted after a call, so you have to - * reset ({@link #clear_args()}) them manually if you want to. + * reset ({@link #clearArgs()}) them manually if you want to. *

    * * @@ -399,10 +406,10 @@ public class ApgCon { * @param val * the value * - * @see #clear_args() + * @see #clearArgs() */ - public void set_arg(String key, String val) { - args.putString(key, val); + public void setArg(String key, String val) { + mArgs.putString(key, val); } /** @@ -415,7 +422,7 @@ public class ApgCon { * * *
    -     * set_arg("a key", new String[]{ "entry 1", "entry 2" });
    +     * setArg("a key", new String[]{ "entry 1", "entry 2" });
          * 
    *
    * @@ -424,14 +431,14 @@ public class ApgCon { * @param vals * the value * - * @see #set_arg(String, String) + * @see #setArg(String, String) */ - public void set_arg(String key, String vals[]) { + public void setArg(String key, String vals[]) { ArrayList list = new ArrayList(); for (String val : vals) { list.add(val); } - args.putStringArrayList(key, list); + mArgs.putStringArrayList(key, list); } /** @@ -442,10 +449,10 @@ public class ApgCon { * @param vals * the value * - * @see #set_arg(String, String) + * @see #setArg(String, String) */ - public void set_arg(String key, boolean val) { - args.putBoolean(key, val); + public void setArg(String key, boolean val) { + mArgs.putBoolean(key, val); } /** @@ -456,10 +463,10 @@ public class ApgCon { * @param vals * the value * - * @see #set_arg(String, String) + * @see #setArg(String, String) */ - public void set_arg(String key, int val) { - args.putInt(key, val); + public void setArg(String key, int val) { + mArgs.putInt(key, val); } /** @@ -474,14 +481,14 @@ public class ApgCon { * @param vals * the value * - * @see #set_arg(String, String) + * @see #setArg(String, String) */ - public void set_arg(String key, int vals[]) { + public void setArg(String key, int vals[]) { ArrayList list = new ArrayList(); for (int val : vals) { list.add(val); } - args.putIntegerArrayList(key, list); + mArgs.putIntegerArrayList(key, list); } /** @@ -489,17 +496,17 @@ public class ApgCon { * *

    * Anything the has been set up with the various - * {@link #set_arg(String, String)} functions, is cleared. + * {@link #setArg(String, String)} functions, is cleared. *

    *

    - * Note, that any warning, error, callback, result, etc. is not cleared with + * Note, that any warning, error, callback, mResult, etc. is not cleared with * this. *

    * * @see #reset() */ - public void clear_args() { - args.clear(); + public void clearArgs() { + mArgs.clear(); } /** @@ -509,8 +516,8 @@ public class ApgCon { * the object's key you want to return * @return an object at position key, or null if not set */ - public Object get_arg(String key) { - return args.get(key); + public Object getArg(String key) { + return mArgs.get(key); } /** @@ -525,12 +532,12 @@ public class ApgCon { * @return a human readable description of a error that happened, or null if * no more errors * - * @see #has_next_error() - * @see #clear_errors() + * @see #hasNextError() + * @see #clearErrors() */ - public String get_next_error() { - if (error_list.size() != 0) - return error_list.remove(0); + public String getNextError() { + if (mErrorList.size() != 0) + return mErrorList.remove(0); else return null; } @@ -540,10 +547,10 @@ public class ApgCon { * * @return true, if there are unreturned errors, false otherwise * - * @see #get_next_error() + * @see #getNextError() */ - public boolean has_next_error() { - return error_list.size() != 0; + public boolean hasNextError() { + return mErrorList.size() != 0; } /** @@ -552,15 +559,15 @@ public class ApgCon { *

    * 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 #get_next_error()}) for what + * human readable description with {@link #getNextError()}) for what * errors >=100 mean. *

    * * @return the id of the error that happened */ - public int get_error() { - if (result.containsKey(ret.ERROR.name())) - return result.getInt(ret.ERROR.name()); + public int getError() { + if (mResult.containsKey(ret.ERROR.name())) + return mResult.getInt(ret.ERROR.name()); else return -1; } @@ -577,12 +584,12 @@ public class ApgCon { * @return a human readable description of a warning that happened, or null * if no more warnings * - * @see #has_next_warning() - * @see #clear_warnings() + * @see #hasNextWarning() + * @see #clearWarnings() */ - public String get_next_warning() { - if (warning_list.size() != 0) - return warning_list.remove(0); + public String getNextWarning() { + if (mWarningList.size() != 0) + return mWarningList.remove(0); else return null; } @@ -592,94 +599,94 @@ public class ApgCon { * * @return true, if there are unreturned warnings, false otherwise * - * @see #get_next_warning() + * @see #getNextWarning() */ - public boolean has_next_warning() { - return warning_list.size() != 0; + public boolean hasNextWarning() { + return mWarningList.size() != 0; } /** * Get the result * *

    - * This gets your result. After doing an encryption or decryption with APG, + * This gets your mResult. After doing an encryption or decryption with APG, * you get the output with this function. *

    *

    - * Note, that when your last remote call is unsuccessful, the result will + * Note, that when your last remote call is unsuccessful, the mResult 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 #clear_result()}) + * call was successful). To ensure you do not work with old call's mResults, + * either be sure to {@link #reset()} (or at least {@link #clearResult()}) * your instance before each new call or always check that - * {@link #has_next_error()} is false. + * {@link #hasNextError()} is false. *

    * - * @return the result of the last {@link #call(String)} or + * @return the mResult of the last {@link #call(String)} or * {@link #call_asinc(String)}. * * @see #reset() - * @see #clear_result() - * @see #get_result_bundle() + * @see #clearResult() + * @see #getResultBundle() */ - public String get_result() { - return result.getString(ret.RESULT.name()); + public String getResult() { + return mResult.getString(ret.RESULT.name()); } /** - * Get the result bundle + * Get the mResult bundle * *

    - * Unlike {@link #get_result()}, which only returns any en-/decrypted + * 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. *

    *

    * For warnings and errors it is suggested to use the functions that are - * provided here, namely {@link #get_error()}, {@link #get_next_error()}, + * 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 + * standard, you have access to the complete mResult bundle to extract the * information. *

    * - * @return the complete result-bundle of the last call to apg + * @return the complete mResult-bundle of the last call to apg */ - public Bundle get_result_bundle() { - return result; + public Bundle getResultBundle() { + return mResult; } - public error get_connection_status() { - return connection_status; + public error getConnectionStatus() { + return mConnectionStatus; } /** * Clears all unfetched errors * - * @see #get_next_error() - * @see #has_next_error() + * @see #getNextError() + * @see #hasNextError() */ - public void clear_errors() { - error_list.clear(); - result.remove(ret.ERROR.name()); + public void clearErrors() { + mErrorList.clear(); + mResult.remove(ret.ERROR.name()); } /** * Clears all unfetched warnings * - * @see #get_next_warning() - * @see #has_next_warning() + * @see #getNextWarning() + * @see #hasNextWarning() */ - public void clear_warnings() { - warning_list.clear(); + public void clearWarnings() { + mWarningList.clear(); } /** - * Clears the last result + * Clears the last mResult * - * @see #get_result() + * @see #getResult() */ - public void clear_result() { - result.remove(ret.RESULT.name()); + public void clearResult() { + mResult.remove(ret.RESULT.name()); } /** @@ -689,34 +696,34 @@ public class ApgCon { * a object to call back after async execution * @see ApgConInterface */ - public void set_onCallFinishListener(OnCallFinishListener lis) { - onCallFinishListener = lis; + public void setOnCallFinishListener(OnCallFinishListener lis) { + mOnCallFinishListener = lis; } /** * Clears any callback object * - * @see #set_onCallFinishListener(OnCallFinishListener) + * @see #setOnCallFinishListener(OnCallFinishListener) */ - public void clear_onCallFinishListener() { - onCallFinishListener = null; + public void clearOnCallFinishListener() { + mOnCallFinishListener = null; } /** * Checks, whether an async execution is running * *

    - * If you started something with {@link #call_async(String)}, this will + * If you started something with {@link #callAsync(String)}, this will * return true if the task is still running *

    * * @return true, if an async task is still running, false otherwise * - * @see #call_async(String) + * @see #callAsync(String) * */ - public boolean is_running() { - return async_running; + public boolean isRunning() { + return mAsyncRunning; } /** @@ -724,24 +731,24 @@ public class ApgCon { * *

    * This currently resets everything in this instance. Errors, warnings, - * results, callbacks, ... are removed. Any connection to the remote + * mResults, callbacks, ... are removed. Any connection to the remote * interface is upheld, though. *

    * *

    - * Note, that when an async execution ({@link #call_async(String)}) is - * running, it's result, warnings etc. will still be evaluated (which might + * Note, that when an async execution ({@link #callAsync(String)}) is + * running, it's mResult, warnings etc. will still be evaluated (which might * be not what you want). Also mind, that any callback you set is also * reseted, so on finishing the execution any before defined callback will * NOT BE TRIGGERED. *

    */ public void reset() { - clear_errors(); - clear_warnings(); - clear_args(); - clear_onCallFinishListener(); - result.clear(); + clearErrors(); + clearWarnings(); + clearArgs(); + clearOnCallFinishListener(); + mResult.clear(); } } From 0502be76524cee950fb33aa1e687f70caabf4030 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 5 Jun 2011 19:47:41 +0000 Subject: [PATCH 65/69] Documentation update of ApgCon --- .../thialfihar/android/apg/utils/ApgCon.java | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 0c216b547..475f7e9a9 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -56,6 +56,11 @@ public class ApgCon { private final static String TAG = "ApgCon"; private final static int API_VERSION = 1; // aidl api-version it expects + /** + * 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 { @@ -278,12 +283,12 @@ public class ApgCon { * *

    * After you have set up everything with {@link #setArg(String, String)} - * (and variants), you can call a function from the AIDL-interface. This - * will + * (and variants), you can call a function of the AIDL-interface. This + * will: *

      *
    • start connection to the remote interface (if not already connected)
    • - *
    • call the passed function with all set up parameters synchronously
    • - *
    • set up everything to retrieve the mResult and/or warnings/errors
    • + *
    • call the function passed with all parameters synchronously
    • + *
    • set up everything to retrieve the result and/or warnings/errors
    • *
    • call the callback if provided *
    *

    @@ -317,7 +322,7 @@ public class ApgCon { } /** - * Calls a function from remote interface asynchronously + * Calls a function of remote interface asynchronously * *

    * This does exactly the same as {@link #call(String)}, but asynchronously. @@ -326,7 +331,7 @@ public class ApgCon { *

    * *

    - * To see whether the task is finished, you have to possibilities: + * To see whether the task is finished, you have two possibilities: *