diff --git a/README.md b/README.md index 29f4f47d0..b70f68536 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ See http://docs.oseems.com/general/application/eclipse/fix-gc-overhead-limit-exc 1. Open svg file in Inkscape 2. Extensions -> Color -> darker (2 times!) -# Security Concept +# Security Model ## Basic goals @@ -83,7 +83,7 @@ Android primitives to exchange data: Intent, Intent with return values, Send (al * DECRYPT * DECRYPT_FILE -### With permission +### With permission ACCESS_API * CREATE_KEY * ENCRYPT_AND_RETURN @@ -100,9 +100,9 @@ Android primitives to exchange data: Intent, Intent with return values, Send (al ## Remote Service -* The whole service requires a permission +* The whole service requires the permission ACCESS_API ## Resulting permission -* Read key information (not the actual keys)(content provider) -* Encrypt/Sign/Decrypt/Create keys (intents, remote service) without user interaction \ No newline at end of file +* READ_KEY_DATABASE: Read key information (not the actual keys)(content provider) +* ACCESS_API: Encrypt/Sign/Decrypt/Create keys without user interaction (intents, remote service) \ No newline at end of file diff --git a/org_apg/AndroidManifest.xml b/org_apg/AndroidManifest.xml index eba3f840e..05034de95 100644 --- a/org_apg/AndroidManifest.xml +++ b/org_apg/AndroidManifest.xml @@ -53,15 +53,23 @@ + + @@ -353,16 +361,19 @@ + - - + android:readPermission="org.thialfihar.android.apg.permission.READ_KEY_DATABASE" /> + + android:permission="org.thialfihar.android.apg.permission.ACCESS_API" /> diff --git a/org_apg/res/values/strings.xml b/org_apg/res/values/strings.xml index 3f1692023..fe807e36c 100644 --- a/org_apg/res/values/strings.xml +++ b/org_apg/res/values/strings.xml @@ -229,7 +229,7 @@ Successfully validated and imported key Long press one entry in this list to show more options! This list is empty! - + done. initializing… @@ -298,11 +298,13 @@ querying %s… - 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. - + APG + Permissions to use APG + Read key details of public and secret keys (The keys themselves can NOT be read.) + 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. + Encrypt/Sign/Decrypt/Create keys without user interaction + Encrypt/Sign/Decrypt/Create keys (by using Intents or Remote Service) without user interaction + Encrypt Decrypt diff --git a/org_apg/src/org/thialfihar/android/apg/Constants.java b/org_apg/src/org/thialfihar/android/apg/Constants.java index 97e70bbea..95ab8158d 100644 --- a/org_apg/src/org/thialfihar/android/apg/Constants.java +++ b/org_apg/src/org/thialfihar/android/apg/Constants.java @@ -20,11 +20,15 @@ import android.os.Environment; public final class Constants { + public static final boolean DEBUG = true; + public static final String TAG = "APG"; public static final String PACKAGE_NAME = "org.thialfihar.android.apg"; - public static final boolean DEBUG = true; + public static final String PERMISSION_ACCESS_KEY_DATABASE = PACKAGE_NAME + + ".permission.ACCESS_KEY_DATABASE"; + public static final String PERMISSION_ACCESS_API = PACKAGE_NAME + ".permission.ACCESS_API"; /* * TODO: @@ -37,7 +41,7 @@ public final class Constants { * * - even better and shorter (without .android.): org.apg.action.DECRYPT */ - public static final String INTENT_PREFIX = "org.thialfihar.android.apg.intent."; + public static final String INTENT_PREFIX = PACKAGE_NAME + ".intent."; public static final class path { public static final String APP_DIR = Environment.getExternalStorageDirectory() + "/APG"; diff --git a/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java b/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java index 531ae20fb..7d618406b 100644 --- a/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java +++ b/org_apg/src/org/thialfihar/android/apg/helper/OtherHelper.java @@ -23,13 +23,17 @@ import java.util.Iterator; import java.util.Set; import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.R; import org.thialfihar.android.apg.util.Log; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockFragmentActivity; +import android.app.Activity; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Bundle; +import android.widget.Toast; public class OtherHelper { @@ -117,6 +121,45 @@ public class OtherHelper { } } + /** + * Check if the calling package has the needed permission to invoke an intent with specific + * restricted actions. + * + * If pkgName is null, this will also deny the use of the given action + * + * @param activity + * @param pkgName + * @param permName + * @param action + * @param restrictedActions + */ + public static void checkPackagePermissionForActions(Activity activity, String pkgName, + String permName, String action, String[] restrictedActions) { + if (action != null) { + PackageManager pkgManager = activity.getPackageManager(); + + for (int i = 0; i < restrictedActions.length; i++) { + if (restrictedActions[i].equals(action)) { + if (pkgName != null + && pkgManager.checkPermission(permName, pkgName) == PackageManager.PERMISSION_GRANTED) { + Log.d(Constants.TAG, pkgName + " has permission " + permName + ". Action " + + action + " was granted!"); + } else { + String error = pkgName + " does NOT have permission " + permName + ". Action " + + action + " was NOT granted!"; + Log.e(Constants.TAG, error); + Toast.makeText(activity, activity.getString(R.string.errorMessage, error), + Toast.LENGTH_LONG).show(); + + // end activity + activity.setResult(Activity.RESULT_CANCELED, null); + activity.finish(); + } + } + } + } + } + /** * Splits userId string into naming part and email part * diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java index 235d2d8ca..c68eec750 100644 --- a/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java @@ -57,9 +57,11 @@ public class ApgContract { public static final int SECRET = 1; } - public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME; + public static final String CONTENT_AUTHORITY_EXTERNAL = Constants.PACKAGE_NAME; + public static final String CONTENT_AUTHORITY_INTERNAL = Constants.PACKAGE_NAME + ".internal"; - private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); + private static final Uri BASE_CONTENT_URI_INTERNAL = Uri.parse("content://" + + CONTENT_AUTHORITY_INTERNAL); public static final String BASE_KEY_RINGS = "key_rings"; public static final String BASE_DATA = "data"; @@ -75,7 +77,7 @@ public class ApgContract { public static final String PATH_KEYS = "keys"; public static class KeyRings implements KeyRingsColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() .appendPath(BASE_KEY_RINGS).build(); /** Use if multiple items get returned */ @@ -132,7 +134,7 @@ public class ApgContract { } public static class Keys implements KeysColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() .appendPath(BASE_KEY_RINGS).build(); /** Use if multiple items get returned */ @@ -163,7 +165,7 @@ public class ApgContract { } public static class UserIds implements UserIdsColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() .appendPath(BASE_KEY_RINGS).build(); /** Use if multiple items get returned */ @@ -194,8 +196,8 @@ public class ApgContract { } public static class DataStream { - public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(BASE_DATA) - .build(); + public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() + .appendPath(BASE_DATA).build(); public static Uri buildDataStreamUri(String streamFilename) { return CONTENT_URI.buildUpon().appendPath(streamFilename).build(); diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java index 8e93365b7..10bc3cee5 100644 --- a/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java @@ -47,8 +47,6 @@ import android.provider.BaseColumns; import android.text.TextUtils; public class ApgProvider extends ContentProvider { - private static final UriMatcher sUriMatcher = buildUriMatcher(); - private static final int PUBLIC_KEY_RING = 101; private static final int PUBLIC_KEY_RING_BY_ROW_ID = 102; private static final int PUBLIC_KEY_RING_BY_MASTER_KEY_ID = 103; @@ -75,13 +73,22 @@ public class ApgProvider extends ContentProvider { private static final int DATA_STREAM = 301; + protected static boolean sInternalProvider; + protected static UriMatcher sUriMatcher; + /** * Build and return a {@link UriMatcher} that catches all {@link Uri} variations supported by * this {@link ContentProvider}. */ - private static UriMatcher buildUriMatcher() { + protected static UriMatcher buildUriMatcher(boolean internalProvider) { final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); - final String authority = ApgContract.CONTENT_AUTHORITY; + + String authority; + if (internalProvider) { + authority = ApgContract.CONTENT_AUTHORITY_INTERNAL; + } else { + authority = ApgContract.CONTENT_AUTHORITY_EXTERNAL; + } /** * public key rings @@ -283,8 +290,66 @@ public class ApgProvider extends ContentProvider { return type; } - private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, - HashMap projectionMap, int match, boolean isMasterKey, String sortOrder) { + /** + * Set result of query to specific columns, don't show blob column for external content provider + * + * @return + */ + private HashMap getProjectionMapForKeyRings() { + HashMap projectionMap = new HashMap(); + + projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); + projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + + KeyRingsColumns.MASTER_KEY_ID); + // only give out keyRing blob when we are using the internal content provider + if (sInternalProvider) { + projectionMap.put(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "." + + KeyRingsColumns.KEY_RING_DATA); + } + projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID); + + return projectionMap; + } + + /** + * Set result of query to specific columns, don't show blob column for external content provider + * + * @return + */ + private HashMap getProjectionMapForKeys() { + HashMap projectionMap = new HashMap(); + + projectionMap.put(BaseColumns._ID, BaseColumns._ID); + projectionMap.put(KeysColumns.KEY_ID, KeysColumns.KEY_ID); + projectionMap.put(KeysColumns.IS_MASTER_KEY, KeysColumns.IS_MASTER_KEY); + projectionMap.put(KeysColumns.ALGORITHM, KeysColumns.ALGORITHM); + projectionMap.put(KeysColumns.KEY_SIZE, KeysColumns.KEY_SIZE); + projectionMap.put(KeysColumns.CAN_SIGN, KeysColumns.CAN_SIGN); + projectionMap.put(KeysColumns.CAN_ENCRYPT, KeysColumns.CAN_ENCRYPT); + projectionMap.put(KeysColumns.IS_REVOKED, KeysColumns.IS_REVOKED); + projectionMap.put(KeysColumns.CREATION, KeysColumns.CREATION); + projectionMap.put(KeysColumns.EXPIRY, KeysColumns.EXPIRY); + projectionMap.put(KeysColumns.KEY_RING_ROW_ID, KeysColumns.KEY_RING_ROW_ID); + // only give out keyRing blob when we are using the internal content provider + if (sInternalProvider) { + projectionMap.put(KeysColumns.KEY_DATA, KeysColumns.KEY_DATA); + } + projectionMap.put(KeysColumns.RANK, KeysColumns.RANK); + + return projectionMap; + } + + /** + * Builds default query for keyRings: KeyRings table is joined with Keys and UserIds + * + * @param qb + * @param match + * @param isMasterKey + * @param sortOrder + * @return + */ + private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, int match, + boolean isMasterKey, String sortOrder) { qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = "); qb.appendWhereEscapeString(Integer.toString(getKeyType(match))); @@ -300,14 +365,7 @@ public class ApgProvider extends ContentProvider { + Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " AND " + Tables.USER_IDS + "." + UserIdsColumns.RANK + " = '0')"); - projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); - projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." - + KeyRingsColumns.MASTER_KEY_ID); - projectionMap.put(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "." - + KeyRingsColumns.KEY_RING_DATA); - projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID); - - qb.setProjectionMap(projectionMap); + qb.setProjectionMap(getProjectionMapForKeyRings()); return qb; } @@ -322,14 +380,12 @@ public class ApgProvider extends ContentProvider { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); SQLiteDatabase db = mApgDatabase.getReadableDatabase(); - HashMap projectionMap = new HashMap(); - int match = sUriMatcher.match(uri); switch (match) { case PUBLIC_KEY_RING: case SECRET_KEY_RING: - qb = buildKeyRingQuery(qb, projectionMap, match, true, sortOrder); + qb = buildKeyRingQuery(qb, match, true, sortOrder); if (TextUtils.isEmpty(sortOrder)) { sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; @@ -339,7 +395,7 @@ public class ApgProvider extends ContentProvider { case PUBLIC_KEY_RING_BY_ROW_ID: case SECRET_KEY_RING_BY_ROW_ID: - qb = buildKeyRingQuery(qb, projectionMap, match, true, sortOrder); + qb = buildKeyRingQuery(qb, match, true, sortOrder); qb.appendWhere(" AND " + Tables.KEY_RINGS + "." + BaseColumns._ID + " = "); qb.appendWhereEscapeString(uri.getLastPathSegment()); @@ -352,7 +408,7 @@ public class ApgProvider extends ContentProvider { case PUBLIC_KEY_RING_BY_MASTER_KEY_ID: case SECRET_KEY_RING_BY_MASTER_KEY_ID: - qb = buildKeyRingQuery(qb, projectionMap, match, true, sortOrder); + qb = buildKeyRingQuery(qb, match, true, sortOrder); qb.appendWhere(" AND " + Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = "); qb.appendWhereEscapeString(uri.getLastPathSegment()); @@ -365,7 +421,7 @@ public class ApgProvider extends ContentProvider { case SECRET_KEY_RING_BY_KEY_ID: case PUBLIC_KEY_RING_BY_KEY_ID: - qb = buildKeyRingQuery(qb, projectionMap, match, false, sortOrder); + qb = buildKeyRingQuery(qb, match, false, sortOrder); qb.appendWhere(" AND " + Tables.KEYS + "." + KeysColumns.KEY_ID + " = "); qb.appendWhereEscapeString(uri.getLastPathSegment()); @@ -389,15 +445,7 @@ public class ApgProvider extends ContentProvider { + Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " AND " + Tables.USER_IDS + "." + UserIdsColumns.RANK + " = '0')"); - projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); - projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." - + KeyRingsColumns.MASTER_KEY_ID); - projectionMap.put(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "." - + KeyRingsColumns.KEY_RING_DATA); - projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." - + UserIdsColumns.USER_ID); - - qb.setProjectionMap(projectionMap); + qb.setProjectionMap(getProjectionMapForKeyRings()); String emails = uri.getLastPathSegment(); String chunks[] = emails.split(" *, *"); @@ -434,6 +482,8 @@ public class ApgProvider extends ContentProvider { qb.appendWhere(" AND " + KeysColumns.KEY_RING_ROW_ID + " = "); qb.appendWhereEscapeString(uri.getPathSegments().get(2)); + qb.setProjectionMap(getProjectionMapForKeys()); + break; case PUBLIC_KEY_RING_KEY_BY_ROW_ID: @@ -448,6 +498,8 @@ public class ApgProvider extends ContentProvider { qb.appendWhere(" AND " + BaseColumns._ID + " = "); qb.appendWhereEscapeString(uri.getLastPathSegment()); + qb.setProjectionMap(getProjectionMapForKeys()); + break; case PUBLIC_KEY_RING_USER_ID: diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgProviderExternal.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgProviderExternal.java new file mode 100644 index 000000000..61cca8bed --- /dev/null +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgProviderExternal.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 Dominik Schürmann + * + * 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.provider; + +/** + * The same content provider as ApgProviderInternal except that it does not give out keyRing and key + * blob data when querying. + * + * This provider is exported with a readPermission in AndroidManifest.xml + */ +public class ApgProviderExternal extends ApgProvider { + + static { + sInternalProvider = false; + sUriMatcher = buildUriMatcher(sInternalProvider); + } + +} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgProviderInternal.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgProviderInternal.java new file mode 100644 index 000000000..e2226a0fa --- /dev/null +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgProviderInternal.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 Dominik Schürmann + * + * 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.provider; + +/** + * This provider is NOT exported in AndroidManifest.xml as it also return the actual secret keys + * from the database + */ +public class ApgProviderInternal extends ApgProvider { + + static { + sInternalProvider = true; + sUriMatcher = buildUriMatcher(sInternalProvider); + } + +} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java b/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java index 6b3e94938..915c0aea5 100644 --- a/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java +++ b/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java @@ -232,7 +232,7 @@ public class ProviderHelper { } try { - context.getContentResolver().applyBatch(ApgContract.CONTENT_AUTHORITY, operations); + context.getContentResolver().applyBatch(ApgContract.CONTENT_AUTHORITY_INTERNAL, operations); } catch (RemoteException e) { Log.e(Constants.TAG, "applyBatch failed!", e); } catch (OperationApplicationException e) { @@ -288,7 +288,7 @@ public class ProviderHelper { } try { - context.getContentResolver().applyBatch(ApgContract.CONTENT_AUTHORITY, operations); + context.getContentResolver().applyBatch(ApgContract.CONTENT_AUTHORITY_INTERNAL, operations); } catch (RemoteException e) { Log.e(Constants.TAG, "applyBatch failed!", e); } catch (OperationApplicationException e) { diff --git a/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java index 498dfd93b..a6b10c521 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/DecryptActivity.java @@ -172,6 +172,12 @@ public class DecryptActivity extends SherlockFragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + // check permissions for intent actions without user interaction + String[] restrictedActions = new String[] { ACTION_DECRYPT_AND_RETURN }; + OtherHelper.checkPackagePermissionForActions(this, this.getCallingPackage(), + Constants.PERMISSION_ACCESS_API, getIntent().getAction(), restrictedActions); + setContentView(R.layout.decrypt); // set actionbar without home button if called from another app diff --git a/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java index cb5808a2a..0e480a3ae 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java @@ -134,6 +134,12 @@ public class EditKeyActivity extends SherlockFragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + // check permissions for intent actions without user interaction + String[] restrictedActions = new String[] { ACTION_CREATE_KEY }; + OtherHelper.checkPackagePermissionForActions(this, this.getCallingPackage(), + Constants.PERMISSION_ACCESS_API, getIntent().getAction(), restrictedActions); + setContentView(R.layout.edit_key); mActionBar = getSupportActionBar(); @@ -422,15 +428,16 @@ public class EditKeyActivity extends SherlockFragmentActivity { data.putString(ApgIntentService.NEW_PASSPHRASE, mNewPassPhrase); data.putStringArrayList(ApgIntentService.USER_IDS, getUserIds(mUserIdsView)); ArrayList keys = getKeys(mKeysView); - data.putByteArray(ApgIntentService.KEYS, PGPConversionHelper.PGPSecretKeyArrayListToBytes(keys)); + data.putByteArray(ApgIntentService.KEYS, + PGPConversionHelper.PGPSecretKeyArrayListToBytes(keys)); data.putIntegerArrayList(ApgIntentService.KEYS_USAGES, getKeysUsages(mKeysView)); data.putLong(ApgIntentService.MASTER_KEY_ID, getMasterKeyId()); intent.putExtra(ApgIntentService.EXTRA_DATA, data); // Message is received after saving is done in ApgService - ApgIntentServiceHandler saveHandler = new ApgIntentServiceHandler(this, R.string.progress_saving, - ProgressDialog.STYLE_HORIZONTAL) { + ApgIntentServiceHandler saveHandler = new ApgIntentServiceHandler(this, + R.string.progress_saving, ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); diff --git a/org_apg/src/org/thialfihar/android/apg/ui/EncryptActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/EncryptActivity.java index 29b1ab86a..ec7f26883 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/EncryptActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/EncryptActivity.java @@ -197,6 +197,13 @@ public class EncryptActivity extends SherlockFragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + // check permissions for intent actions without user interaction + String[] restrictedActions = new String[] { ACTION_ENCRYPT_AND_RETURN, + ACTION_GENERATE_SIGNATURE }; + OtherHelper.checkPackagePermissionForActions(this, this.getCallingPackage(), + Constants.PERMISSION_ACCESS_API, getIntent().getAction(), restrictedActions); + setContentView(R.layout.encrypt); // set actionbar without home button if called from another app @@ -841,8 +848,8 @@ public class EncryptActivity extends SherlockFragmentActivity { intent.putExtra(ApgIntentService.EXTRA_DATA, data); // Message is received after encrypting is done in ApgService - ApgIntentServiceHandler saveHandler = new ApgIntentServiceHandler(this, R.string.progress_encrypting, - ProgressDialog.STYLE_HORIZONTAL) { + ApgIntentServiceHandler saveHandler = new ApgIntentServiceHandler(this, + R.string.progress_encrypting, ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard ApgHandler first super.handleMessage(message); diff --git a/org_apg_integration_demo/AndroidManifest.xml b/org_apg_integration_demo/AndroidManifest.xml index 6fc5b1817..8d7a9e970 100644 --- a/org_apg_integration_demo/AndroidManifest.xml +++ b/org_apg_integration_demo/AndroidManifest.xml @@ -4,8 +4,8 @@ android:versionCode="1" android:versionName="1.0" > - - + +