-- cgit v1.2.3 From e8d29c01c286f24f660f6d1c55f896c7bc0994c9 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 29 Dec 2010 16:31:58 +0000 Subject: 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 +- src/org/thialfihar/android/apg/ApgService.java | 76 +++++++++++++++++++++++++ src/org/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: 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; -- cgit v1.2.3 From 455510e0c0e51e9650121472637ffdbb589baf14 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 29 Dec 2010 16:47:55 +0000 Subject: 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 -- cgit v1.2.3 From ec988efb55165978233118691ec95268f7d30667 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 29 Dec 2010 16:49:27 +0000 Subject: 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; -- cgit v1.2.3 From 2660c561a171a09c1c6ed2610aea3d0efca23f98 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 30 Dec 2010 13:48:24 +0000 Subject: 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) { -- cgit v1.2.3 From 6477f6076420b71ad1697aa8db9d453bd2422412 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 4 Jan 2011 23:08:08 +0000 Subject: Add connection helper for other projects This eases using the AIDL-Interface and is the recommended way for other project to implement the connection. --- src/org/thialfihar/android/apg/ApgService.java | 31 +++-- src/org/thialfihar/android/apg/IApgService.aidl | 4 +- src/org/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; + } + } + +} -- cgit v1.2.3 From dbb46f1633b94aa7be39ebb8f4acc24a3420083f Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 4 Jan 2011 23:09:56 +0000 Subject: 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); -- cgit v1.2.3 From 1a338de47e7d9faa73a3bc6eda51cb47a18dc91b Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 5 Jan 2011 14:07:09 +0000 Subject: 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). --- src/org/thialfihar/android/apg/ApgService.java | 103 +++++++++++++++++++---- src/org/thialfihar/android/apg/IApgService.aidl | 33 +++++++- src/org/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() { -- cgit v1.2.3 From b1e8194ce24377528d1f36e578bb2e80e0051239 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 17:17:08 +0000 Subject: 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); } -- cgit v1.2.3 From 91da2dd2ea59463d5502febf0909f2e64bf519df Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 17:17:18 +0000 Subject: 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; -- cgit v1.2.3 From a29dfc0addb5b2eac07e29633f044c4690559f1a Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 17:17:27 +0000 Subject: Reset errors before calling, make some vars final, minor cleanups --- src/org/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() { -- cgit v1.2.3 From 9e089f03b6efb656650be7fa465833f189398af5 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 19:16:22 +0000 Subject: Prefix local vars with "_" --- src/org/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"); -- cgit v1.2.3 From c84c449035db1498414486b13e63e590ddf49a58 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 19:16:45 +0000 Subject: 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. --- src/org/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) { -- cgit v1.2.3 From def11ad18f0394adaf61c0cf53647f5583e5b8b6 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 19:16:54 +0000 Subject: 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); -- cgit v1.2.3 From 3f0c80882e39881d6c93596ce498e50144836eae Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 20:12:03 +0000 Subject: 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 -- cgit v1.2.3 From 51b63d099c6794b01ae8cbdbdd56c9fe673e4e8a Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 9 Jan 2011 20:12:12 +0000 Subject: 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); -- cgit v1.2.3 From d367bc12f833bed8082c99936e0ac5b86a95faf7 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 11 Jan 2011 17:58:13 +0000 Subject: Make some things static *Should* speed up encryption, or better: does not make encryption using AIDL slower than using APG directly. --- src/org/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 { -- cgit v1.2.3 From fc05dfd8b7260ed042a4c78f66256d775bd6e9d2 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 11 Jan 2011 22:24:08 +0000 Subject: 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; -- cgit v1.2.3 From 45e4897dc7f05f1f270f4993cc3060f654e2f3a9 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 11 Jan 2011 22:24:20 +0000 Subject: 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. --- src/org/thialfihar/android/apg/ApgService.java | 270 +++++++++++++++---------- 1 file changed, 168 insertions(+), 102 deletions(-) diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 717383b98..ff2fb8ad8 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -7,7 +7,9 @@ import java.io.OutputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.Set; import android.content.Intent; import android.os.Bundle; @@ -23,23 +25,74 @@ public class ApgService extends Service { return mBinder; } + /** error status */ private enum error { ARGUMENTS_MISSING, APG_FAILURE } + /** all arguments that can be passed by calling application */ + private enum arg { + MSG, // message to encrypt or to decrypt + SYM_KEY, // key for symmetric en/decryption + PUBLIC_KEYS, // public keys for encryption + ENCRYPTION_ALGO, // encryption algorithm + HASH_ALGO, // hash algorithm + ARMORED, // whether to armor output + FORCE_V3_SIG, // whether to force v3 signature + COMPRESSION + // what compression to use for encrypted output + } + + /** all things that might be returned */ + private enum ret { + ERRORS, + WARNINGS, + ERROR, + RESULT + } + + /** required arguments for each AIDL function */ + private static final HashMap> FUNCTIONS_REQUIRED_ARGS = new HashMap>(); + static { + 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 */ - static final HashMap FUNCTIONS_DEFAULTS = new HashMap(); + private 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"); + 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()); } } } } - 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); - - Bundle _my_args = new Bundle(pArgs); - - /* add default values if missing */ - add_defaults(_my_args); + /** + * updates a Bundle with default return values + * + * @param pReturn + * the Bundle to update + */ + private void add_default_returns(Bundle pReturn) { + ArrayList errors = new ArrayList(); + ArrayList warnings = new ArrayList(); - /* required args */ - String msg = _my_args.getString("MSG"); - _my_args.remove("MSG"); + pReturn.putStringArrayList(ret.ERRORS.name(), errors); + pReturn.putStringArrayList(ret.WARNINGS.name(), warnings); + } - String passphrase = _my_args.getString("SYM_KEY"); - _my_args.remove("SYM_KEY"); + /** + * checks for required arguments and adds them to the error if missing + * + * @param function + * the functions required arguments to check for + * @param pArgs + * the Bundle of arguments to check + * @param pReturn + * the bundle to write errors to + */ + private void check_required_args(String function, Bundle pArgs, Bundle pReturn) { + Iterator _iter = FUNCTIONS_REQUIRED_ARGS.get(function).iterator(); + while (_iter.hasNext()) { + String _cur_arg = _iter.next().name(); + if (!pArgs.containsKey(_cur_arg)) { + pReturn.getStringArrayList(ret.ERRORS.name()).add("Argument missing: " + _cur_arg); + } + } + } - /* optional args */ - Boolean armored = _my_args.getBoolean("ARMORED"); - _my_args.remove("ARMORED"); + /** + * checks for unknown arguments and add them to warning if found + * + * @param function + * the functions name to check against + * @param pArgs + * the Bundle of arguments to check + * @param pReturn + * the bundle to write warnings to + */ + private void check_unknown_args(String function, Bundle pArgs, Bundle pReturn) { + HashSet all_args = new HashSet(FUNCTIONS_REQUIRED_ARGS.get(function)); + all_args.addAll(FUNCTIONS_OPTIONAL_ARGS.get(function)); - int encryption_algorithm = _my_args.getInt("ENCRYPTION_ALGO"); - _my_args.remove("ENCRYPTION_ALGO"); + Iterator _iter = pArgs.keySet().iterator(); + while (_iter.hasNext()) { + String _cur_key = _iter.next(); + try { + arg.valueOf(_cur_key); + } catch (Exception e) { + pReturn.getStringArrayList(ret.WARNINGS.name()).add("Unknown argument: " + _cur_key); + } - int hash_algorithm = _my_args.getInt("HASH_ALGO"); - _my_args.remove("HASH_ALGO"); + } + } - int compression = _my_args.getInt("COMPRESSION"); - _my_args.remove("COMPRESSION"); + private final IApgService.Stub mBinder = new IApgService.Stub() { - Boolean force_v3_signatures = _my_args.getBoolean("FORCE_V3_SIG"); - _my_args.remove("FORCE_V3_SIG"); + public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { + /* add default return values for all functions */ + add_default_returns(pReturn); - /* check required args */ - if (msg == null) { - errors.add("Message to encrypt (MSG) missing"); - } + /* add default arguments if missing */ + add_default_arguments(pArgs); + Log.d(TAG, "add_default_arguments"); - if (passphrase == null) { - errors.add("Symmetric key (SYM_KEY) missing"); - } + /* check for required arguments */ + check_required_args("encrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_required_args"); - /* check for unknown args and add to warning */ - if (!_my_args.isEmpty()) { - Iterator _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(); - - pReturn.putStringArrayList("ERRORS", errors); - pReturn.putStringArrayList("WARNINGS", warnings); + /* add default return values for all functions */ + add_default_returns(pReturn); - String encrypted_msg = pArgs.getString("MSG"); - pArgs.remove("MSG"); + /* add default arguments if missing */ + add_default_arguments(pArgs); + Log.d(TAG, "add_default_arguments"); - String passphrase = pArgs.getString("SYM_KEY"); - pArgs.remove("SYM_KEY"); - if (encrypted_msg == null) { - errors.add("Message to decrypt (MSG) missing"); - } + /* check required args */ + check_required_args("decrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_required_args"); - if (passphrase == null) { - errors.add("Symmetric key (SYM_KEY) missing"); - } - if (!pArgs.isEmpty()) { - Iterator iter = pArgs.keySet().iterator(); - while (iter.hasNext()) { - warnings.add("Unknown key: " + iter.next()); - } - } + /* check for unknown args and add to warning */ + check_unknown_args("decrypt_with_passphrase", pArgs, pReturn); + Log.d(TAG, "check_unknown_args"); - if (errors.size() != 0) { - pReturn.putStringArrayList("ERROR", errors); - pReturn.putInt("ERROR", error.ARGUMENTS_MISSING.ordinal()); + + /* return if errors happened */ + if (pReturn.getStringArrayList(ret.ERRORS.name()).size() != 0) { + pReturn.putInt(ret.ERROR.name(), error.ARGUMENTS_MISSING.ordinal()); return false; } - InputStream inStream = new ByteArrayInputStream(encrypted_msg.getBytes()); + InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); InputData in = new InputData(inStream, 0); // XXX what size in // second parameter? OutputStream out = new ByteArrayOutputStream(); try { - Apg.decrypt(getApplicationContext(), in, out, passphrase, null, // progress + Apg.decrypt(getApplicationContext(), in, out, pArgs.getString(arg.SYM_KEY.name()), null, // progress true // symmetric ); } catch (Exception e) { Log.d(TAG, "Exception in decrypt"); - errors.add("Internal failure in APG when decrypting: " + e.getMessage()); + pReturn.getStringArrayList(ret.ERRORS.name()).add("Internal failure in APG when decrypting: " + e.getMessage()); - pReturn.putInt("ERROR", error.APG_FAILURE.ordinal()); - pReturn.putStringArrayList("ERROR", errors); + pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); return false; } - pReturn.putString("RESULT", out.toString()); + pReturn.putString(ret.RESULT.name(), out.toString()); return true; } }; -- cgit v1.2.3 From 8b352296503b555bc8d7e0fa7fff2f66ad5a8701 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 11 Jan 2011 22:31:35 +0000 Subject: 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); } -- cgit v1.2.3 From 9c06bb03b66c80742715935e7aacb6b519c87f51 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 13 Jan 2011 20:12:02 +0000 Subject: Prepare ApgCon for asymetric enc and clean up --- src/org/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; -- cgit v1.2.3 From a1c75dd47ce4a72f516366b24c9e00d270a187b6 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 13 Jan 2011 20:12:10 +0000 Subject: Add asymmetric encryption --- src/org/thialfihar/android/apg/ApgService.java | 248 ++++++++++++++++-------- src/org/thialfihar/android/apg/IApgService.aidl | 20 +- 2 files changed, 186 insertions(+), 82 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 final IApgService.Stub mBinder = new IApgService.Stub() { + private boolean prepare_args(String call, Bundle pArgs, Bundle pReturn) { + Apg.initialize(getBaseContext()); - public boolean encrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { - /* add default return values for all functions */ - add_default_returns(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"); + /* add default arguments if missing */ + add_default_arguments(call, 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 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("encrypt_with_passphrase", pArgs, pReturn); - Log.d(TAG, "check_unknown_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 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"); - InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); - InputData _in = new InputData(_inStream, 0); // XXX Size second - // param? - OutputStream _out = new ByteArrayOutputStream(); + return true; + } - 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()); + private boolean encrypt(Bundle pArgs, Bundle pReturn) { - pReturn.putInt(ret.ERROR.name(), error.APG_FAILURE.ordinal()); - return false; + 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()); } - Log.d(TAG, "Encrypted"); - pReturn.putString(ret.RESULT.name(), _out.toString()); - return true; + _pub_master_keys = get_master_key(_pub_keys); } - public boolean decrypt_with_passphrase(Bundle pArgs, Bundle pReturn) { - /* add default return values for all functions */ - add_default_returns(pReturn); + InputStream _inStream = new ByteArrayInputStream(pArgs.getString(arg.MSG.name()).getBytes()); + InputData _in = new InputData(_inStream, 0); // XXX Size second + // param? - /* add default arguments if missing */ - add_default_arguments(pArgs); - Log.d(TAG, "add_default_arguments"); + 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; + } - /* check required args */ - check_required_args("decrypt_with_passphrase", pArgs, pReturn); - Log.d(TAG, "check_required_args"); + private final IApgService.Stub mBinder = new IApgService.Stub() { + public boolean encrypt_with_public_key(Bundle pArgs, Bundle pReturn) { + if (!prepare_args("encrypt_with_public_key", pArgs, pReturn)) { + return false; + } - /* check for unknown args and add to warning */ - check_unknown_args("decrypt_with_passphrase", pArgs, pReturn); - Log.d(TAG, "check_unknown_args"); + return encrypt(pArgs, pReturn); + } - - /* 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_passphrase(Bundle pArgs, Bundle pReturn) { + if (!prepare_args("encrypt_with_passphrase", pArgs, pReturn)) { + return false; + } + + return encrypt(pArgs, pReturn); + + } + + public boolean decrypt(Bundle pArgs, Bundle pReturn) { + if (!prepare_args("decrypt", pArgs, pReturn)) { 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 -- cgit v1.2.3 From 9fb631d599d9c375b83a5b2a682a4ff58cc23b79 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 13 Jan 2011 20:28:08 +0000 Subject: 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() { -- cgit v1.2.3 From 7bf8649d9537bc6d51a199cf8ecd79d9c022a34d Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Mon, 17 Jan 2011 21:15:31 +0000 Subject: 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: Allow to sign and specify passphrase on decrypting --- src/org/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) { -- cgit v1.2.3 From dc02a74d52f66ebf7e4b3592ad7af09ce883f734 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Mon, 17 Jan 2011 22:16:57 +0000 Subject: Update AIDL-Doc --- src/org/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 -- cgit v1.2.3 From eb75eea64fbb0c9bfb86ed1fc1ef5dc1248144e0 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Mon, 17 Jan 2011 22:21:41 +0000 Subject: 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); -- cgit v1.2.3 From 5eaea519adfda20246d11b380048adfc83f1ff37 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 20:35:33 +0000 Subject: Refactor some log prios --- src/org/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; -- cgit v1.2.3 From 79238cbcce46c9623214a9d0a895cf1a7bc64867 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 20:35:41 +0000 Subject: Rename parameters Writing them out should make them clearer --- src/org/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"); -- cgit v1.2.3 From 3f703fa4ea5ffb59def408455399cc1ea43b0434 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 21:17:05 +0000 Subject: More finegrained errors --- src/org/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; -- cgit v1.2.3 From 10e0dd0237f2072bb2862772f8bb2997b3747926 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 21:17:14 +0000 Subject: 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. --- src/org/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 -- cgit v1.2.3 From e6ece71fa0d9500bea7e110cb66db08e354d3738 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 22:08:56 +0000 Subject: 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: 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. --- src/org/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(); } -- cgit v1.2.3 From 209b300638d70caa10d4ac9a79be46123a8f7f91 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 22:12:47 +0000 Subject: 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"); } } } -- cgit v1.2.3 From 945e8bb25bd3bff3b03be3061113895ab78033a9 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 22:19:48 +0000 Subject: 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) { -- cgit v1.2.3 From 79cf07f1e23f5b19c151b360cc25fc9c5a62589f Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 18 Jan 2011 22:24:28 +0000 Subject: 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 { -- cgit v1.2.3 From be2476e0ba56241c4681be11371177cfd4d5d876 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 19 Jan 2011 22:33:06 +0000 Subject: 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. --- src/org/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(); } } -- cgit v1.2.3 From e73794a5cc1f1c78485cce4282f5b2ecef549fe2 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 11:55:36 +0000 Subject: Add javadoc on public things Small other changes, too. --- src/org/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(); -- cgit v1.2.3 From 15bf93de348410fe3bad0aae9d869f04676ffb06 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 12:49:49 +0000 Subject: 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 -- cgit v1.2.3 From 3e158d0afc585e9fddd202c0fb7ddbe3f215fc30 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 16:36:03 +0000 Subject: Some better errors (hopefully more information) Some smaller fixes and some new functions/doc, too --- src/org/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(); } } -- cgit v1.2.3 From 72ab7fb25ffe193aa418ba0ba31fc292d8235e62 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 16:40:45 +0000 Subject: 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()); } -- cgit v1.2.3 From d4901f5999b51398b3a2ff43ba82f356225f4fef Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 16:53:51 +0000 Subject: 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; -- cgit v1.2.3 From dfb4f4e03050757c9226f0a3b089cb18ab29c6f5 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 17:38:25 +0000 Subject: Allow at compile time to enable stacktraces on exceptions --- src/org/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; -- cgit v1.2.3 From 730b44bc73ca25cf0a5747f401bda18d0d010ee7 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 18:19:34 +0000 Subject: 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 { -- cgit v1.2.3 From 05627fbd623411e0c138d5e182b207c222e46e31 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 18:19:42 +0000 Subject: 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; } -- cgit v1.2.3 From 1af5a985b5db356860a622dacda767c85ef444e6 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 18:25:38 +0000 Subject: 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); -- cgit v1.2.3 From 392969629c9fb4953a0a257e866d8538515faa50 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 18:38:15 +0000 Subject: Some better (non-misleading) error msgs Also some reindentation --- src/org/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 -- cgit v1.2.3 From c9f6f56827ce7b368a009c153d1f9995651f6522 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 20:00:28 +0000 Subject: Work on errors and documentation - once more --- src/org/thialfihar/android/apg/ApgService.java | 20 ++-- src/org/thialfihar/android/apg/IApgService.aidl | 9 +- src/org/thialfihar/android/apg/utils/ApgCon.java | 119 +++++++++++------------ 3 files changed, 78 insertions(+), 70 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; /** + * A APG-AIDL-Wrapper + * + *

* This class can be used by other projects to simplify connecting to the - * APG-Service. Kind of wrapper of for AIDL. + * 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 - } - - public static enum ret { + /** + * 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 + } + + 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(); } /** -- cgit v1.2.3 From b5097b7a417b13c288adfbd1c0ea4f6d86715cf1 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 20 Jan 2011 20:23:13 +0000 Subject: 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; -- cgit v1.2.3 From 4b882fa90bd59765d27f8462c505315233d4475c Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:20 +0000 Subject: 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"/> - + -- cgit v1.2.3 From 6b7db8161a158e12344145815534f6552797cf6d Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:27 +0000 Subject: 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 + ")"); -- cgit v1.2.3 From 1ec5fc05412c6d7019dd40497a81397752bee602 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:35 +0000 Subject: Allow to retrieve fingerprints and user ids through AIDL Update ApgCon and doc accordingly. Not very tested. --- src/org/thialfihar/android/apg/ApgService.java | 148 ++++++++++++++++------- src/org/thialfihar/android/apg/IApgService.aidl | 33 ++++- src/org/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()) { -- cgit v1.2.3 From efc5575d56e4888f8335a76a7a44472aa53965ea Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:44 +0000 Subject: Change the way the complete result can be retrieved --- src/org/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 * -- cgit v1.2.3 From cb4f1933d55abeda08623115464e393a886b8032 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:51 +0000 Subject: 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) -- cgit v1.2.3 From 66263ab6e3d9ce3a67e5f10496c0b99a0dcd1752 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:36:59 +0000 Subject: Allow to return itself on callback --- src/org/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; + } + } -- cgit v1.2.3 From 3372e571577481bfa62140a131f5c0dea35936fc Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 23 Jan 2011 21:37:06 +0000 Subject: Allow to retrieve connection status This tells, if a connection to APG *might* be possible (right version of APG found) --- src/org/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 -- cgit v1.2.3 From 1036eb6bd5f89844cf71f171d89f48c342aee217 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 25 Jan 2011 19:38:56 +0000 Subject: Log stacktraces the android way --- src/org/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; -- cgit v1.2.3 From 7278932990d1014bb635905de05ade429f826849 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 25 Jan 2011 19:39:07 +0000 Subject: Make callback use an interface 'the java way'_tm --- src/org/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) - */ - 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) + * @see ApgConInterface */ - 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) - */ - 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) + * @see #set_onCallFinishListener(OnCallFinishListener) */ - 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); + } +} -- cgit v1.2.3 From c497e48817141589624b933cffb6e9e714942818 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Tue, 25 Jan 2011 19:51:35 +0000 Subject: 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); } } -- cgit v1.2.3 From 3be076d0245ceddb483e9972ea0662a8de665e52 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Wed, 18 May 2011 18:19:47 +0000 Subject: Little better log-managing for release-versions of ApgCon --- src/org/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()); -- cgit v1.2.3 From 6502e58c26cddc8472b6b46932250eb1fca88156 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 5 Jun 2011 19:05:18 +0000 Subject: Possibility to not compile Log.d and Log.v in --- src/org/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; -- cgit v1.2.3 From 24205b8dbc6487ee066fec07c9c0840a3be30bb7 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 5 Jun 2011 19:05:57 +0000 Subject: Cleanup of code, AIDL-calls renamed! --- src/org/thialfihar/android/apg/ApgService.java | 320 ++++++++++---------- src/org/thialfihar/android/apg/IApgService.aidl | 48 +-- src/org/thialfihar/android/apg/utils/ApgCon.java | 353 ++++++++++++----------- 3 files changed, 357 insertions(+), 364 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); - - 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); + long curMkey = mCursor.getLong(0); + String curUser = mCursor.getString(1); + + 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); - - 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); + if (FUNCTIONS_OPTIONAL_ARGS.containsKey(pCall)) { + Preferences preferences = Preferences.getPreferences(getBaseContext(), true); + + 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(); } } -- cgit v1.2.3 From 0502be76524cee950fb33aa1e687f70caabf4030 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Sun, 5 Jun 2011 19:47:41 +0000 Subject: Documentation update of ApgCon --- src/org/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: *

      *
    • In your thread, poll {@link #isRunning()}
    • *
    • Supply a callback with {@link #setOnCallFinishListener(OnCallFinishListener)}
    • @@ -396,7 +401,7 @@ public class ApgCon { *

      * *

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

      * @@ -496,10 +501,11 @@ public class ApgCon { * *

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

      + * *

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

      * @@ -524,7 +530,7 @@ public class ApgCon { * Iterates through the errors * *

      - * With this method, you can iterate through all errors. The errors are only + * 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. *

      @@ -543,7 +549,7 @@ public class ApgCon { } /** - * Check, if there are any new errors + * Check if there are any new errors * * @return true, if there are unreturned errors, false otherwise * @@ -576,7 +582,7 @@ public class ApgCon { * Iterates through the warnings * *

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

      @@ -595,7 +601,7 @@ public class ApgCon { } /** - * Check, if there are any new warnings + * Check if there are any new warnings * * @return true, if there are unreturned warnings, false otherwise * @@ -609,20 +615,21 @@ public class ApgCon { * Get the result * *

      - * This gets your mResult. After doing an encryption or decryption with APG, + * 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 mResult will + * Note when your last remote call is unsuccessful, the result will * still have the same value like the last successful call (or null, if no - * call was successful). To ensure you do not work with old call's mResults, + * call was successful). To ensure you do not work with old call's results, * either be sure to {@link #reset()} (or at least {@link #clearResult()}) * your instance before each new call or always check that * {@link #hasNextError()} is false. *

      * * @return the mResult of the last {@link #call(String)} or - * {@link #call_asinc(String)}. + * {@link #callAsync(String)}. * * @see #reset() * @see #clearResult() @@ -633,7 +640,7 @@ public class ApgCon { } /** - * Get the mResult bundle + * Get the result bundle * *

      * Unlike {@link #getResult()}, which only returns any en-/decrypted @@ -645,11 +652,11 @@ public class ApgCon { * For warnings and errors it is suggested to use the functions that are * provided here, namely {@link #getError()}, {@link #getNextError()}, * {@link #get_next_Warning()} etc.), but if any call returns something non - * standard, you have access to the complete mResult bundle to extract the + * standard, you have access to the complete result bundle to extract the * information. *

      * - * @return the complete mResult-bundle of the last call to apg + * @return the complete result bundle of the last call to apg */ public Bundle getResultBundle() { return mResult; @@ -710,7 +717,7 @@ public class ApgCon { } /** - * Checks, whether an async execution is running + * Checks if an async execution is running * *

      * If you started something with {@link #callAsync(String)}, this will @@ -731,15 +738,15 @@ public class ApgCon { * *

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

      * *

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

      */ -- cgit v1.2.3 From e6c86a88922cfc6570d2c96067155c958aa02ee2 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 3 Nov 2011 22:14:37 +0100 Subject: Add .gitignore to ignore eclipse-specific files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..f82656a0e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bin/ +gen/ +.classpath +.project -- cgit v1.2.3 From 8d9b0e1db83f9effa9cb240ad46f1ae2f85df98b Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Thu, 3 Nov 2011 22:15:31 +0100 Subject: Switch to spongycastle https://github.com/rtyley/spongycastle It replaces bouncycastle2. Looks like a cleaner and better integration. A precompiled .jar ist in the "lib/"-dir. --- lib/bcprov-jdk16-146.jar | Bin 0 -> 3759267 bytes project.properties | 11 ++ src/org/thialfihar/android/apg/Apg.java | 121 ++++++++++----------- .../android/apg/AskForSecretKeyPassPhrase.java | 9 +- .../thialfihar/android/apg/DecryptActivity.java | 26 ++--- .../thialfihar/android/apg/EditKeyActivity.java | 18 +-- .../thialfihar/android/apg/EncryptActivity.java | 30 ++--- src/org/thialfihar/android/apg/Id.java | 2 +- .../thialfihar/android/apg/KeyListActivity.java | 26 ++--- src/org/thialfihar/android/apg/Preferences.java | 8 +- .../android/apg/PreferencesActivity.java | 12 +- .../android/apg/PublicKeyListActivity.java | 2 +- .../thialfihar/android/apg/provider/Database.java | 20 ++-- .../android/apg/ui/widget/KeyEditor.java | 16 +-- .../android/apg/ui/widget/SectionView.java | 16 +-- 15 files changed, 162 insertions(+), 155 deletions(-) create mode 100644 lib/bcprov-jdk16-146.jar create mode 100644 project.properties diff --git a/lib/bcprov-jdk16-146.jar b/lib/bcprov-jdk16-146.jar new file mode 100644 index 000000000..66cb1a73b Binary files /dev/null and b/lib/bcprov-jdk16-146.jar differ diff --git a/project.properties b/project.properties new file mode 100644 index 000000000..f049142c1 --- /dev/null +++ b/project.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-10 diff --git a/src/org/thialfihar/android/apg/Apg.java b/src/org/thialfihar/android/apg/Apg.java index 0d61d4f42..bc082d9b6 100644 --- a/src/org/thialfihar/android/apg/Apg.java +++ b/src/org/thialfihar/android/apg/Apg.java @@ -16,6 +16,64 @@ package org.thialfihar.android.apg; +import org.spongycastle.bcpg.ArmoredInputStream; +import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.jce.spec.ElGamalParameterSpec; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPKeyRingGenerator; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPBEEncryptedData; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.PGPV3SignatureGenerator; +import org.thialfihar.android.apg.provider.DataProvider; +import org.thialfihar.android.apg.provider.Database; +import org.thialfihar.android.apg.provider.KeyRings; +import org.thialfihar.android.apg.provider.Keys; +import org.thialfihar.android.apg.provider.UserIds; +import org.thialfihar.android.apg.ui.widget.KeyEditor; +import org.thialfihar.android.apg.ui.widget.SectionView; +import org.thialfihar.android.apg.ui.widget.UserIdEditor; +import org.thialfihar.android.apg.utils.IterableIterator; + +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.os.Message; +import android.view.ViewGroup; + import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; @@ -45,64 +103,6 @@ import java.util.Map; import java.util.Vector; import java.util.regex.Pattern; -import org.bouncycastle2.bcpg.ArmoredInputStream; -import org.bouncycastle2.bcpg.ArmoredOutputStream; -import org.bouncycastle2.bcpg.BCPGOutputStream; -import org.bouncycastle2.bcpg.CompressionAlgorithmTags; -import org.bouncycastle2.bcpg.HashAlgorithmTags; -import org.bouncycastle2.bcpg.SymmetricKeyAlgorithmTags; -import org.bouncycastle2.bcpg.sig.KeyFlags; -import org.bouncycastle2.jce.provider.BouncyCastleProvider; -import org.bouncycastle2.jce.spec.ElGamalParameterSpec; -import org.bouncycastle2.openpgp.PGPCompressedData; -import org.bouncycastle2.openpgp.PGPCompressedDataGenerator; -import org.bouncycastle2.openpgp.PGPEncryptedData; -import org.bouncycastle2.openpgp.PGPEncryptedDataGenerator; -import org.bouncycastle2.openpgp.PGPEncryptedDataList; -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPKeyPair; -import org.bouncycastle2.openpgp.PGPKeyRingGenerator; -import org.bouncycastle2.openpgp.PGPLiteralData; -import org.bouncycastle2.openpgp.PGPLiteralDataGenerator; -import org.bouncycastle2.openpgp.PGPObjectFactory; -import org.bouncycastle2.openpgp.PGPOnePassSignature; -import org.bouncycastle2.openpgp.PGPOnePassSignatureList; -import org.bouncycastle2.openpgp.PGPPBEEncryptedData; -import org.bouncycastle2.openpgp.PGPPrivateKey; -import org.bouncycastle2.openpgp.PGPPublicKey; -import org.bouncycastle2.openpgp.PGPPublicKeyEncryptedData; -import org.bouncycastle2.openpgp.PGPPublicKeyRing; -import org.bouncycastle2.openpgp.PGPSecretKey; -import org.bouncycastle2.openpgp.PGPSecretKeyRing; -import org.bouncycastle2.openpgp.PGPSignature; -import org.bouncycastle2.openpgp.PGPSignatureGenerator; -import org.bouncycastle2.openpgp.PGPSignatureList; -import org.bouncycastle2.openpgp.PGPSignatureSubpacketGenerator; -import org.bouncycastle2.openpgp.PGPSignatureSubpacketVector; -import org.bouncycastle2.openpgp.PGPUtil; -import org.bouncycastle2.openpgp.PGPV3SignatureGenerator; -import org.thialfihar.android.apg.provider.DataProvider; -import org.thialfihar.android.apg.provider.Database; -import org.thialfihar.android.apg.provider.KeyRings; -import org.thialfihar.android.apg.provider.Keys; -import org.thialfihar.android.apg.provider.UserIds; -import org.thialfihar.android.apg.ui.widget.KeyEditor; -import org.thialfihar.android.apg.ui.widget.SectionView; -import org.thialfihar.android.apg.ui.widget.UserIdEditor; -import org.thialfihar.android.apg.utils.IterableIterator; - -import android.app.Activity; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.os.Message; -import android.view.ViewGroup; - public class Apg { private static final String mApgPackageName = "org.thialfihar.android.apg"; @@ -1145,11 +1145,8 @@ public class Apg { if (keyRing == null) { return null; } - try { return keyRing.getPublicKey(keyId); - } catch (PGPException e) { - return null; - } + } public static Vector getKeyRingIds(int type) { diff --git a/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java b/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java index 829244e0d..dc65ff762 100644 --- a/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java +++ b/src/org/thialfihar/android/apg/AskForSecretKeyPassPhrase.java @@ -16,11 +16,10 @@ package org.thialfihar.android.apg; -import org.bouncycastle2.jce.provider.BouncyCastleProvider; -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPPrivateKey; -import org.bouncycastle2.openpgp.PGPSecretKey; -import org.thialfihar.android.apg.Apg.GeneralException; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPSecretKey; import android.app.Activity; import android.app.AlertDialog; diff --git a/src/org/thialfihar/android/apg/DecryptActivity.java b/src/org/thialfihar/android/apg/DecryptActivity.java index 576b6d531..dfa4cb69b 100644 --- a/src/org/thialfihar/android/apg/DecryptActivity.java +++ b/src/org/thialfihar/android/apg/DecryptActivity.java @@ -16,19 +16,9 @@ package org.thialfihar.android.apg; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.Security; -import java.security.SignatureException; -import java.util.regex.Matcher; - -import org.bouncycastle2.jce.provider.BouncyCastleProvider; -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPPublicKeyRing; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPublicKeyRing; import org.thialfihar.android.apg.provider.DataProvider; import android.app.AlertDialog; @@ -53,6 +43,16 @@ import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Security; +import java.security.SignatureException; +import java.util.regex.Matcher; + public class DecryptActivity extends BaseActivity { private long mSignatureKeyId = 0; diff --git a/src/org/thialfihar/android/apg/EditKeyActivity.java b/src/org/thialfihar/android/apg/EditKeyActivity.java index 4bb8899ca..760fbbc73 100644 --- a/src/org/thialfihar/android/apg/EditKeyActivity.java +++ b/src/org/thialfihar/android/apg/EditKeyActivity.java @@ -16,15 +16,9 @@ package org.thialfihar.android.apg; -import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SignatureException; -import java.util.Vector; - -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPSecretKey; -import org.bouncycastle2.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.provider.Database; import org.thialfihar.android.apg.ui.widget.KeyEditor; import org.thialfihar.android.apg.ui.widget.SectionView; @@ -46,6 +40,12 @@ import android.widget.EditText; import android.widget.LinearLayout; import android.widget.Toast; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SignatureException; +import java.util.Vector; + public class EditKeyActivity extends BaseActivity implements OnClickListener { private PGPSecretKeyRing mKeyRing = null; diff --git a/src/org/thialfihar/android/apg/EncryptActivity.java b/src/org/thialfihar/android/apg/EncryptActivity.java index 9ba71f570..2f4f273a6 100644 --- a/src/org/thialfihar/android/apg/EncryptActivity.java +++ b/src/org/thialfihar/android/apg/EncryptActivity.java @@ -16,21 +16,11 @@ package org.thialfihar.android.apg; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SignatureException; -import java.util.Vector; - -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPPublicKey; -import org.bouncycastle2.openpgp.PGPPublicKeyRing; -import org.bouncycastle2.openpgp.PGPSecretKey; -import org.bouncycastle2.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.provider.DataProvider; import org.thialfihar.android.apg.utils.Choice; @@ -55,6 +45,16 @@ import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SignatureException; +import java.util.Vector; + public class EncryptActivity extends BaseActivity { private Intent mIntent = null; private String mSubject = null; diff --git a/src/org/thialfihar/android/apg/Id.java b/src/org/thialfihar/android/apg/Id.java index ebc1ecf87..1ce53eabd 100644 --- a/src/org/thialfihar/android/apg/Id.java +++ b/src/org/thialfihar/android/apg/Id.java @@ -16,7 +16,7 @@ package org.thialfihar.android.apg; -import org.bouncycastle2.bcpg.CompressionAlgorithmTags; +import org.spongycastle.bcpg.CompressionAlgorithmTags; public final class Id { public static final class menu { diff --git a/src/org/thialfihar/android/apg/KeyListActivity.java b/src/org/thialfihar/android/apg/KeyListActivity.java index 57a7f5de1..fc7544d3c 100644 --- a/src/org/thialfihar/android/apg/KeyListActivity.java +++ b/src/org/thialfihar/android/apg/KeyListActivity.java @@ -16,19 +16,9 @@ package org.thialfihar.android.apg; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Vector; - -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPPublicKeyRing; -import org.bouncycastle2.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.provider.KeyRings; import org.thialfihar.android.apg.provider.Keys; import org.thialfihar.android.apg.provider.UserIds; @@ -58,6 +48,16 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Vector; + public class KeyListActivity extends BaseActivity { protected ExpandableListView mList; protected KeyListAdapter mListAdapter; diff --git a/src/org/thialfihar/android/apg/Preferences.java b/src/org/thialfihar/android/apg/Preferences.java index e704d79f3..198294377 100644 --- a/src/org/thialfihar/android/apg/Preferences.java +++ b/src/org/thialfihar/android/apg/Preferences.java @@ -1,13 +1,13 @@ package org.thialfihar.android.apg; -import java.util.Vector; - -import org.bouncycastle2.bcpg.HashAlgorithmTags; -import org.bouncycastle2.openpgp.PGPEncryptedData; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.openpgp.PGPEncryptedData; import android.content.Context; import android.content.SharedPreferences; +import java.util.Vector; + public class Preferences { private static Preferences mPreferences; private SharedPreferences mSharedPreferences; diff --git a/src/org/thialfihar/android/apg/PreferencesActivity.java b/src/org/thialfihar/android/apg/PreferencesActivity.java index 0d0d76318..49ea1a983 100644 --- a/src/org/thialfihar/android/apg/PreferencesActivity.java +++ b/src/org/thialfihar/android/apg/PreferencesActivity.java @@ -16,12 +16,8 @@ package org.thialfihar.android.apg; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Vector; - -import org.bouncycastle2.bcpg.HashAlgorithmTags; -import org.bouncycastle2.openpgp.PGPEncryptedData; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.openpgp.PGPEncryptedData; import org.thialfihar.android.apg.ui.widget.IntegerListPreference; import android.content.Intent; @@ -32,6 +28,10 @@ import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Vector; + public class PreferencesActivity extends PreferenceActivity { private ListPreference mLanguage = null; private IntegerListPreference mPassPhraseCacheTtl = null; diff --git a/src/org/thialfihar/android/apg/PublicKeyListActivity.java b/src/org/thialfihar/android/apg/PublicKeyListActivity.java index 4cc3b4df9..509a81374 100644 --- a/src/org/thialfihar/android/apg/PublicKeyListActivity.java +++ b/src/org/thialfihar/android/apg/PublicKeyListActivity.java @@ -16,7 +16,7 @@ package org.thialfihar.android.apg; -import org.bouncycastle2.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPPublicKeyRing; import android.content.Intent; import android.os.Bundle; diff --git a/src/org/thialfihar/android/apg/provider/Database.java b/src/org/thialfihar/android/apg/provider/Database.java index 05beb980d..92d8ae9fb 100644 --- a/src/org/thialfihar/android/apg/provider/Database.java +++ b/src/org/thialfihar/android/apg/provider/Database.java @@ -1,15 +1,10 @@ package org.thialfihar.android.apg.provider; -import java.io.IOException; -import java.util.Date; -import java.util.HashMap; -import java.util.Vector; - -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPPublicKey; -import org.bouncycastle2.openpgp.PGPPublicKeyRing; -import org.bouncycastle2.openpgp.PGPSecretKey; -import org.bouncycastle2.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.Apg; import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.utils.IterableIterator; @@ -21,6 +16,11 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Vector; + public class Database extends SQLiteOpenHelper { public static class GeneralException extends Exception { static final long serialVersionUID = 0xf812773343L; diff --git a/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java b/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java index dbdae9def..e232c3934 100644 --- a/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java +++ b/src/org/thialfihar/android/apg/ui/widget/KeyEditor.java @@ -16,14 +16,8 @@ package org.thialfihar.android.apg.ui.widget; -import java.text.DateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Vector; - -import org.bouncycastle2.openpgp.PGPPublicKey; -import org.bouncycastle2.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSecretKey; import org.thialfihar.android.apg.Apg; import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.R; @@ -45,6 +39,12 @@ import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Vector; + public class KeyEditor extends LinearLayout implements Editor, OnClickListener { private PGPSecretKey mKey; diff --git a/src/org/thialfihar/android/apg/ui/widget/SectionView.java b/src/org/thialfihar/android/apg/ui/widget/SectionView.java index 124c1c9da..0e3e43784 100644 --- a/src/org/thialfihar/android/apg/ui/widget/SectionView.java +++ b/src/org/thialfihar/android/apg/ui/widget/SectionView.java @@ -16,14 +16,8 @@ package org.thialfihar.android.apg.ui.widget; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Vector; - -import org.bouncycastle2.openpgp.PGPException; -import org.bouncycastle2.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPSecretKey; import org.thialfihar.android.apg.Apg; import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.R; @@ -49,6 +43,12 @@ import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.util.Vector; + public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Runnable { private LayoutInflater mInflater; private View mAdd; -- cgit v1.2.3 From a7294d50b1f6a7f0ab30118602a1fcbdad0b8169 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Fri, 4 Nov 2011 20:53:01 +0100 Subject: Ignore good old mac's .DS_Store ... --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f82656a0e..7deeafce9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ bin/ gen/ .classpath .project +.DS_Store -- cgit v1.2.3 From ad1657465778c05cef7a7ba9d25f97943cf68144 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Fri, 4 Nov 2011 21:22:49 +0100 Subject: Allow to pass large blobs and a new content provider to simplify this Since AIDL is not for passing large data, a blob can be passed to APG by a Uri. This Uri is opened as a file by APG and read/written to. Note the file is overwritten by APG, so make sure it is a copy if you want to keep the original. With the ApgServiceBlobProvider, Apg has an own ContentProvider that can be used like mentioned above. For now the data is stored in the dir where APG stores other files and NOT DELETED after en/decryption. This is tbd. It can only be accessed by an application with the permission "org.thialfihar.android.apg.permission.STORE_BLOBS". ApgCon has been updated accordingly and can handle blobs with `setBlob` and `getBlobResult`. That is a really easy way to en/decrypt large data. Note that encrypting by blob should only be used for large files (1MB+). On all other cases, the data should be passed as as String through the AIDl-Interface, so no temporary file must be created. See ApgCon for a complete example of how to connect to the AIDL and use it. Or use it in your own project! --- AndroidManifest.xml | 13 +- res/values/strings.xml | 2 + src/org/thialfihar/android/apg/ApgService.java | 118 ++++++++++++++---- src/org/thialfihar/android/apg/Constants.java | 3 + .../thialfihar/android/apg/DecryptActivity.java | 13 ++ src/org/thialfihar/android/apg/IApgService.aidl | 18 ++- src/org/thialfihar/android/apg/Id.java | 3 + .../apg/provider/ApgServiceBlobDatabase.java | 54 ++++++++ .../apg/provider/ApgServiceBlobProvider.java | 138 +++++++++++++++++++++ src/org/thialfihar/android/apg/utils/ApgCon.java | 97 +++++++++++++-- 10 files changed, 423 insertions(+), 36 deletions(-) create mode 100644 src/org/thialfihar/android/apg/provider/ApgServiceBlobDatabase.java create mode 100644 src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 937eb488a..e72197138 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -204,12 +204,17 @@ - + + + @@ -219,10 +224,16 @@ android:label="@string/permission_read_key_details_label" android:description="@string/permission_read_key_details_description"/> + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 5b29e4f12..62e0935a9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -288,6 +288,8 @@ Read key details from APG. Read key details of public and secret keys stored in APG, such as key ID and user IDs. The keys themselves can NOT be read. + Store blobs to en/decrypt with APG. + Store and read files on the android file system through APG. It cannot read files of other applications. Encrypt diff --git a/src/org/thialfihar/android/apg/ApgService.java b/src/org/thialfihar/android/apg/ApgService.java index 0a25c6055..46d8b4765 100644 --- a/src/org/thialfihar/android/apg/ApgService.java +++ b/src/org/thialfihar/android/apg/ApgService.java @@ -2,6 +2,7 @@ package org.thialfihar.android.apg; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; @@ -14,17 +15,19 @@ import org.thialfihar.android.apg.provider.KeyRings; import org.thialfihar.android.apg.provider.Keys; import org.thialfihar.android.apg.provider.UserIds; +import android.content.ContentResolver; import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; import android.os.Bundle; import android.os.IBinder; import 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; + public static final boolean LOCAL_LOGV = true; + public static final boolean LOCAL_LOGD = true; @Override public IBinder onBind(Intent intent) { @@ -33,7 +36,7 @@ public class ApgService extends Service { } /** error status */ - private enum error { + private static enum error { ARGUMENTS_MISSING, APG_FAILURE, NO_MATCHING_SECRET_KEY, @@ -44,9 +47,16 @@ public class ApgService extends Service { return ordinal() + 100; } } + + private static enum call { + encrypt_with_passphrase, + encrypt_with_public_key, + decrypt, + get_keys + } /** all arguments that can be passed by calling application */ - private enum arg { + public static enum arg { MESSAGE, // message to encrypt or to decrypt SYMMETRIC_PASSPHRASE, // key for symmetric en/decryption PUBLIC_KEYS, // public keys for encryption @@ -58,10 +68,11 @@ public class ApgService extends Service { SIGNATURE_KEY, // key for signing PRIVATE_KEY_PASSPHRASE, // passphrase for encrypted private key KEY_TYPE, // type of key (private or public) + BLOB, // blob passed } /** all things that might be returned */ - private enum ret { + private static enum ret { ERRORS, // string array list with errors WARNINGS, // string array list with warnings ERROR, // numeric error @@ -75,21 +86,18 @@ public class ApgService extends Service { static { HashSet args = new HashSet(); args.add(arg.SYMMETRIC_PASSPHRASE); - args.add(arg.MESSAGE); - FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_passphrase", args); + FUNCTIONS_REQUIRED_ARGS.put(call.encrypt_with_passphrase.name(), args); args = new HashSet(); args.add(arg.PUBLIC_KEYS); - args.add(arg.MESSAGE); - FUNCTIONS_REQUIRED_ARGS.put("encrypt_with_public_key", args); + FUNCTIONS_REQUIRED_ARGS.put(call.encrypt_with_public_key.name(), args); args = new HashSet(); - args.add(arg.MESSAGE); - FUNCTIONS_REQUIRED_ARGS.put("decrypt", args); + FUNCTIONS_REQUIRED_ARGS.put(call.decrypt.name(), args); args = new HashSet(); args.add(arg.KEY_TYPE); - FUNCTIONS_REQUIRED_ARGS.put("get_keys", args); + FUNCTIONS_REQUIRED_ARGS.put(call.get_keys.name(), args); } /** optional arguments for each AIDL function */ @@ -103,14 +111,18 @@ public class ApgService extends Service { args.add(arg.COMPRESSION); 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.add(arg.BLOB); + args.add(arg.MESSAGE); + FUNCTIONS_OPTIONAL_ARGS.put(call.encrypt_with_passphrase.name(), args); + FUNCTIONS_OPTIONAL_ARGS.put(call.encrypt_with_public_key.name(), args); args = new HashSet(); args.add(arg.SYMMETRIC_PASSPHRASE); args.add(arg.PUBLIC_KEYS); args.add(arg.PRIVATE_KEY_PASSPHRASE); - FUNCTIONS_OPTIONAL_ARGS.put("decrypt", args); + args.add(arg.MESSAGE); + args.add(arg.BLOB); + FUNCTIONS_OPTIONAL_ARGS.put(call.decrypt.name(), args); } /** a map from ApgService parameters to function calls to get the default */ @@ -136,6 +148,14 @@ public class ApgService extends Service { Log.e(TAG, "Function method exception: " + e.getMessage()); } } + + private static void writeToOutputStream(InputStream is, OutputStream os) throws IOException { + byte[] buffer = new byte[8]; + int len = 0; + while( (len = is.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + } private static Cursor getKeyEntries(HashMap pParams) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); @@ -304,6 +324,16 @@ public class ApgService extends Service { } } } + + if(pFunction.equals(call.encrypt_with_passphrase.name()) || + pFunction.equals(call.encrypt_with_public_key.name()) || + pFunction.equals(call.decrypt.name())) { + // check that either MESSAGE or BLOB are there + if( !pArgs.containsKey(arg.MESSAGE.name()) && !pArgs.containsKey(arg.BLOB.name())) { + pReturn.getStringArrayList(ret.ERRORS.name()).add("Arguments missing: Neither MESSAGE nor BLOG found"); + } + + } } /** @@ -378,6 +408,7 @@ public class ApgService extends Service { } private boolean encrypt(Bundle pArgs, Bundle pReturn) { + boolean isBlob = pArgs.containsKey(arg.BLOB.name()); long pubMasterKeys[] = {}; if (pArgs.containsKey(arg.PUBLIC_KEYS.name())) { @@ -391,7 +422,17 @@ public class ApgService extends Service { pubMasterKeys = getMasterKey(pubKeys, pReturn); } - InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); + InputStream inStream = null; + if(isBlob) { + ContentResolver cr = getContentResolver(); + try { + inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name()))); + } catch (Exception e) { + Log.e(TAG, "... exception on opening blob", e); + } + } else { + inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); + } InputData in = new InputData(inStream, 0); // XXX Size second param? OutputStream out = new ByteArrayOutputStream(); @@ -427,7 +468,18 @@ public class ApgService extends Service { return false; } if( LOCAL_LOGV ) Log.v(TAG, "Encrypted"); - pReturn.putString(ret.RESULT.name(), out.toString()); + if(isBlob) { + ContentResolver cr = getContentResolver(); + try { + OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB.name()))); + writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()), outStream); + outStream.close(); + } catch (Exception e) { + Log.e(TAG, "... exception on writing blob", e); + } + } else { + pReturn.putString(ret.RESULT.name(), out.toString()); + } return true; } @@ -481,11 +533,24 @@ public class ApgService extends Service { if (!prepareArgs("decrypt", pArgs, pReturn)) { return false; } + + boolean isBlob = pArgs.containsKey(arg.BLOB.name()); String passphrase = pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) != null ? pArgs.getString(arg.SYMMETRIC_PASSPHRASE.name()) : pArgs .getString(arg.PRIVATE_KEY_PASSPHRASE.name()); - InputStream inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); + InputStream inStream = null; + if(isBlob) { + ContentResolver cr = getContentResolver(); + try { + inStream = cr.openInputStream(Uri.parse(pArgs.getString(arg.BLOB.name()))); + } catch (Exception e) { + Log.e(TAG, "... exception on opening blob", e); + } + } else { + inStream = new ByteArrayInputStream(pArgs.getString(arg.MESSAGE.name()).getBytes()); + } + InputData in = new InputData(inStream, 0); // XXX what size in second parameter? OutputStream out = new ByteArrayOutputStream(); if( LOCAL_LOGV ) Log.v(TAG, "About to decrypt"); @@ -508,9 +573,20 @@ public class ApgService extends Service { } return false; } - if( LOCAL_LOGV ) Log.v(TAG, "Decrypted"); - - pReturn.putString(ret.RESULT.name(), out.toString()); + if( LOCAL_LOGV ) Log.v(TAG, "... decrypted"); + + if(isBlob) { + ContentResolver cr = getContentResolver(); + try { + OutputStream outStream = cr.openOutputStream(Uri.parse(pArgs.getString(arg.BLOB.name()))); + writeToOutputStream(new ByteArrayInputStream(out.toString().getBytes()), outStream); + outStream.close(); + } catch (Exception e) { + Log.e(TAG, "... exception on writing blob", e); + } + } else { + pReturn.putString(ret.RESULT.name(), out.toString()); + } return true; } diff --git a/src/org/thialfihar/android/apg/Constants.java b/src/org/thialfihar/android/apg/Constants.java index 89751e268..bd0746085 100644 --- a/src/org/thialfihar/android/apg/Constants.java +++ b/src/org/thialfihar/android/apg/Constants.java @@ -19,6 +19,9 @@ package org.thialfihar.android.apg; import android.os.Environment; public final class Constants { + + public static final String tag = "APG"; + public static final class path { public static final String app_dir = Environment.getExternalStorageDirectory() + "/APG"; } diff --git a/src/org/thialfihar/android/apg/DecryptActivity.java b/src/org/thialfihar/android/apg/DecryptActivity.java index dfa4cb69b..a10a168de 100644 --- a/src/org/thialfihar/android/apg/DecryptActivity.java +++ b/src/org/thialfihar/android/apg/DecryptActivity.java @@ -30,6 +30,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.text.ClipboardManager; +import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.animation.AnimationUtils; @@ -189,19 +190,28 @@ public class DecryptActivity extends BaseActivity { // ignore, then } } else if (Apg.Intent.DECRYPT.equals(mIntent.getAction())) { + Log.d(Constants.tag, "Apg Intent DECRYPT startet"); Bundle extras = mIntent.getExtras(); if (extras == null) { + Log.d(Constants.tag, "extra bundle was null"); extras = new Bundle(); + } else { + Log.d(Constants.tag, "got extras"); } mData = extras.getByteArray(Apg.EXTRA_DATA); String textData = null; if (mData == null) { + Log.d(Constants.tag, "EXTRA_DATA was null"); textData = extras.getString(Apg.EXTRA_TEXT); + } else { + Log.d(Constants.tag, "Got data from EXTRA_DATA"); } if (textData != null) { + Log.d(Constants.tag, "textData null, matching text ..."); Matcher matcher = Apg.PGP_MESSAGE.matcher(textData); if (matcher.matches()) { + Log.d(Constants.tag, "PGP_MESSAGE matched"); textData = matcher.group(1); // replace non breakable spaces textData = textData.replaceAll("\\xa0", " "); @@ -209,11 +219,14 @@ public class DecryptActivity extends BaseActivity { } else { matcher = Apg.PGP_SIGNED_MESSAGE.matcher(textData); if (matcher.matches()) { + Log.d(Constants.tag, "PGP_SIGNED_MESSAGE matched"); textData = matcher.group(1); // replace non breakable spaces textData = textData.replaceAll("\\xa0", " "); mMessage.setText(textData); mDecryptButton.setText(R.string.btn_verify); + } else { + Log.d(Constants.tag, "Nothing matched!"); } } } diff --git a/src/org/thialfihar/android/apg/IApgService.aidl b/src/org/thialfihar/android/apg/IApgService.aidl index df46805ac..25780f366 100644 --- a/src/org/thialfihar/android/apg/IApgService.aidl +++ b/src/org/thialfihar/android/apg/IApgService.aidl @@ -27,6 +27,11 @@ interface IApgService { * * (required) * String "MESSAGE" = Message to encrypt + * OR + * String "BLOB" = ContentUri to a file handle + * with binary data to encrypt + * (Attention: file will be overwritten + * with encrypted content!) * * (optional) * int "ENCRYPTION_ALGORYTHM" = Encryption Algorithm @@ -55,7 +60,8 @@ interface IApgService { * String "PRIVATE_KEY_PASSPHRASE" = Passphrase for signing key * * Bundle returnVals (in addition to the ERRORS/WARNINGS above): - * String "RESULT" = Encrypted message + * If "MESSAGE" was set: + * String "RESULT" = Encrypted message */ /* Additional argument for function below: @@ -77,7 +83,12 @@ interface IApgService { /* Bundle params: * (required) - * String "MESSAGE" = Message to decrypt + * String "MESSAGE" = Message to dencrypt + * OR + * String "BLOB" = ContentUri to a file handle + * with binary data to dencrypt + * (Attention: file will be overwritten + * with dencrypted content!) * * (optional) * String "SYMMETRIC_PASSPHRASE" = Symmetric passphrase for decryption @@ -86,7 +97,8 @@ interface IApgService { * String "PRIVATE_KEY_PASSPHRASE" = Private keys's passphrase on asymmetric encryption * * Bundle return_vals: - * String "RESULT" = Decrypted message + * If "MESSAGE" was set: + * String "RESULT" = Decrypted message */ boolean decrypt(in Bundle params, out Bundle returnVals); diff --git a/src/org/thialfihar/android/apg/Id.java b/src/org/thialfihar/android/apg/Id.java index 1ce53eabd..2b486e84a 100644 --- a/src/org/thialfihar/android/apg/Id.java +++ b/src/org/thialfihar/android/apg/Id.java @@ -19,6 +19,9 @@ package org.thialfihar.android.apg; import org.spongycastle.bcpg.CompressionAlgorithmTags; public final class Id { + + public static final String TAG = "APG"; + public static final class menu { public static final int export = 0x21070001; public static final int delete = 0x21070002; diff --git a/src/org/thialfihar/android/apg/provider/ApgServiceBlobDatabase.java b/src/org/thialfihar/android/apg/provider/ApgServiceBlobDatabase.java new file mode 100644 index 000000000..9a891ddfa --- /dev/null +++ b/src/org/thialfihar/android/apg/provider/ApgServiceBlobDatabase.java @@ -0,0 +1,54 @@ +package org.thialfihar.android.apg.provider; + +import org.thialfihar.android.apg.ApgService; + +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.net.Uri; +import android.util.Log; + +public class ApgServiceBlobDatabase extends SQLiteOpenHelper { + + private static final String TAG = "ApgServiceBlobDatabase"; + + private static final int VERSION = 1; + private static final String NAME = "apg_service_blob_data"; + private static final String TABLE = "data"; + + public ApgServiceBlobDatabase(Context context) { + super(context, NAME, null, VERSION); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "constructor called"); + } + + @Override + public void onCreate(SQLiteDatabase db) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "onCreate() called"); + db.execSQL("create table " + TABLE + " ( _id integer primary key autoincrement," + + "key text not null)"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "onUpgrade() called"); + // no upgrade necessary yet + } + + public Uri insert(ContentValues vals) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "insert() called"); + SQLiteDatabase db = this.getWritableDatabase(); + long newId = db.insert(TABLE, null, vals); + return ContentUris.withAppendedId(ApgServiceBlobProvider.CONTENT_URI, newId); + } + + public Cursor query(String id, String key) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "query() called"); + SQLiteDatabase db = this.getReadableDatabase(); + return db.query(TABLE, new String[] {"_id"}, + "_id = ? and key = ?", new String[] {id, key}, + null, null, null); + } +} diff --git a/src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java b/src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java new file mode 100644 index 000000000..fd4145f4c --- /dev/null +++ b/src/org/thialfihar/android/apg/provider/ApgServiceBlobProvider.java @@ -0,0 +1,138 @@ +package org.thialfihar.android.apg.provider; + +import org.thialfihar.android.apg.ApgService; +import org.thialfihar.android.apg.Constants; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +public class ApgServiceBlobProvider extends ContentProvider { + + private static final String TAG = "ApgServiceBlobProvider"; + + public static final Uri CONTENT_URI = Uri.parse("content://org.thialfihar.android.apg.provider.apgserviceblobprovider"); + + private static final String COLUMN_KEY = "key"; + + private static final String STORE_PATH = Constants.path.app_dir+"/ApgServiceBlobs"; + + private ApgServiceBlobDatabase mDb = null; + + public ApgServiceBlobProvider() { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "Constructor called"); + File dir = new File(STORE_PATH); + dir.mkdirs(); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "Constructor finished"); + } + + @Override + public int delete(Uri arg0, String arg1, String[] arg2) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "delete() called"); + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getType(Uri arg0) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "getType() called"); + // not needed for now + return null; + } + + @Override + public Uri insert(Uri uri, ContentValues ignored) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "insert() called"); + // ContentValues are actually ignored, because we want to store a blob with no more information + // but have to create an record with the password generated here first + + ContentValues vals = new ContentValues(); + + // Insert a random key in the database. This has to provided by the caller when updating or + // getting the blob + String password = UUID.randomUUID().toString(); + vals.put(COLUMN_KEY, password); + + Uri insertedUri = mDb.insert(vals); + return Uri.withAppendedPath(insertedUri, password); + } + + @Override + public boolean onCreate() { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "onCreate() called"); + mDb = new ApgServiceBlobDatabase(getContext()); + // TODO Auto-generated method stub + return true; + } + + @Override + public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "query() called"); + // TODO Auto-generated method stub + return null; + } + + @Override + public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "update() called"); + // TODO Auto-generated method stub + return 0; + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException, FileNotFoundException { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "openFile() called"); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... with uri: "+uri.toString()); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... with mode: "+mode); + + List segments = uri.getPathSegments(); + if(segments.size() < 2) { + throw new SecurityException("Password not found in URI"); + } + String id = segments.get(0); + String key = segments.get(1); + + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... got id: "+id); + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... and key: "+key); + + // get the data + Cursor result = mDb.query(id, key); + + if(result.getCount() == 0) { + // either the key is wrong or no id exists + throw new FileNotFoundException("No file found with that ID and/or password"); + } + + File targetFile = new File(STORE_PATH, id); + if(mode.equals("w")) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... will try to open file w"); + if( !targetFile.exists() ) { + try { + targetFile.createNewFile(); + } catch (IOException e) { + Log.e(TAG, "... got IEOException on creating new file", e); + throw new FileNotFoundException("Could not create file to write to"); + } + } + return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE ); + } else if(mode.equals("r")) { + if(ApgService.LOCAL_LOGD) Log.d(TAG, "... will try to open file r"); + if( !targetFile.exists() ) { + throw new FileNotFoundException("Error: Could not find the file requested"); + } + return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY); + } + + return null; + } + +} diff --git a/src/org/thialfihar/android/apg/utils/ApgCon.java b/src/org/thialfihar/android/apg/utils/ApgCon.java index 475f7e9a9..c46ccf6b1 100644 --- a/src/org/thialfihar/android/apg/utils/ApgCon.java +++ b/src/org/thialfihar/android/apg/utils/ApgCon.java @@ -16,22 +16,27 @@ package org.thialfihar.android.apg.utils; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; +import org.thialfihar.android.apg.IApgService; +import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener; -import android.content.Context; import android.content.ComponentName; -import android.content.ServiceConnection; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; +import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.IBinder; import android.util.Log; -import org.thialfihar.android.apg.IApgService; -import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; /** * A APG-AIDL-Wrapper @@ -46,7 +51,7 @@ import org.thialfihar.android.apg.utils.ApgConInterface.OnCallFinishListener; *

      * * @author Markus Doits - * @version 1.0rc1 + * @version 1.1rc1 * */ public class ApgCon { @@ -54,7 +59,8 @@ public class ApgCon { private static final boolean LOCAL_LOGD = true; private final static String TAG = "ApgCon"; - private final static int API_VERSION = 1; // aidl api-version it expects + private final static int API_VERSION = 2; // aidl api-version it expects + private final static String BLOB_URI = "content://org.thialfihar.android.apg.provider.apgserviceblobprovider"; /** * How many seconds to wait for a connection to AGP when connecting. @@ -80,7 +86,6 @@ public class ApgCon { } - private final Context mContext; private final error mConnectionStatus; private boolean mAsyncRunning = false; @@ -187,9 +192,9 @@ public class ApgCon { 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, "Found ApgService API version " + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION); Log.w(TAG, "This probably won't work!"); - mWarningList.add("(LOCAL) Found ApgService API version" + inf.metaData.getInt("api_version") + " but exspected " + API_VERSION); + 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"); @@ -495,6 +500,41 @@ public class ApgCon { } mArgs.putIntegerArrayList(key, list); } + + /** + * Set up binary data to en/decrypt + * + * @param is + * InputStream to get the data from + */ + public void setBlob(InputStream is) { + if( LOCAL_LOGD ) Log.d(TAG, "setBlob() called"); + // 1. get the new contentUri + ContentResolver cr = mContext.getContentResolver(); + Uri contentUri = cr.insert(Uri.parse(BLOB_URI), new ContentValues()); + + // 2. insert binary data + OutputStream os = null; + try { + os = cr.openOutputStream(contentUri, "w"); + } catch( Exception e ) { + Log.e(TAG, "... exception on setBlob", e); + } + + byte[] buffer = new byte[8]; + int len = 0; + try { + while( (len = is.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + if(LOCAL_LOGD) Log.d(TAG, "... write finished, now closing"); + os.close(); + } catch (Exception e) { + Log.e(TAG, "... error on writing buffer", e); + } + + mArgs.putString("BLOB", contentUri.toString() ); + } /** * Clears all arguments @@ -628,17 +668,52 @@ public class ApgCon { * {@link #hasNextError()} is false. *

      * + *

      + * Note: When handling binary data with {@link #setBlob(InputStream)}, you + * get your result with {@link #getBlobResult()}. + *

      + * * @return the mResult of the last {@link #call(String)} or * {@link #callAsync(String)}. * * @see #reset() * @see #clearResult() * @see #getResultBundle() + * @see #getBlobResult() */ public String getResult() { return mResult.getString(ret.RESULT.name()); } + /** + * Get the binary result + * + *

      + * This gets your binary result. It only works if you called {@link #setBlob(InputStream)} before. + * + * If you did not call encrypt nor decrypt, this will be the same data as you inputed. + *

      + * + * @return InputStream of the binary data which was en/decrypted + * + * @see #setBlob(InputStream) + * @see #getResult() + */ + public InputStream getBlobResult() { + if(mArgs.containsKey("BLOB")) { + ContentResolver cr = mContext.getContentResolver(); + InputStream in = null; + try { + in = cr.openInputStream(Uri.parse(mArgs.getString("BLOB"))); + } catch( Exception e ) { + Log.e(TAG, "Could not return blob in result", e); + } + return in; + } else { + return null; + } + } + /** * Get the result bundle * -- cgit v1.2.3