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" >
-
-
+
+