diff options
36 files changed, 1113 insertions, 275 deletions
diff --git a/APG-API-Demo/AndroidManifest.xml b/APG-API-Demo/AndroidManifest.xml index 4112b8a09..812b5d45e 100644 --- a/APG-API-Demo/AndroidManifest.xml +++ b/APG-API-Demo/AndroidManifest.xml @@ -4,8 +4,8 @@ android:versionCode="1" android:versionName="1.0" > - <uses-permission android:name="org.thialfihar.android.apg.permission.READ_KEY_DATABASE" /> <uses-permission android:name="org.thialfihar.android.apg.permission.ACCESS_API" /> + <uses-permission android:name="org.thialfihar.android.apg.permission.ACCESS_KEYS" /> <uses-sdk android:minSdkVersion="7" @@ -29,7 +29,11 @@ android:windowSoftInputMode="stateHidden" /> <activity android:name=".AidlDemoActivity" - android:label="Aidl Demo" + android:label="Aidl Demo (ACCESS_API permission)" + android:windowSoftInputMode="stateHidden" /> + <activity + android:name=".AidlDemoActivity2" + android:label="Aidl Demo (ACCESS_KEYS permission)" android:windowSoftInputMode="stateHidden" /> <activity android:name=".ContentProviderDemoActivity" diff --git a/APG-API-Demo/res/layout/aidl_demo2.xml b/APG-API-Demo/res/layout/aidl_demo2.xml new file mode 100644 index 000000000..73abd9b5c --- /dev/null +++ b/APG-API-Demo/res/layout/aidl_demo2.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" > + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" > + + <Button + android:id="@+id/aidl_demo_select_encryption_key" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:onClick="selectEncryptionKeysOnClick" + android:text="Select encryption key(s)" /> + + <EditText + android:id="@+id/aidl_demo_keyrings" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="keyrings output" + android:textAppearance="@android:style/TextAppearance.Small" /> + + <Button + android:id="@+id/aidl_demo_get_keyrings_strings" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:onClick="getKeyringsStringsOnClick" + android:text="getKeyrings as Strings" /> + + <Button + android:id="@+id/aidl_demo_get_keyrings_bytes" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:onClick="getKeyringsBytesOnClick" + android:text="getKeyringsBytes" /> + </LinearLayout> + +</ScrollView>
\ No newline at end of file diff --git a/APG-API-Demo/res/xml/base_preference.xml b/APG-API-Demo/res/xml/base_preference.xml index 3fcd036e2..c9a34efd1 100644 --- a/APG-API-Demo/res/xml/base_preference.xml +++ b/APG-API-Demo/res/xml/base_preference.xml @@ -6,15 +6,18 @@ android:key="intent_demo" android:title="Intent Demo" /> </PreferenceCategory> - <PreferenceCategory android:title="AIDL" > - <Preference - android:key="aidl_demo" - android:title="AIDL Demo" /> - </PreferenceCategory> <PreferenceCategory android:title="Content Provider" > <Preference android:key="content_provider_demo" android:title="Content Provider Demo" /> </PreferenceCategory> + <PreferenceCategory android:title="AIDL" > + <Preference + android:key="aidl_demo" + android:title="AIDL Demo (ACCESS_API permission)" /> + <Preference + android:key="aidl_demo2" + android:title="AIDL Demo (ACCESS_KEYS permission)" /> + </PreferenceCategory> </PreferenceScreen>
\ No newline at end of file diff --git a/APG-API-Demo/src/org/thialfihar/android/apg/demo/AidlDemoActivity.java b/APG-API-Demo/src/org/thialfihar/android/apg/demo/AidlDemoActivity.java index 7c08c0e06..65bd3caf5 100644 --- a/APG-API-Demo/src/org/thialfihar/android/apg/demo/AidlDemoActivity.java +++ b/APG-API-Demo/src/org/thialfihar/android/apg/demo/AidlDemoActivity.java @@ -18,9 +18,10 @@ package org.thialfihar.android.apg.demo; import org.thialfihar.android.apg.integration.ApgData; import org.thialfihar.android.apg.integration.ApgIntentHelper; -import org.thialfihar.android.apg.service.IApgEncryptDecryptHandler; -import org.thialfihar.android.apg.service.IApgHelperHandler; -import org.thialfihar.android.apg.service.IApgService; +import org.thialfihar.android.apg.service.IApgApiService; +import org.thialfihar.android.apg.service.handler.IApgDecryptHandler; +import org.thialfihar.android.apg.service.handler.IApgEncryptHandler; +import org.thialfihar.android.apg.service.handler.IApgGetDecryptionKeyIdHandler; import android.app.Activity; import android.app.AlertDialog; @@ -44,10 +45,10 @@ public class AidlDemoActivity extends Activity { ApgIntentHelper mApgIntentHelper; ApgData mApgData; - private IApgService service = null; + private IApgApiService service = null; private ServiceConnection svcConn = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder binder) { - service = IApgService.Stub.asInterface(binder); + service = IApgApiService.Stub.asInterface(binder); } public void onServiceDisconnected(ComponentName className) { @@ -69,7 +70,7 @@ public class AidlDemoActivity extends Activity { mApgIntentHelper = new ApgIntentHelper(mActivity); mApgData = new ApgData(); - bindService(new Intent("org.thialfihar.android.apg.service.IApgService"), svcConn, + bindService(new Intent("org.thialfihar.android.apg.service.IApgApiService"), svcConn, Context.BIND_AUTO_CREATE); } @@ -77,8 +78,8 @@ public class AidlDemoActivity extends Activity { byte[] inputBytes = mMessageTextView.getText().toString().getBytes(); try { - service.encryptAsymmetric(inputBytes, null, true, 0, mApgData.getEncryptionKeys(), 7, - encryptDecryptHandler); + service.encryptAsymmetric(inputBytes, null, true, 0, mApgData.getPublicKeys(), 7, + encryptHandler); } catch (RemoteException e) { exceptionImplementation(-1, e.toString()); } @@ -88,7 +89,7 @@ public class AidlDemoActivity extends Activity { byte[] inputBytes = mCiphertextTextView.getText().toString().getBytes(); try { - service.decryptAndVerifyAsymmetric(inputBytes, null, null, encryptDecryptHandler); + service.decryptAndVerifyAsymmetric(inputBytes, null, null, decryptHandler); } catch (RemoteException e) { exceptionImplementation(-1, e.toString()); } @@ -116,7 +117,7 @@ public class AidlDemoActivity extends Activity { builder.setTitle("Exception!").setMessage(error).setPositiveButton("OK", null).show(); } - private final IApgEncryptDecryptHandler.Stub encryptDecryptHandler = new IApgEncryptDecryptHandler.Stub() { + private final IApgEncryptHandler.Stub encryptHandler = new IApgEncryptHandler.Stub() { @Override public void onException(final int exceptionId, final String message) throws RemoteException { @@ -128,8 +129,7 @@ public class AidlDemoActivity extends Activity { } @Override - public void onSuccessEncrypt(final byte[] outputBytes, String outputUri) - throws RemoteException { + public void onSuccess(final byte[] outputBytes, String outputUri) throws RemoteException { runOnUiThread(new Runnable() { public void run() { mApgData.setEncryptedData(new String(outputBytes)); @@ -138,8 +138,21 @@ public class AidlDemoActivity extends Activity { }); } + }; + + private final IApgDecryptHandler.Stub decryptHandler = new IApgDecryptHandler.Stub() { + + @Override + public void onException(final int exceptionId, final String message) throws RemoteException { + runOnUiThread(new Runnable() { + public void run() { + exceptionImplementation(exceptionId, message); + } + }); + } + @Override - public void onSuccessDecrypt(final byte[] outputBytes, String outputUri, boolean signature, + public void onSuccess(final byte[] outputBytes, String outputUri, boolean signature, long signatureKeyId, String signatureUserId, boolean signatureSuccess, boolean signatureUnknown) throws RemoteException { runOnUiThread(new Runnable() { @@ -153,7 +166,7 @@ public class AidlDemoActivity extends Activity { }; - private final IApgHelperHandler.Stub helperHandler = new IApgHelperHandler.Stub() { + private final IApgGetDecryptionKeyIdHandler.Stub helperHandler = new IApgGetDecryptionKeyIdHandler.Stub() { @Override public void onException(final int exceptionId, final String message) throws RemoteException { @@ -165,7 +178,7 @@ public class AidlDemoActivity extends Activity { } @Override - public void onSuccessGetDecryptionKey(long arg0, boolean arg1) throws RemoteException { + public void onSuccess(long arg0, boolean arg1) throws RemoteException { // TODO Auto-generated method stub } @@ -182,7 +195,7 @@ public class AidlDemoActivity extends Activity { } public void selectEncryptionKeysOnClick(View view) { - mApgIntentHelper.selectEncryptionKeys("user@example.com"); + mApgIntentHelper.selectPublicKeys("user@example.com"); } diff --git a/APG-API-Demo/src/org/thialfihar/android/apg/demo/AidlDemoActivity2.java b/APG-API-Demo/src/org/thialfihar/android/apg/demo/AidlDemoActivity2.java new file mode 100644 index 000000000..51054f58a --- /dev/null +++ b/APG-API-Demo/src/org/thialfihar/android/apg/demo/AidlDemoActivity2.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.thialfihar.android.apg.integration.ApgData; +import org.thialfihar.android.apg.integration.ApgIntentHelper; +import org.thialfihar.android.apg.service.IApgKeyService; +import org.thialfihar.android.apg.service.handler.IApgGetKeyringsHandler; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Base64; +import android.view.View; +import android.widget.TextView; + +public class AidlDemoActivity2 extends Activity { + Activity mActivity; + + TextView mKeyringsTextView; + + ApgIntentHelper mApgIntentHelper; + ApgData mApgData; + + byte[] keysBytes; + ArrayList<String> keysStrings; + + private IApgKeyService service = null; + private ServiceConnection svcConn = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder binder) { + service = IApgKeyService.Stub.asInterface(binder); + } + + public void onServiceDisconnected(ComponentName className) { + service = null; + } + }; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.aidl_demo2); + + mActivity = this; + + mKeyringsTextView = (TextView) findViewById(R.id.aidl_demo_keyrings); + + mApgIntentHelper = new ApgIntentHelper(mActivity); + mApgData = new ApgData(); + + bindService(new Intent("org.thialfihar.android.apg.service.IApgKeyService"), svcConn, + Context.BIND_AUTO_CREATE); + } + + public void getKeyringsStringsOnClick(View view) { + try { + service.getPublicKeyRings(mApgData.getPublicKeys(), true, getKeyringsHandler); + } catch (RemoteException e) { + exceptionImplementation(-1, e.toString()); + } + } + + public void getKeyringsBytesOnClick(View view) { + try { + service.getPublicKeyRings(mApgData.getPublicKeys(), false, getKeyringsHandler); + } catch (RemoteException e) { + exceptionImplementation(-1, e.toString()); + } + } + + @SuppressLint("NewApi") + private void updateView() { + if (keysBytes != null) { + mKeyringsTextView.setText(Base64.encodeToString(keysBytes, Base64.DEFAULT)); + } else if (keysStrings != null) { + mKeyringsTextView.setText(""); + for (String output : keysStrings) { + mKeyringsTextView.append(output); + } + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + unbindService(svcConn); + } + + private void exceptionImplementation(int exceptionId, String error) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("Exception!").setMessage(error).setPositiveButton("OK", null).show(); + } + + private final IApgGetKeyringsHandler.Stub getKeyringsHandler = new IApgGetKeyringsHandler.Stub() { + + @Override + public void onException(final int exceptionId, final String message) throws RemoteException { + runOnUiThread(new Runnable() { + public void run() { + exceptionImplementation(exceptionId, message); + } + }); + } + + @Override + public void onSuccess(final byte[] outputBytes, final List<String> outputStrings) + throws RemoteException { + runOnUiThread(new Runnable() { + public void run() { + if (outputBytes != null) { + keysBytes = outputBytes; + keysStrings = null; + } else if (outputStrings != null) { + keysBytes = null; + keysStrings = (ArrayList<String>) outputStrings; + } + updateView(); + } + }); + + } + + }; + + public void selectEncryptionKeysOnClick(View view) { + mApgIntentHelper.selectPublicKeys("user@example.com"); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // this updates the mApgData object to the result of the methods + boolean result = mApgIntentHelper.onActivityResult(requestCode, resultCode, data, mApgData); + if (result) { + updateView(); + } + + // continue with other activity results + super.onActivityResult(requestCode, resultCode, data); + } + +} diff --git a/APG-API-Demo/src/org/thialfihar/android/apg/demo/BaseActivity.java b/APG-API-Demo/src/org/thialfihar/android/apg/demo/BaseActivity.java index 66c3a9a0e..5e2108c50 100644 --- a/APG-API-Demo/src/org/thialfihar/android/apg/demo/BaseActivity.java +++ b/APG-API-Demo/src/org/thialfihar/android/apg/demo/BaseActivity.java @@ -29,8 +29,9 @@ public class BaseActivity extends PreferenceActivity { private Activity mActivity; private Preference mIntentDemo; - private Preference mAidlDemo; private Preference mContentProviderDemo; + private Preference mAidlDemo; + private Preference mAidlDemo2; /** * Called when the activity is first created. @@ -46,8 +47,9 @@ public class BaseActivity extends PreferenceActivity { // find preferences mIntentDemo = (Preference) findPreference("intent_demo"); - mAidlDemo = (Preference) findPreference("aidl_demo"); mContentProviderDemo = (Preference) findPreference("content_provider_demo"); + mAidlDemo = (Preference) findPreference("aidl_demo"); + mAidlDemo2 = (Preference) findPreference("aidl_demo2"); mIntentDemo.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override @@ -58,6 +60,15 @@ public class BaseActivity extends PreferenceActivity { } }); + mContentProviderDemo.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + startActivity(new Intent(mActivity, ContentProviderDemoActivity.class)); + + return false; + } + }); + mAidlDemo.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { @@ -67,14 +78,15 @@ public class BaseActivity extends PreferenceActivity { } }); - mContentProviderDemo.setOnPreferenceClickListener(new OnPreferenceClickListener() { + mAidlDemo2.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - startActivity(new Intent(mActivity, ContentProviderDemoActivity.class)); + startActivity(new Intent(mActivity, AidlDemoActivity2.class)); return false; } }); + } } diff --git a/APG-API-Demo/src/org/thialfihar/android/apg/demo/IntentDemoActivity.java b/APG-API-Demo/src/org/thialfihar/android/apg/demo/IntentDemoActivity.java index b707e48a8..b789dccb1 100644 --- a/APG-API-Demo/src/org/thialfihar/android/apg/demo/IntentDemoActivity.java +++ b/APG-API-Demo/src/org/thialfihar/android/apg/demo/IntentDemoActivity.java @@ -65,17 +65,17 @@ public class IntentDemoActivity extends Activity { } public void selectEncryptionKeysOnClick(View view) { - mApgIntentHelper.selectEncryptionKeys("user@example.com"); + mApgIntentHelper.selectPublicKeys("user@example.com"); } public void encryptOnClick(View view) { - mApgIntentHelper.encrypt(mMessageTextView.getText().toString(), - mApgData.getEncryptionKeys(), mApgData.getSignatureKeyId(), false); + mApgIntentHelper.encrypt(mMessageTextView.getText().toString(), mApgData.getPublicKeys(), + mApgData.getSecretKeyId(), false); } public void encryptAndReturnOnClick(View view) { - mApgIntentHelper.encrypt(mMessageTextView.getText().toString(), - mApgData.getEncryptionKeys(), mApgData.getSignatureKeyId(), true); + mApgIntentHelper.encrypt(mMessageTextView.getText().toString(), mApgData.getPublicKeys(), + mApgData.getSecretKeyId(), true); } public void decryptOnClick(View view) { diff --git a/APG/src/org/thialfihar/android/apg/service/IApgService.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgApiService.aidl index 98c08c62b..277ce6722 100644 --- a/APG/src/org/thialfihar/android/apg/service/IApgService.aidl +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgApiService.aidl @@ -16,15 +16,15 @@ package org.thialfihar.android.apg.service; -import org.thialfihar.android.apg.service.IApgEncryptSignHandler; -import org.thialfihar.android.apg.service.IApgDecryptVerifyHandler; -import org.thialfihar.android.apg.service.IApgHelperHandler; +import org.thialfihar.android.apg.service.handler.IApgEncryptHandler; +import org.thialfihar.android.apg.service.handler.IApgDecryptHandler; +import org.thialfihar.android.apg.service.handler.IApgGetDecryptionKeyIdHandler; /** * All methods are oneway, which means they are asynchronous and non-blocking. * Results are returned into given Handler, which has to be implemented on client side. */ -interface IApgService { +interface IApgApiService { /** * Encrypt @@ -50,7 +50,7 @@ interface IApgService { */ oneway void encryptAsymmetric(in byte[] inputBytes, in String inputUri, in boolean useAsciiArmor, in int compression, in long[] encryptionKeyIds, in int symmetricEncryptionAlgorithm, - in IApgEncryptSignHandler handler); + in IApgEncryptHandler handler); /** * Same as encryptAsymmetric but using a passphrase for symmetric encryption @@ -60,7 +60,7 @@ interface IApgService { */ oneway void encryptSymmetric(in byte[] inputBytes, in String inputUri, in boolean useAsciiArmor, in int compression, in String encryptionPassphrase, in int symmetricEncryptionAlgorithm, - in IApgEncryptSignHandler handler); + in IApgEncryptHandler handler); /** * Encrypt and sign @@ -97,7 +97,7 @@ interface IApgService { in boolean useAsciiArmor, in int compression, in long[] encryptionKeyIds, in int symmetricEncryptionAlgorithm, in long signatureKeyId, in int signatureHashAlgorithm, in boolean signatureForceV3, in String signaturePassphrase, - in IApgEncryptSignHandler handler); + in IApgEncryptHandler handler); /** * Same as encryptAndSignAsymmetric but using a passphrase for symmetric encryption @@ -109,7 +109,7 @@ interface IApgService { in boolean useAsciiArmor, in int compression, in String encryptionPassphrase, in int symmetricEncryptionAlgorithm, in long signatureKeyId, in int signatureHashAlgorithm, in boolean signatureForceV3, in String signaturePassphrase, - in IApgEncryptSignHandler handler); + in IApgEncryptHandler handler); /** * Decrypts and verifies given input bytes. If no signature is present this method @@ -125,7 +125,7 @@ interface IApgService { * Handler where to return results to after successful encryption */ oneway void decryptAndVerifyAsymmetric(in byte[] inputBytes, in String inputUri, - in String keyPassphrase, in IApgDecryptVerifyHandler handler); + in String keyPassphrase, in IApgDecryptHandler handler); /** * Same as decryptAndVerifyAsymmetric but for symmetric decryption. @@ -134,13 +134,13 @@ interface IApgService { * Passphrase to decrypt */ oneway void decryptAndVerifySymmetric(in byte[] inputBytes, in String inputUri, - in String encryptionPassphrase, in IApgDecryptVerifyHandler handler); + in String encryptionPassphrase, in IApgDecryptHandler handler); /** * */ - oneway void getDecryptionKey(in byte[] inputBytes, in String inputUri, - in IApgHelperHandler handler); + oneway void getDecryptionKeyId(in byte[] inputBytes, in String inputUri, + in IApgGetDecryptionKeyIdHandler handler); }
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgEncryptDecryptHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgEncryptDecryptHandler.aidl deleted file mode 100644 index ff6b7254c..000000000 --- a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgEncryptDecryptHandler.aidl +++ /dev/null @@ -1,16 +0,0 @@ -package org.thialfihar.android.apg.service; - -interface IApgEncryptDecryptHandler { - /** - * Either output or streamUri is given. One of them is null - * - */ - oneway void onSuccessEncrypt(in byte[] outputBytes, in String outputUri); - - oneway void onSuccessDecrypt(in byte[] outputBytes, in String outputUri, in boolean signature, - in long signatureKeyId, in String signatureUserId, in boolean signatureSuccess, - in boolean signatureUnknown); - - - oneway void onException(in int exceptionNumber, in String message); -}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgHelperHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgHelperHandler.aidl deleted file mode 100644 index bb405329a..000000000 --- a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgHelperHandler.aidl +++ /dev/null @@ -1,9 +0,0 @@ -package org.thialfihar.android.apg.service; - -interface IApgHelperHandler { - - oneway void onSuccessGetDecryptionKey(in long secretKeyId, in boolean symmetric); - - - oneway void onException(in int exceptionNumber, in String message); -}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgKeyService.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgKeyService.aidl new file mode 100644 index 000000000..12ecddc17 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgKeyService.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service; + +import org.thialfihar.android.apg.service.handler.IApgGetKeyringsHandler; + +/** + * All methods are oneway, which means they are asynchronous and non-blocking. + * Results are returned into given Handler, which has to be implemented on client side. + */ +interface IApgKeyService { + + oneway void getPublicKeyRings(in long[] masterKeyIds, in boolean asAsciiArmoredStringArray, + in IApgGetKeyringsHandler handler); + + oneway void getSecretKeyRings(in long[] masterKeyIds, in boolean asAsciiArmoredStringArray, + in IApgGetKeyringsHandler handler); +}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgSignVerifyHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgSignVerifyHandler.aidl deleted file mode 100644 index 1375d1548..000000000 --- a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgSignVerifyHandler.aidl +++ /dev/null @@ -1,11 +0,0 @@ -package org.thialfihar.android.apg.service; - -interface IApgSignVerifyHandler { - oneway void onSuccessSign(in byte[] outputBytes, in String outputUri); - - oneway void onSuccessVerify(in boolean signature, in long signatureKeyId, - in String signatureUserId, in boolean signatureSuccess, in boolean signatureUnknown); - - - oneway void onException(in int exceptionNumber, in String message); -}
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/IApgDecryptVerifyHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgDecryptHandler.aidl index ad74340bf..feb56bce6 100644 --- a/APG/src/org/thialfihar/android/apg/service/IApgDecryptVerifyHandler.aidl +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgDecryptHandler.aidl @@ -14,17 +14,14 @@ * limitations under the License. */ -package org.thialfihar.android.apg.service; +package org.thialfihar.android.apg.service.handler; -interface IApgDecryptVerifyHandler { +interface IApgDecryptHandler { - oneway void onSuccessDecrypt(in byte[] outputBytes, in String outputUri, in boolean signature, + oneway void onSuccess(in byte[] outputBytes, in String outputUri, in boolean signature, in long signatureKeyId, in String signatureUserId, in boolean signatureSuccess, in boolean signatureUnknown); - - oneway void onSuccessVerify(in boolean signature, in long signatureKeyId, - in String signatureUserId, in boolean signatureSuccess, in boolean signatureUnknown); - - + + oneway void onException(in int exceptionNumber, in String message); }
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/IApgEncryptSignHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgEncryptHandler.aidl index ea3e2ae86..be0317715 100644 --- a/APG/src/org/thialfihar/android/apg/service/IApgEncryptSignHandler.aidl +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgEncryptHandler.aidl @@ -14,17 +14,15 @@ * limitations under the License. */ -package org.thialfihar.android.apg.service; +package org.thialfihar.android.apg.service.handler; -interface IApgEncryptSignHandler { +interface IApgEncryptHandler { /** * Either output or streamUri is given. One of them is null * */ - oneway void onSuccessEncrypt(in byte[] outputBytes, in String outputUri); - - oneway void onSuccessSign(in byte[] outputBytes, in String outputUri); - - + oneway void onSuccess(in byte[] outputBytes, in String outputUri); + + oneway void onException(in int exceptionNumber, in String message); }
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/IApgHelperHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgGetDecryptionKeyIdHandler.aidl index 29ff2dd3e..020a80b99 100644 --- a/APG/src/org/thialfihar/android/apg/service/IApgHelperHandler.aidl +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgGetDecryptionKeyIdHandler.aidl @@ -14,12 +14,12 @@ * limitations under the License. */ -package org.thialfihar.android.apg.service; +package org.thialfihar.android.apg.service.handler; + +interface IApgGetDecryptionKeyIdHandler { + + oneway void onSuccess(in long secretKeyId, in boolean symmetric); -interface IApgHelperHandler { - oneway void onSuccessGetDecryptionKey(in long secretKeyId, in boolean symmetric); - - oneway void onException(in int exceptionNumber, in String message); }
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgGetKeyringsHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgGetKeyringsHandler.aidl new file mode 100644 index 000000000..ffa9d0d2d --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgGetKeyringsHandler.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgGetKeyringsHandler { + /** + * Either outputBytes or outputString is given. One of them is null + * + */ + oneway void onSuccess(in byte[] outputBytes, in List<String> outputString); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgSignHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgSignHandler.aidl new file mode 100644 index 000000000..cf91e8bc4 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgSignHandler.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgSignHandler { + /** + * Either output or streamUri is given. One of them is null + * + */ + oneway void onSuccess(in byte[] outputBytes, in String outputUri); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgVerifyHandler.aidl b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgVerifyHandler.aidl new file mode 100644 index 000000000..6baaec758 --- /dev/null +++ b/APG-API-Lib/src/org/thialfihar/android/apg/service/handler/IApgVerifyHandler.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgVerifyHandler { + + oneway void onSuccess(in boolean signature, in long signatureKeyId, + in String signatureUserId, in boolean signatureSuccess, in boolean signatureUnknown); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG/AndroidManifest.xml b/APG/AndroidManifest.xml index ea5dcb1f8..800655f8b 100644 --- a/APG/AndroidManifest.xml +++ b/APG/AndroidManifest.xml @@ -60,9 +60,9 @@ android:label="@string/permission_group_label" /> <permission - android:name="org.thialfihar.android.apg.permission.READ_KEY_DATABASE" - android:description="@string/permission_read_key_database_description" - android:label="@string/permission_read_key_database_label" + android:name="org.thialfihar.android.apg.permission.ACCESS_KEYS" + android:description="@string/permission_access_keys_description" + android:label="@string/permission_access_keys_label" android:permissionGroup="org.thialfihar.android.apg.permission-group.APG" android:protectionLevel="dangerous" /> <permission @@ -346,13 +346,27 @@ <service android:name=".service.PassphraseCacheService" /> <service android:name=".service.ApgIntentService" /> <service - android:name=".service.ApgService" + android:name="org.thialfihar.android.apg.service.ApgApiService" android:enabled="true" android:exported="true" android:permission="org.thialfihar.android.apg.permission.ACCESS_API" - android:process=":remote" > + android:process=":remoteapi" > <intent-filter> - <action android:name="org.thialfihar.android.apg.service.IApgService" /> + <action android:name="org.thialfihar.android.apg.service.IApgApiService" /> + </intent-filter> + + <meta-data + android:name="api_version" + android:value="3" /> + </service> + <service + android:name="org.thialfihar.android.apg.service.ApgKeyService" + android:enabled="true" + android:exported="true" + android:permission="org.thialfihar.android.apg.permission.ACCESS_KEYS" + android:process=":remotekeys" > + <intent-filter> + <action android:name="org.thialfihar.android.apg.service.IApgKeyService" /> </intent-filter> <meta-data @@ -367,7 +381,7 @@ <provider android:name=".provider.ApgProviderExternal" android:authorities="org.thialfihar.android.apg" - android:readPermission="org.thialfihar.android.apg.permission.READ_KEY_DATABASE" /> + android:readPermission="org.thialfihar.android.apg.permission.ACCESS_API" /> <!-- TODO: authority! --> <provider diff --git a/APG/res/values/strings.xml b/APG/res/values/strings.xml index 08e285299..215905b3c 100644 --- a/APG/res/values/strings.xml +++ b/APG/res/values/strings.xml @@ -20,16 +20,16 @@ <!-- title_lowerCase: capitalized words, no punctuation --> <string name="title_mailInbox">Mail Inbox</string> - <string name="title_managePublicKeys">Manage Public Keys</string> - <string name="title_manageSecretKeys">Manage Secret Keys</string> - <string name="title_selectRecipients">Select Public Key</string> - <string name="title_selectSignature">Select Secret Key</string> + <string name="title_managePublicKeys">Manage Public Keyrings</string> + <string name="title_manageSecretKeys">Manage Secret Keyrings</string> + <string name="title_selectRecipients">Select Public Keyring</string> + <string name="title_selectSignature">Select Secret Keyring</string> <string name="title_encrypt">Encrypt</string> <string name="title_decrypt">Decrypt</string> <string name="title_authentication">Passphrase</string> <string name="title_createKey">Create Key</string> - <string name="title_editKey">Edit Key</string> - <string name="title_createKey">Create Key</string> + <string name="title_editKey">Edit Keyring</string> + <string name="title_createKey">Create Keyring</string> <string name="title_preferences">Preferences</string> <string name="title_keyServerPreference">Key Server Preference</string> <string name="title_changePassPhrase">Change Passphrase</string> @@ -37,16 +37,16 @@ <string name="title_sendEmail">"Send Mail…"</string> <string name="title_encryptToFile">Encrypt To File</string> <string name="title_decryptToFile">Decrypt To File</string> - <string name="title_importKeys">Import Keys</string> - <string name="title_exportKey">Export Key</string> - <string name="title_exportKeys">Export Keys</string> + <string name="title_importKeys">Import Keyrings</string> + <string name="title_exportKey">Export Keyring</string> + <string name="title_exportKeys">Export Keyrings</string> <string name="title_keyNotFound">Key Not Found</string> <string name="title_help">Getting Started</string> <string name="title_keyServerQuery">Query Key Server</string> <string name="title_sendKey">Export to Key Server</string> <string name="title_unknownSignatureKey">Unknown Signature Key</string> <string name="title_importFromQRCode">Import from QR Code</string> - <string name="title_signKey">Sign Key</string> + <string name="title_signKey">Sign Keyring</string> <string name="title_about">About</string> <string name="title_help">Help</string> @@ -86,21 +86,21 @@ <!-- menu_lowerCase: capitalized words, no punctuation --> <string name="menu_about">About</string> <string name="menu_deleteAccount">Delete Account</string> - <string name="menu_managePublicKeys">Manage Public Keys</string> - <string name="menu_manageSecretKeys">Manage Secret Keys</string> + <string name="menu_managePublicKeys">Manage Public Keyrings</string> + <string name="menu_manageSecretKeys">Manage Secret Keyrings</string> <string name="menu_preferences">Settings</string> - <string name="menu_importKeys">Import Keys</string> - <string name="menu_exportKeys">Export All Keys</string> - <string name="menu_exportKey">Export Key</string> - <string name="menu_deleteKey">Delete Key</string> - <string name="menu_createKey">Create Key</string> - <string name="menu_editKey">Edit Key</string> + <string name="menu_importKeys">Import Keyrings</string> + <string name="menu_exportKeys">Export All Keyrings</string> + <string name="menu_exportKey">Export Keyring</string> + <string name="menu_deleteKey">Delete Keyring</string> + <string name="menu_createKey">Create Keyring</string> + <string name="menu_editKey">Edit Keyring</string> <string name="menu_search">Search</string> <string name="menu_help">Help</string> <string name="menu_keyServer">Key Server</string> <string name="menu_updateKey">Update from Server</string> <string name="menu_exportKeyToServer">Export To Server</string> - <string name="menu_share">Share public key with QR Code</string> + <string name="menu_share">Share public keyring with QR Code</string> <string name="menu_scanQRCode">Scan QR Code</string> <string name="menu_signKey">Sign Key</string> @@ -135,7 +135,7 @@ <string name="label_name">Name</string> <string name="label_comment">Comment</string> <string name="label_email">Email</string> - <string name="label_sendKey">Send Key to Server?</string> + <string name="label_sendKey">Send Keyring to Server?</string> <string name="noKeysSelected">Select</string> <string name="oneKeySelected">1 Selected</string> <string name="nKeysSelected">Selected</string> @@ -201,32 +201,31 @@ <string name="encryptionSuccessful">Successfully encrypted.</string> <string name="encryptionToClipboardSuccessful">Successfully encrypted to clipboard.</string> <string name="enterPassPhraseTwice">Enter the passphrase twice.</string> - <string name="selectEncryptionKey">Select at least one encryption key.</string> - <string name="selectEncryptionOrSignatureKey">Select at least one encryption key or a signature key.</string> + <string name="selectEncryptionKey">Select at least one encryption keyring.</string> + <string name="selectEncryptionOrSignatureKey">Select at least one encryption keyring or a signature keyring.</string> <string name="specifyFileToEncryptTo">Please specify which file to encrypt to.\nWARNING! File will be overwritten if it exists.</string> <string name="specifyFileToDecryptTo">Please specify which file to decrypt to.\nWARNING! File will be overwritten if it exists.</string> - <string name="specifyFileToImportFrom">Please specify which file to import keys from. (.asc or .gpg)</string> + <string name="specifyFileToImportFrom">Please specify which file to import keyrings from. (.asc or .gpg)</string> <string name="specifyFileToExportTo">Please specify which file to export to.\nWARNING! File will be overwritten if it exists.</string> - <string name="specifyFileToExportSecretKeysTo">Please specify which file to export to.\nWARNING! You are about to export SECRET keys.\nWARNING! File will be overwritten if it exists.</string> - <string name="keyDeletionConfirmation">Do you really want to delete the key \'%s\'?\nYou can\'t undo this!</string> - <string name="secretKeyDeletionConfirmation">Do you really want to delete the SECRET key \'%s\'?\nYou can\'t undo this!</string> - <string name="keysAddedAndUpdated">Successfully added %1$s key(s) and updated %2$s key(s).</string> - <string name="keysAdded">Successfully added %s key(s).</string> - <string name="keysUpdated">Successfully updated %s key(s).</string> - <string name="noKeysAddedOrUpdated">No keys added or updated.</string> - <string name="keyExported">Successfully exported 1 key.</string> - <string name="keysExported">Successfully exported %s keys.</string> - <string name="noKeysExported">No keys exported.</string> + <string name="specifyFileToExportSecretKeysTo">Please specify which file to export to.\nWARNING! You are about to export SECRET keyrings.\nWARNING! File will be overwritten if it exists.</string> + <string name="keyDeletionConfirmation">Do you really want to delete the keyring \'%s\'?\nYou can\'t undo this!</string> + <string name="secretKeyDeletionConfirmation">Do you really want to delete the SECRET keyring \'%s\'?\nYou can\'t undo this!</string> + <string name="keysAddedAndUpdated">Successfully added %1$s keyring(s) and updated %2$s keyring(s).</string> + <string name="keysAdded">Successfully added %s keyring(s).</string> + <string name="keysUpdated">Successfully updated %s keyring(s).</string> + <string name="noKeysAddedOrUpdated">No keyrings added or updated.</string> + <string name="keyExported">Successfully exported 1 keyring.</string> + <string name="keysExported">Successfully exported %s keyrings.</string> + <string name="noKeysExported">No keyrings exported.</string> <string name="keyCreationElGamalInfo">Note: only subkeys support ElGamal, and for ElGamal the nearest keysize of 1536, 2048, 3072, 4096, or 8192 will be used.</string> <string name="keyNotFound">Couldn\'t find key %08X.</string> <string name="keysFound">Found %s key(s).</string> <string name="unknownSignatureKeyTouchToLookUp">Unknown signature, touch to look up key.</string> - <string name="keyEditingIsBeta">Key editing is still kind of beta.</string> <string name="badKeysEncountered">%s bad secret key(s) ignored. Perhaps you exported with the option\n --export-secret-subkeys\nMake sure you export with\n --export-secret-keys\ninstead.</string> - <string name="lookupUnknownKey">Unknown key %s, do you want to try finding it on a keyserver?</string> - <string name="keySendSuccess">Successfully sent key to server</string> - <string name="keySignSuccess">Successfully signed key</string> - <string name="qrScanImportSuccess">Successfully validated and imported key</string> + <string name="lookupUnknownKey">Unknown keyring %s, do you want to try finding it on a keyserver?</string> + <string name="keySendSuccess">Successfully sent keyring to server</string> + <string name="keySignSuccess">Successfully signed keyring</string> + <string name="qrScanImportSuccess">Successfully validated and imported keyring</string> <string name="listInformation">Long press one entry in this list to show more options!</string> <string name="listEmpty">This list is empty!</string> @@ -274,12 +273,11 @@ <string name="progress_certifyingMasterKey">certifying master key…</string> <string name="progress_buildingMasterKeyRing">building master key ring…</string> <string name="progress_addingSubKeys">adding sub keys…</string> - <string name="progress_savingKeyRing">saving key ring…</string> - <string name="progress_importingSecretKeys">importing secret keys…</string> - <string name="progress_importingPublicKeys">importing public keys…</string> - <string name="progress_reloadingKeys">reloading keys…</string> - <string name="progress_exportingKey">exporting key…</string> - <string name="progress_exportingKeys">exporting keys…</string> + <string name="progress_savingKeyRing">saving key keyring…</string> + <string name="progress_importingSecretKeys">importing secret keyrings…</string> + <string name="progress_importingPublicKeys">importing public keyrings…</string> + <string name="progress_exportingKey">exporting keyring…</string> + <string name="progress_exportingKeys">exporting keyrings…</string> <string name="progress_extractingSignatureKey">extracting signature key…</string> <string name="progress_extractingKey">extracting key…</string> <string name="progress_preparingStreams">preparing streams…</string> @@ -301,18 +299,18 @@ <!-- permission strings --> <string name="permission_group_label">APG</string> <string name="permission_group_description">Permissions to use APG</string> - <string name="permission_read_key_database_label">Read key details of public and secret keys (The keys themselves can NOT be read.)</string> - <string name="permission_read_key_database_description">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.</string> - <string name="permission_access_api_label">Encrypt/Sign/Decrypt/Create keys without user interaction</string> - <string name="permission_access_api_description">Encrypt/Sign/Decrypt/Create keys (by using Intents or Remote Service) without user interaction</string> + <string name="permission_access_api_label">Encrypt/Sign/Decrypt/Create keys without user interaction, Read key details of public and secret keys (The keys themselves can NOT be read.)</string> + <string name="permission_access_api_description">Encrypt/Sign/Decrypt/Create keys (by using Intents or Remote Service) without user interaction. 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.</string> + <string name="permission_access_keys_label">Import/Export actual public and secret keys</string> + <string name="permission_access_keys_description">Import and export actual private and public keys directly without user uinteraction.</string> <!-- action strings --> <string name="action_encrypt">Encrypt</string> <string name="action_decrypt">Decrypt</string> - <string name="action_importPublic">Import Public Keys</string> - <string name="action_importSecret">Import Secret Keys</string> - <string name="hint_publicKeys">Search Public Keys</string> - <string name="hint_secretKeys">Search Secret Keys</string> + <string name="action_importPublic">Import Public Keyrings</string> + <string name="action_importSecret">Import Secret Keyrings</string> + <string name="hint_publicKeys">Search Public Keyrings</string> + <string name="hint_secretKeys">Search Secret Keyrings</string> <string name="filterInfo">Filter: \"%s\"</string> <!-- misc --> @@ -324,8 +322,8 @@ <!-- Dashboard --> - <string name="dashboard_manage_keys">Manage Public Keys</string> - <string name="dashboard_my_keys">My Secret Keys</string> + <string name="dashboard_manage_keys">Manage Public Keyrings</string> + <string name="dashboard_my_keys">My Secret Keyrings</string> <string name="dashboard_encrypt">Encrypt</string> <string name="dashboard_decrypt">Decrypt</string> <string name="dashboard_help">Help</string> @@ -338,14 +336,14 @@ <string name="help_about_version">Version:</string> <!-- Import from QR Code --> - <string name="import_from_qr_code_import">Import key (only locally)</string> - <string name="import_from_qr_code_import_sign_and_upload">Import, Sign, and upload key</string> - <string name="import_from_qr_code_scan_again">Scan qr code again</string> + <string name="import_from_qr_code_import">Import keyring (only locally)</string> + <string name="import_from_qr_code_import_sign_and_upload">Import, Sign, and upload keyring</string> + <string name="import_from_qr_code_scan_again">Scan QR Code again</string> <string name="import_from_qr_code_finish">Finish</string> <!-- Intent labels --> <string name="intent_decrypt_file">APG: Decrypt File</string> - <string name="intent_import_key">APG: Import Key</string> + <string name="intent_import_key">APG: Import Keyring</string> <string name="intent_send_encrypt">APG: Encrypt</string> <string name="intent_send_decrypt">APG: Decrypt</string> diff --git a/APG/src/org/thialfihar/android/apg/helper/PGPConversionHelper.java b/APG/src/org/thialfihar/android/apg/helper/PGPConversionHelper.java index 040ff2a9e..7fee97882 100644 --- a/APG/src/org/thialfihar/android/apg/helper/PGPConversionHelper.java +++ b/APG/src/org/thialfihar/android/apg/helper/PGPConversionHelper.java @@ -18,17 +18,24 @@ package org.thialfihar.android.apg.helper; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; +import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPUtil; import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.provider.ProviderHelper; import org.thialfihar.android.apg.util.Log; +import android.content.Context; + public class PGPConversionHelper { /** @@ -134,4 +141,17 @@ public class PGPConversionHelper { return null; } } + + public static PGPKeyRing decodeKeyRing(InputStream is) throws IOException { + InputStream in = PGPUtil.getDecoderStream(is); + PGPObjectFactory objectFactory = new PGPObjectFactory(in); + Object obj = objectFactory.nextObject(); + + if (obj instanceof PGPKeyRing) { + return (PGPKeyRing) obj; + } + + return null; + } + } diff --git a/APG/src/org/thialfihar/android/apg/helper/PGPHelper.java b/APG/src/org/thialfihar/android/apg/helper/PGPHelper.java index b566cffa0..1571ed023 100644 --- a/APG/src/org/thialfihar/android/apg/helper/PGPHelper.java +++ b/APG/src/org/thialfihar/android/apg/helper/PGPHelper.java @@ -20,9 +20,11 @@ package org.thialfihar.android.apg.helper; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.Locale; import java.util.Vector; import org.spongycastle.bcpg.ArmoredOutputStream; @@ -38,24 +40,17 @@ import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPUtil; import org.thialfihar.android.apg.Constants; import org.thialfihar.android.apg.R; +import org.thialfihar.android.apg.provider.ApgContract.KeyRings; import org.thialfihar.android.apg.provider.ProviderHelper; import org.thialfihar.android.apg.util.IterableIterator; import org.thialfihar.android.apg.util.Log; import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.net.Uri; public class PGPHelper { - public static PGPKeyRing decodeKeyRing(InputStream is) throws IOException { - InputStream in = PGPUtil.getDecoderStream(is); - PGPObjectFactory objectFactory = new PGPObjectFactory(in); - Object obj = objectFactory.nextObject(); - - if (obj instanceof PGPKeyRing) { - return (PGPKeyRing) obj; - } - - return null; - } public static Date getCreationDate(PGPPublicKey key) { return key.getCreationTime(); @@ -191,7 +186,8 @@ public class PGPHelper { } public static PGPPublicKey getEncryptPublicKey(Context context, long masterKeyId) { - PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByMasterKeyId(context, masterKeyId); + PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByMasterKeyId(context, + masterKeyId); if (keyRing == null) { Log.e(Constants.TAG, "keyRing is null!"); return null; @@ -205,7 +201,8 @@ public class PGPHelper { } public static PGPSecretKey getSigningKey(Context context, long masterKeyId) { - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(context, masterKeyId); + PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(context, + masterKeyId); if (keyRing == null) { return null; } @@ -374,7 +371,7 @@ public class PGPHelper { } else if (i != 0 && i % 2 == 0) { fingerPrint += " "; } - String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase(); + String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase(Locale.US); while (chunk.length() < 2) { chunk = "0" + chunk; } @@ -385,37 +382,6 @@ public class PGPHelper { } - public static String getPubkeyAsArmoredString(Context context, long keyId) { - PGPPublicKey key = ProviderHelper.getPGPPublicKeyByKeyId(context, keyId); - // if it is no public key get it from your own keys... - if (key == null) { - PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId); - if (secretKey == null) { - Log.e(Constants.TAG, "Key could not be found!"); - return null; - } - key = secretKey.getPublicKey(); - } - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ArmoredOutputStream aos = new ArmoredOutputStream(bos); - aos.setHeader("Version", PGPMain.getFullVersion(context)); - - String armouredKey = null; - try { - aos.write(key.getEncoded()); - aos.close(); - - armouredKey = bos.toString("UTF-8"); - } catch (IOException e) { - Log.e(Constants.TAG, "Problems while encoding key as armored string", e); - } - - Log.d(Constants.TAG, "key:" + armouredKey); - - return armouredKey; - } - public static String getFingerPrint(Context context, long keyId) { PGPPublicKey key = ProviderHelper.getPGPPublicKeyByKeyId(context, keyId); // if it is no public key get it from your own keys... @@ -432,7 +398,7 @@ public class PGPHelper { } public static String getSmallFingerPrint(long keyId) { - String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(); + String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(Locale.US); while (fingerPrint.length() < 8) { fingerPrint = "0" + fingerPrint; } @@ -449,4 +415,5 @@ public class PGPHelper { String s1 = data.substring(0, len - 8); return (Long.parseLong(s1, 16) << 32) | Long.parseLong(s2, 16); } + } diff --git a/APG/src/org/thialfihar/android/apg/helper/PGPMain.java b/APG/src/org/thialfihar/android/apg/helper/PGPMain.java index bf76901a1..cb4326f88 100644 --- a/APG/src/org/thialfihar/android/apg/helper/PGPMain.java +++ b/APG/src/org/thialfihar/android/apg/helper/PGPMain.java @@ -564,7 +564,7 @@ public class PGPMain { int oldKeys = 0; int badKeys = 0; try { - PGPKeyRing keyring = PGPHelper.decodeKeyRing(bufferedInput); + PGPKeyRing keyring = PGPConversionHelper.decodeKeyRing(bufferedInput); while (keyring != null) { int status = Integer.MIN_VALUE; // out of bounds value @@ -592,7 +592,7 @@ public class PGPMain { // TODO: needed? // obj = objectFactory.nextObject(); - keyring = PGPHelper.decodeKeyRing(bufferedInput); + keyring = PGPConversionHelper.decodeKeyRing(bufferedInput); } } catch (EOFException e) { // nothing to do, we are done @@ -652,6 +652,42 @@ public class PGPMain { return returnData; } + public static Bundle getKeyRings(Context context, long[] masterKeyIds, + OutputStream outStream, ProgressDialogUpdater progress) throws ApgGeneralException, + FileNotFoundException, PGPException, IOException { + Bundle returnData = new Bundle(); + + ArmoredOutputStream out = new ArmoredOutputStream(outStream); + out.setHeader("Version", getFullVersion(context)); + + int numKeys = 0; + for (int i = 0; i < masterKeyIds.length; ++i) { + updateProgress(progress, i * 100 / masterKeyIds.length, 100); + + // try to get it as a PGPPublicKeyRing, if that fails try to get it as a SecretKeyRing + PGPPublicKeyRing publicKeyRing = ProviderHelper.getPGPPublicKeyRingByRowId(context, + masterKeyIds[i]); + if (publicKeyRing != null) { + publicKeyRing.encode(out); + } else { + PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByRowId(context, + masterKeyIds[i]); + if (secretKeyRing != null) { + secretKeyRing.encode(out); + } else { + continue; + } + } + ++numKeys; + } + out.close(); + returnData.putInt(ApgIntentService.RESULT_EXPORT, numKeys); + + updateProgress(progress, R.string.progress_done, 100, 100); + + return returnData; + } + /** * Encrypt and Sign data * diff --git a/APG/src/org/thialfihar/android/apg/provider/ProviderHelper.java b/APG/src/org/thialfihar/android/apg/provider/ProviderHelper.java index 611b647e6..125b557a3 100644 --- a/APG/src/org/thialfihar/android/apg/provider/ProviderHelper.java +++ b/APG/src/org/thialfihar/android/apg/provider/ProviderHelper.java @@ -16,10 +16,12 @@ package org.thialfihar.android.apg.provider; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Date; +import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; @@ -28,6 +30,7 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.Constants; import org.thialfihar.android.apg.helper.PGPConversionHelper; import org.thialfihar.android.apg.helper.PGPHelper; +import org.thialfihar.android.apg.helper.PGPMain; import org.thialfihar.android.apg.provider.ApgContract.KeyRings; import org.thialfihar.android.apg.provider.ApgContract.UserIds; import org.thialfihar.android.apg.provider.ApgContract.Keys; @@ -40,6 +43,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.OperationApplicationException; import android.database.Cursor; +import android.database.DatabaseUtils; import android.net.Uri; import android.os.RemoteException; @@ -469,16 +473,38 @@ public class ProviderHelper { cr.delete(KeyRings.buildSecretKeyRingsUri(Long.toString(rowId)), null, null); } + /** + * Get master key id of keyring by its row id + * + * @param context + * @param keyRingRowId + * @return + */ public static long getPublicMasterKeyId(Context context, long keyRingRowId) { Uri queryUri = KeyRings.buildPublicKeyRingsUri(String.valueOf(keyRingRowId)); return getMasterKeyId(context, queryUri, keyRingRowId); } + /** + * Get master key id of keyring by its row id + * + * @param context + * @param keyRingRowId + * @return + */ public static long getSecretMasterKeyId(Context context, long keyRingRowId) { Uri queryUri = KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowId)); return getMasterKeyId(context, queryUri, keyRingRowId); } + /** + * Private helper method to get master key id of keyring by its row id + * + * @param context + * @param queryUri + * @param keyRingRowId + * @return + */ private static long getMasterKeyId(Context context, Uri queryUri, long keyRingRowId) { String[] projection = new String[] { KeyRings.MASTER_KEY_ID }; @@ -499,4 +525,135 @@ public class ProviderHelper { return masterKeyId; } + public static ArrayList<String> getPublicKeyRingsAsArmoredString(Context context, + long[] masterKeyIds) { + return getKeyRingsAsArmoredString(context, KeyRings.buildPublicKeyRingsUri(), masterKeyIds); + } + + public static ArrayList<String> getSecretKeyRingsAsArmoredString(Context context, + long[] masterKeyIds) { + return getKeyRingsAsArmoredString(context, KeyRings.buildSecretKeyRingsUri(), masterKeyIds); + } + + private static ArrayList<String> getKeyRingsAsArmoredString(Context context, Uri uri, + long[] masterKeyIds) { + ArrayList<String> output = new ArrayList<String>(); + + if (masterKeyIds != null && masterKeyIds.length > 0) { + + Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds); + + if (cursor != null) { + int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID); + int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA); + if (cursor.moveToFirst()) { + do { + Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol)); + + // get actual keyring data blob and write it to ByteArrayOutputStream + try { + Object keyRing = null; + byte[] data = cursor.getBlob(dataCol); + if (data != null) { + keyRing = PGPConversionHelper.BytesToPGPKeyRing(data); + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ArmoredOutputStream aos = new ArmoredOutputStream(bos); + aos.setHeader("Version", PGPMain.getFullVersion(context)); + + if (keyRing instanceof PGPSecretKeyRing) { + aos.write(((PGPSecretKeyRing) keyRing).getEncoded()); + } else if (keyRing instanceof PGPPublicKeyRing) { + aos.write(((PGPPublicKeyRing) keyRing).getEncoded()); + } + aos.close(); + + String armoredKey = bos.toString("UTF-8"); + + Log.d(Constants.TAG, "armouredKey:" + armoredKey); + + output.add(armoredKey); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException", e); + } + } while (cursor.moveToNext()); + } + } + + if (cursor != null) { + cursor.close(); + } + + } else { + Log.e(Constants.TAG, "No master keys given!"); + } + + return output; + } + + public static byte[] getPublicKeyRingsAsByteArray(Context context, long[] masterKeyIds) { + return getKeyRingsAsByteArray(context, KeyRings.buildPublicKeyRingsUri(), masterKeyIds); + } + + public static byte[] getSecretKeyRingsAsByteArray(Context context, long[] masterKeyIds) { + return getKeyRingsAsByteArray(context, KeyRings.buildSecretKeyRingsUri(), masterKeyIds); + } + + private static byte[] getKeyRingsAsByteArray(Context context, Uri uri, long[] masterKeyIds) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + if (masterKeyIds != null && masterKeyIds.length > 0) { + + Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds); + + if (cursor != null) { + int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID); + int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA); + if (cursor.moveToFirst()) { + do { + Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol)); + + // get actual keyring data blob and write it to ByteArrayOutputStream + try { + bos.write(cursor.getBlob(dataCol)); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException", e); + } + } while (cursor.moveToNext()); + } + } + + if (cursor != null) { + cursor.close(); + } + + } else { + Log.e(Constants.TAG, "No master keys given!"); + } + + return bos.toByteArray(); + } + + private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, Uri baseUri, + long[] masterKeyIds) { + Cursor cursor = null; + if (masterKeyIds != null && masterKeyIds.length > 0) { + + String inMasterKeyList = KeyRings.MASTER_KEY_ID + " IN ("; + for (int i = 0; i < masterKeyIds.length; ++i) { + if (i != 0) { + inMasterKeyList += ", "; + } + inMasterKeyList += DatabaseUtils.sqlEscapeString("" + masterKeyIds[i]); + } + inMasterKeyList += ")"; + + cursor = context.getContentResolver().query(baseUri, + new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.KEY_RING_DATA }, + inMasterKeyList, null, null); + } + + return cursor; + } } diff --git a/APG/src/org/thialfihar/android/apg/service/ApgService.java b/APG/src/org/thialfihar/android/apg/service/ApgApiService.java index a94887ba4..81d665e13 100644 --- a/APG/src/org/thialfihar/android/apg/service/ApgService.java +++ b/APG/src/org/thialfihar/android/apg/service/ApgApiService.java @@ -31,6 +31,9 @@ import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.R; import org.thialfihar.android.apg.helper.PGPMain; import org.thialfihar.android.apg.helper.PGPMain.ApgGeneralException; +import org.thialfihar.android.apg.service.handler.IApgDecryptHandler; +import org.thialfihar.android.apg.service.handler.IApgEncryptHandler; +import org.thialfihar.android.apg.service.handler.IApgGetDecryptionKeyIdHandler; import org.thialfihar.android.apg.util.InputData; import org.thialfihar.android.apg.util.Log; @@ -47,20 +50,20 @@ import android.os.RemoteException; * - is this service thread safe? Probably not! * */ -public class ApgService extends Service { +public class ApgApiService extends Service { Context mContext; @Override public void onCreate() { super.onCreate(); mContext = this; - Log.d(Constants.TAG, "ApgService, onCreate()"); + Log.d(Constants.TAG, "ApgApiService, onCreate()"); } @Override public void onDestroy() { super.onDestroy(); - Log.d(Constants.TAG, "ApgService, onDestroy()"); + Log.d(Constants.TAG, "ApgApiService, onDestroy()"); } @Override @@ -68,19 +71,19 @@ public class ApgService extends Service { return mBinder; } - 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 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 void encryptAndSignImplementation(byte[] inputBytes, String inputUri, boolean useAsciiArmor, int compression, long[] encryptionKeyIds, String encryptionPassphrase, int symmetricEncryptionAlgorithm, long signatureKeyId, int signatureHashAlgorithm, boolean signatureForceV3, String signaturePassphrase, - IApgEncryptSignHandler handler) throws RemoteException { + IApgEncryptHandler handler) throws RemoteException { try { // TODO use inputUri @@ -128,7 +131,7 @@ public class ApgService extends Service { byte[] outputBytes = ((ByteArrayOutputStream) output).toByteArray(); // return over handler on client side - handler.onSuccessEncrypt(outputBytes, null); + handler.onSuccess(outputBytes, null); } catch (Exception e) { Log.e(Constants.TAG, "ApgService, Exception!", e); @@ -141,7 +144,7 @@ public class ApgService extends Service { } private void decryptAndVerifyImplementation(byte[] inputBytes, String inputUri, - String passphrase, boolean assumeSymmetric, IApgDecryptVerifyHandler handler) + String passphrase, boolean assumeSymmetric, IApgDecryptHandler handler) throws RemoteException { try { @@ -170,7 +173,7 @@ public class ApgService extends Service { .getBoolean(ApgIntentService.RESULT_SIGNATURE_UNKNOWN); // return over handler on client side - handler.onSuccessDecrypt(outputBytes, null, signature, signatureKeyId, signatureUserId, + handler.onSuccess(outputBytes, null, signature, signatureKeyId, signatureUserId, signatureSuccess, signatureUnknown); } catch (Exception e) { Log.e(Constants.TAG, "ApgService, Exception!", e); @@ -184,7 +187,7 @@ public class ApgService extends Service { } private void getDecryptionKeyImplementation(byte[] inputBytes, String inputUri, - IApgHelperHandler handler) { + IApgGetDecryptionKeyIdHandler handler) { // TODO: implement inputUri @@ -195,20 +198,20 @@ public class ApgService extends Service { boolean symmetric; try { - secretKeyId = PGPMain.getDecryptionKeyId(ApgService.this, inputStream); + secretKeyId = PGPMain.getDecryptionKeyId(ApgApiService.this, inputStream); if (secretKeyId == Id.key.none) { throw new ApgGeneralException(getString(R.string.error_noSecretKeyFound)); } symmetric = false; } catch (PGPMain.NoAsymmetricEncryptionException e) { secretKeyId = Id.key.symmetric; - if (!PGPMain.hasSymmetricEncryption(ApgService.this, inputStream)) { + if (!PGPMain.hasSymmetricEncryption(ApgApiService.this, inputStream)) { throw new ApgGeneralException(getString(R.string.error_noKnownEncryptionFound)); } symmetric = true; } - handler.onSuccessGetDecryptionKey(secretKeyId, symmetric); + handler.onSuccess(secretKeyId, symmetric); } catch (Exception e) { Log.e(Constants.TAG, "ApgService, Exception!", e); @@ -227,12 +230,12 @@ public class ApgService extends Service { * * The real PGP code is located in PGPMain. */ - private final IApgService.Stub mBinder = new IApgService.Stub() { + private final IApgApiService.Stub mBinder = new IApgApiService.Stub() { @Override public void encryptAsymmetric(byte[] inputBytes, String inputUri, boolean useAsciiArmor, int compression, long[] encryptionKeyIds, int symmetricEncryptionAlgorithm, - IApgEncryptSignHandler handler) throws RemoteException { + IApgEncryptHandler handler) throws RemoteException { encryptAndSignImplementation(inputBytes, inputUri, useAsciiArmor, compression, encryptionKeyIds, null, symmetricEncryptionAlgorithm, Id.key.none, 0, false, @@ -242,7 +245,7 @@ public class ApgService extends Service { @Override public void encryptSymmetric(byte[] inputBytes, String inputUri, boolean useAsciiArmor, int compression, String encryptionPassphrase, int symmetricEncryptionAlgorithm, - IApgEncryptSignHandler handler) throws RemoteException { + IApgEncryptHandler handler) throws RemoteException { encryptAndSignImplementation(inputBytes, inputUri, useAsciiArmor, compression, null, encryptionPassphrase, symmetricEncryptionAlgorithm, Id.key.none, 0, false, @@ -253,7 +256,7 @@ public class ApgService extends Service { public void encryptAndSignAsymmetric(byte[] inputBytes, String inputUri, boolean useAsciiArmor, int compression, long[] encryptionKeyIds, int symmetricEncryptionAlgorithm, long signatureKeyId, int signatureHashAlgorithm, - boolean signatureForceV3, String signaturePassphrase, IApgEncryptSignHandler handler) + boolean signatureForceV3, String signaturePassphrase, IApgEncryptHandler handler) throws RemoteException { encryptAndSignImplementation(inputBytes, inputUri, useAsciiArmor, compression, @@ -265,7 +268,7 @@ public class ApgService extends Service { public void encryptAndSignSymmetric(byte[] inputBytes, String inputUri, boolean useAsciiArmor, int compression, String encryptionPassphrase, int symmetricEncryptionAlgorithm, long signatureKeyId, int signatureHashAlgorithm, - boolean signatureForceV3, String signaturePassphrase, IApgEncryptSignHandler handler) + boolean signatureForceV3, String signaturePassphrase, IApgEncryptHandler handler) throws RemoteException { encryptAndSignImplementation(inputBytes, inputUri, useAsciiArmor, compression, null, @@ -275,23 +278,22 @@ public class ApgService extends Service { @Override public void decryptAndVerifyAsymmetric(byte[] inputBytes, String inputUri, - String keyPassphrase, IApgDecryptVerifyHandler handler) throws RemoteException { + String keyPassphrase, IApgDecryptHandler handler) throws RemoteException { decryptAndVerifyImplementation(inputBytes, inputUri, keyPassphrase, false, handler); } @Override public void decryptAndVerifySymmetric(byte[] inputBytes, String inputUri, - String encryptionPassphrase, IApgDecryptVerifyHandler handler) - throws RemoteException { + String encryptionPassphrase, IApgDecryptHandler handler) throws RemoteException { decryptAndVerifyImplementation(inputBytes, inputUri, encryptionPassphrase, true, handler); } @Override - public void getDecryptionKey(byte[] inputBytes, String inputUri, IApgHelperHandler handler) - throws RemoteException { + public void getDecryptionKeyId(byte[] inputBytes, String inputUri, + IApgGetDecryptionKeyIdHandler handler) throws RemoteException { getDecryptionKeyImplementation(inputBytes, inputUri, handler); } diff --git a/APG/src/org/thialfihar/android/apg/service/ApgKeyService.java b/APG/src/org/thialfihar/android/apg/service/ApgKeyService.java new file mode 100644 index 000000000..32dd84675 --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/service/ApgKeyService.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service; + +import java.util.ArrayList; + +import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.provider.ProviderHelper; +import org.thialfihar.android.apg.service.handler.IApgGetKeyringsHandler; +import org.thialfihar.android.apg.util.Log; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.os.RemoteException; + +/** + * TODO: + * + * - is this service thread safe? Probably not! + * + */ +public class ApgKeyService extends Service { + Context mContext; + + @Override + public void onCreate() { + super.onCreate(); + mContext = this; + Log.d(Constants.TAG, "ApgKeyService, onCreate()"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.d(Constants.TAG, "ApgKeyService, onDestroy()"); + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /** + * This is the implementation of the interface IApgService. All methods are oneway, meaning + * asynchronous and return to the client using IApgHandler. + * + * The real PGP code is located in PGPMain. + */ + private final IApgKeyService.Stub mBinder = new IApgKeyService.Stub() { + + @Override + public void getPublicKeyRings(long[] masterKeyIds, boolean asAsciiArmoredStringArray, + IApgGetKeyringsHandler handler) throws RemoteException { + if (asAsciiArmoredStringArray) { + ArrayList<String> output = ProviderHelper.getPublicKeyRingsAsArmoredString( + mContext, masterKeyIds); + + handler.onSuccess(null, output); + } else { + byte[] outputBytes = ProviderHelper.getPublicKeyRingsAsByteArray(mContext, + masterKeyIds); + handler.onSuccess(outputBytes, null); + } + } + + @Override + public void getSecretKeyRings(long[] masterKeyIds, boolean asAsciiArmoredStringArray, + IApgGetKeyringsHandler handler) throws RemoteException { + if (asAsciiArmoredStringArray) { + ArrayList<String> output = ProviderHelper.getSecretKeyRingsAsArmoredString( + mContext, masterKeyIds); + + handler.onSuccess(null, output); + } else { + byte[] outputBytes = ProviderHelper.getSecretKeyRingsAsByteArray(mContext, + masterKeyIds); + handler.onSuccess(outputBytes, null); + } + + } + + }; + + /** + * As we can not throw an exception through Android RPC, we assign identifiers to the exception + * types. + * + * @param e + * @return + */ + // private int getExceptionId(Exception e) { + // if (e instanceof NoSuchProviderException) { + // return 0; + // } else if (e instanceof NoSuchAlgorithmException) { + // return 1; + // } else if (e instanceof SignatureException) { + // return 2; + // } else if (e instanceof IOException) { + // return 3; + // } else if (e instanceof ApgGeneralException) { + // return 4; + // } else if (e instanceof PGPException) { + // return 5; + // } else { + // return -1; + // } + // } + +} diff --git a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgService.aidl b/APG/src/org/thialfihar/android/apg/service/IApgApiService.aidl index 71c6a9e42..277ce6722 100644 --- a/APG-API-Lib/src/org/thialfihar/android/apg/service/IApgService.aidl +++ b/APG/src/org/thialfihar/android/apg/service/IApgApiService.aidl @@ -1,14 +1,30 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service; -import org.thialfihar.android.apg.service.IApgEncryptDecryptHandler; -import org.thialfihar.android.apg.service.IApgSignVerifyHandler; -import org.thialfihar.android.apg.service.IApgHelperHandler; +import org.thialfihar.android.apg.service.handler.IApgEncryptHandler; +import org.thialfihar.android.apg.service.handler.IApgDecryptHandler; +import org.thialfihar.android.apg.service.handler.IApgGetDecryptionKeyIdHandler; /** * All methods are oneway, which means they are asynchronous and non-blocking. * Results are returned into given Handler, which has to be implemented on client side. */ -interface IApgService { +interface IApgApiService { /** * Encrypt @@ -34,7 +50,7 @@ interface IApgService { */ oneway void encryptAsymmetric(in byte[] inputBytes, in String inputUri, in boolean useAsciiArmor, in int compression, in long[] encryptionKeyIds, in int symmetricEncryptionAlgorithm, - in IApgEncryptDecryptHandler handler); + in IApgEncryptHandler handler); /** * Same as encryptAsymmetric but using a passphrase for symmetric encryption @@ -44,7 +60,7 @@ interface IApgService { */ oneway void encryptSymmetric(in byte[] inputBytes, in String inputUri, in boolean useAsciiArmor, in int compression, in String encryptionPassphrase, in int symmetricEncryptionAlgorithm, - in IApgEncryptDecryptHandler handler); + in IApgEncryptHandler handler); /** * Encrypt and sign @@ -81,7 +97,7 @@ interface IApgService { in boolean useAsciiArmor, in int compression, in long[] encryptionKeyIds, in int symmetricEncryptionAlgorithm, in long signatureKeyId, in int signatureHashAlgorithm, in boolean signatureForceV3, in String signaturePassphrase, - in IApgEncryptDecryptHandler handler); + in IApgEncryptHandler handler); /** * Same as encryptAndSignAsymmetric but using a passphrase for symmetric encryption @@ -93,7 +109,7 @@ interface IApgService { in boolean useAsciiArmor, in int compression, in String encryptionPassphrase, in int symmetricEncryptionAlgorithm, in long signatureKeyId, in int signatureHashAlgorithm, in boolean signatureForceV3, in String signaturePassphrase, - in IApgEncryptDecryptHandler handler); + in IApgEncryptHandler handler); /** * Decrypts and verifies given input bytes. If no signature is present this method @@ -109,7 +125,7 @@ interface IApgService { * Handler where to return results to after successful encryption */ oneway void decryptAndVerifyAsymmetric(in byte[] inputBytes, in String inputUri, - in String keyPassphrase, in IApgEncryptDecryptHandler handler); + in String keyPassphrase, in IApgDecryptHandler handler); /** * Same as decryptAndVerifyAsymmetric but for symmetric decryption. @@ -118,13 +134,13 @@ interface IApgService { * Passphrase to decrypt */ oneway void decryptAndVerifySymmetric(in byte[] inputBytes, in String inputUri, - in String encryptionPassphrase, in IApgEncryptDecryptHandler handler); + in String encryptionPassphrase, in IApgDecryptHandler handler); /** * */ - oneway void getDecryptionKey(in byte[] inputBytes, in String inputUri, - in IApgHelperHandler handler); + oneway void getDecryptionKeyId(in byte[] inputBytes, in String inputUri, + in IApgGetDecryptionKeyIdHandler handler); }
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/IApgKeyService.aidl b/APG/src/org/thialfihar/android/apg/service/IApgKeyService.aidl new file mode 100644 index 000000000..12ecddc17 --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/service/IApgKeyService.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service; + +import org.thialfihar.android.apg.service.handler.IApgGetKeyringsHandler; + +/** + * All methods are oneway, which means they are asynchronous and non-blocking. + * Results are returned into given Handler, which has to be implemented on client side. + */ +interface IApgKeyService { + + oneway void getPublicKeyRings(in long[] masterKeyIds, in boolean asAsciiArmoredStringArray, + in IApgGetKeyringsHandler handler); + + oneway void getSecretKeyRings(in long[] masterKeyIds, in boolean asAsciiArmoredStringArray, + in IApgGetKeyringsHandler handler); +}
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/handler/IApgDecryptHandler.aidl b/APG/src/org/thialfihar/android/apg/service/handler/IApgDecryptHandler.aidl new file mode 100644 index 000000000..feb56bce6 --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/service/handler/IApgDecryptHandler.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgDecryptHandler { + + oneway void onSuccess(in byte[] outputBytes, in String outputUri, in boolean signature, + in long signatureKeyId, in String signatureUserId, in boolean signatureSuccess, + in boolean signatureUnknown); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/handler/IApgEncryptHandler.aidl b/APG/src/org/thialfihar/android/apg/service/handler/IApgEncryptHandler.aidl new file mode 100644 index 000000000..be0317715 --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/service/handler/IApgEncryptHandler.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgEncryptHandler { + /** + * Either output or streamUri is given. One of them is null + * + */ + oneway void onSuccess(in byte[] outputBytes, in String outputUri); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/handler/IApgGetDecryptionKeyIdHandler.aidl b/APG/src/org/thialfihar/android/apg/service/handler/IApgGetDecryptionKeyIdHandler.aidl new file mode 100644 index 000000000..020a80b99 --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/service/handler/IApgGetDecryptionKeyIdHandler.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgGetDecryptionKeyIdHandler { + + oneway void onSuccess(in long secretKeyId, in boolean symmetric); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/handler/IApgGetKeyringsHandler.aidl b/APG/src/org/thialfihar/android/apg/service/handler/IApgGetKeyringsHandler.aidl new file mode 100644 index 000000000..ffa9d0d2d --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/service/handler/IApgGetKeyringsHandler.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgGetKeyringsHandler { + /** + * Either outputBytes or outputString is given. One of them is null + * + */ + oneway void onSuccess(in byte[] outputBytes, in List<String> outputString); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/handler/IApgSignHandler.aidl b/APG/src/org/thialfihar/android/apg/service/handler/IApgSignHandler.aidl new file mode 100644 index 000000000..cf91e8bc4 --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/service/handler/IApgSignHandler.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgSignHandler { + /** + * Either output or streamUri is given. One of them is null + * + */ + oneway void onSuccess(in byte[] outputBytes, in String outputUri); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/service/handler/IApgVerifyHandler.aidl b/APG/src/org/thialfihar/android/apg/service/handler/IApgVerifyHandler.aidl new file mode 100644 index 000000000..6baaec758 --- /dev/null +++ b/APG/src/org/thialfihar/android/apg/service/handler/IApgVerifyHandler.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.service.handler; + +interface IApgVerifyHandler { + + oneway void onSuccess(in boolean signature, in long signatureKeyId, + in String signatureUserId, in boolean signatureSuccess, in boolean signatureUnknown); + + + oneway void onException(in int exceptionNumber, in String message); +}
\ No newline at end of file diff --git a/APG/src/org/thialfihar/android/apg/ui/KeyListSecretFragment.java b/APG/src/org/thialfihar/android/apg/ui/KeyListSecretFragment.java index 12a0bb131..0d12f5fe4 100644 --- a/APG/src/org/thialfihar/android/apg/ui/KeyListSecretFragment.java +++ b/APG/src/org/thialfihar/android/apg/ui/KeyListSecretFragment.java @@ -17,9 +17,10 @@ package org.thialfihar.android.apg.ui; +import java.util.ArrayList; + import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.R; -import org.thialfihar.android.apg.helper.PGPHelper; import org.thialfihar.android.apg.provider.ProviderHelper; import org.thialfihar.android.apg.provider.ApgContract.KeyRings; import org.thialfihar.android.apg.provider.ApgContract.UserIds; @@ -87,25 +88,21 @@ public class KeyListSecretFragment extends KeyListFragment implements int groupPosition = ExpandableListView.getPackedPositionGroup(expInfo.packedPosition); long keyRingRowId = getExpandableListAdapter().getGroupId(groupPosition); + // get master key id using row id + long masterKeyId = ProviderHelper + .getSecretMasterKeyId(mKeyListSecretActivity, keyRingRowId); + switch (item.getItemId()) { case Id.menu.edit: - // TODO: do it better directly with keyRingRowId? - long masterKeyId = ProviderHelper.getSecretMasterKeyId(mKeyListSecretActivity, - keyRingRowId); - mKeyListSecretActivity.checkPassPhraseAndEdit(masterKeyId); - return true; + return true; case Id.menu.share_qr_code: - // TODO: do it better directly with keyRingRowId? - long masterKeyId2 = ProviderHelper.getSecretMasterKeyId(mKeyListSecretActivity, - keyRingRowId); - - String msg = PGPHelper.getPubkeyAsArmoredString(mKeyListSecretActivity, masterKeyId2); + ArrayList<String> keyringArmored = ProviderHelper.getPublicKeyRingsAsArmoredString( + mKeyListSecretActivity, new long[] { masterKeyId }); + new IntentIntegrator(mKeyListSecretActivity).shareText(keyringArmored.get(0)); - new IntentIntegrator(mKeyListSecretActivity).shareText(msg); return true; - default: return super.onContextItemSelected(item); @@ -62,11 +62,15 @@ See http://docs.oseems.com/general/application/eclipse/fix-gc-overhead-limit-exc ## Basic goals -* Never (even with permissions) give out actual PGPSecretKey/PGPSecretKeyRing blobs * Intents without permissions should only work based on user interaction (e.g. click a button in a dialog) Android primitives to exchange data: Intent, Intent with return values, Send (also an Intent), Content Provider, AIDL +## Permission + +* ACCESS_API: Encrypt/Sign/Decrypt/Create keys without user interaction (intents, remote service), Read key information (not the actual keys)(content provider) +* ACCESS_KEYS: get and import actual public and secret keys (remote service) + ## Intents ### Without permission @@ -92,16 +96,13 @@ Android primitives to exchange data: Intent, Intent with return values, Send (al ## Content Provider * The whole content provider requires a permission (only read) -* Don't give out blobs +* Don't give out blobs (keys can be accessed by ACCESS_KEYS via remote service) * Make an internal and external content provider (or pathes with <path-permission>) * Look at android:grantUriPermissions especially for ApgServiceBlobProvider * Only give out android:readPermission -## Remote Service - -* The whole service requires the permission ACCESS_API - -## Resulting permission +## ApgApiService (Remote Service) +* ACCESS_API -* 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 +## ApgKeyService (Remote Service) +* ACCESS_KEYS
\ No newline at end of file |