package st.wow.git.passgo; import java.lang.Runnable; import java.lang.String; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import android.os.Handler; import android.os.IBinder; import java.io.InputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import org.openintents.openpgp.IOpenPgpService2; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; import android.content.ComponentName; import android.content.ServiceConnection; import android.content.Context; import android.content.ClipboardManager; import android.content.ClipData; import android.content.Intent; import android.util.Log; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.PendingIntent; import android.content.IntentSender; import android.content.IntentSender.OnFinished; import android.content.IntentSender.SendIntentException; import android.os.Bundle; import android.Manifest; import android.content.pm.PackageManager; import android.content.Context; import android.view.View; public class PgpConnect extends Fragment { Context ctx; Handler handler; ClipboardManager cb; IOpenPgpService2 mService; final int PERMISSIONS_REQUEST = 1; // Keychain >= 11 (and the standalone "Keychain" 5.x/6.x releases) expose // the OpenPGP API service under org.openintents.openpgp.IOpenPgpService; // older releases used org.openintents.openpgp.api.OpenPgpService (the // action hardcoded in OpenPgpServiceConnection). Try the new action // first and fall back to the legacy one. static final String[] SERVICE_ACTIONS = { "org.openintents.openpgp.IOpenPgpService", "org.openintents.openpgp.api.OpenPgpService", }; final ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = IOpenPgpService2.Stub.asInterface(service); Log.d("gio", "OpenPGP service connected: " + name); } @Override public void onServiceDisconnected(ComponentName name) { mService = null; Log.d("gio", "OpenPGP service disconnected"); } }; private void bindOpenPgp() { Intent bindIntent = null; for (String action : SERVICE_ACTIONS) { Intent i = new Intent(action); i.setPackage("org.sufficientlysecure.keychain"); if (ctx.getPackageManager().resolveService(i, 0) != null) { bindIntent = i; break; } } if (bindIntent == null) { Log.e("gio", "No OpenPGP service found in org.sufficientlysecure.keychain"); return; } Log.d("gio", "Binding OpenPGP service: " + bindIntent.getAction()); ctx.bindService(bindIntent, mConnection, Context.BIND_AUTO_CREATE); } // executeApi needs a live service; the bind is asynchronous, so if the // service is not connected yet, retry on the main looper (up to ~10 s) // instead of calling into a null service. private void runWhenConnected(final int chint, final Runnable task, final int attempt) { if (mService != null) { task.run(); return; } if (attempt > 33) { Log.e("gio", "OpenPGP service never connected"); stringResult(chint, null); return; } handler.postDelayed(new Runnable() { public void run() { runWhenConnected(chint, task, attempt + 1); } }, 300); } public PgpConnect(View view) { Log.d("gio", "PgpConnect()"); this.ctx = view.getContext(); this.handler = new Handler(this.ctx.getMainLooper()); PgpConnect inst = this; handler.post(new Runnable() { public void run() { Activity act = (Activity)ctx; FragmentTransaction ft = act.getFragmentManager().beginTransaction(); ft.add(inst, "PgpConnect"); ft.commitNow(); } }); } @Override public void onAttach(Context ctx) { super.onAttach(ctx); Log.d("gio", "onAttach()"); if (ctx instanceof Activity) { Log.d("gio", "It's an Activity!"); } bindOpenPgp(); cb = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); if (ctx.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ctx.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST); } System.loadLibrary("gio"); installComplete(this); } //For debugging: /*private void printExtras(Intent data) { Bundle bundle = data.getExtras(); if (bundle != null) { for (String k : bundle.keySet()) { Log.d("gio", "extra:" + k); } } }*/ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d("gio", "onActivityResult(" + requestCode + "): " + resultCode); super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) { Log.d("gio", "onActivityResult: not OK"); stringResult(requestCode, null); return; } switch (data.getAction()) { case OpenPgpApi.ACTION_DECRYPT_VERIFY: { Log.d("gio", "action decrypt"); _decrypt(data, requestCode); break; } case OpenPgpApi.ACTION_ENCRYPT: { Log.d("gio", "action encrypt"); _encrypt(data, requestCode); break; } case OpenPgpApi.ACTION_GET_KEY_IDS: Log.d("gio", "action getid"); String[] ids = data.getStringArrayExtra("user_ids"); if (ids != null && ids.length > 0) { Log.d("gio", "got some IDs"); stringResult(requestCode, ids[0]); } else { Log.d("gio", "no ids"); stringResult(requestCode, null); } break; default: { Log.d("gio", "some other action"); } } } public void Clip(byte []dat) { ClipData clip = ClipData.newPlainText("PgpConnect", new String(dat)); cb.setPrimaryClip(clip); } public void GetId(int chint) { if (handler == null) { stringResult(chint, null); return; } Log.d("gio", "GetId()"); handler.post(new Runnable() { public void run() { Intent data = new Intent(); data.setAction(OpenPgpApi.ACTION_GET_KEY_IDS); //data.setAction(OpenPgpApi.ACTION_ENCRYPT); data.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[]{" "}); _getid(data, chint); } }); } public void Decrypt(byte []dat, int chint) { if (handler == null) { stringResult(chint, null); return; } handler.post(new Runnable() { public void run() { Intent data = new Intent(); data.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); data.putExtra("DATA", dat); _decrypt(data, chint); } }); } private void _getid(Intent data, int chint) { Log.d("gio","_getid"); runWhenConnected(chint, new Runnable() { public void run() { doGetid(data, chint); } }, 0); } private void doGetid(Intent data, int chint) { InputStream is = null; ByteArrayOutputStream os = new ByteArrayOutputStream(); OpenPgpApi api = new OpenPgpApi(this.ctx, mService); Intent result = api.executeApi(data, is, os); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: { Log.d("gio","_getid: success"); try { String ret = os.toString("UTF-8"); //Log.d(OpenPgpApi.TAG, "output: " + ret); stringResult(chint, ret); } catch (UnsupportedEncodingException e) { Log.e("gio", "UnsupportedEncodingException", e); stringResult(chint, null); } break; } case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: { Log.d("gio","_getid: interaction required"); PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT); try { startIntentSenderForResult(pi.getIntentSender(), chint, null, 0, 0, 0, null); } catch (IntentSender.SendIntentException e) { Log.e("gio", "SendIntentException", e); stringResult(chint, null); } break; } case OpenPgpApi.RESULT_CODE_ERROR: { Log.d("gio","_getid: error"); OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); stringResult(chint, null); } } } private void _decrypt(Intent data, int chint) { Log.d("gio","_decrypt"); runWhenConnected(chint, new Runnable() { public void run() { doDecrypt(data, chint); } }, 0); } private void doDecrypt(Intent data, int chint) { byte []dat = data.getByteArrayExtra("DATA"); InputStream is = new ByteArrayInputStream(dat); ByteArrayOutputStream os = new ByteArrayOutputStream(); OpenPgpApi api = new OpenPgpApi(this.ctx, mService); Intent result = api.executeApi(data, is, os); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: { try { String ret = os.toString("UTF-8"); //Log.d(OpenPgpApi.TAG, "output: " + ret); stringResult(chint, ret); } catch (UnsupportedEncodingException e) { Log.e("gio", "UnsupportedEncodingException", e); stringResult(chint, null); } break; } case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: { PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT); try { startIntentSenderForResult(pi.getIntentSender(), chint, null, 0, 0, 0, null); } catch (IntentSender.SendIntentException e) { Log.e("gio", "SendIntentException", e); stringResult(chint, null); } break; } case OpenPgpApi.RESULT_CODE_ERROR: { OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); stringResult(chint, null); } } } public void Encrypt(byte[] id, byte[] dat, int chint) { if (handler == null) { stringResult(chint, null); return; } handler.post(new Runnable() { public void run() { Intent data = new Intent(); data.setAction(OpenPgpApi.ACTION_ENCRYPT); data.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[]{new String(id)}); data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); data.putExtra("DATA", dat); _encrypt(data, chint); } }); } private void _encrypt(Intent data, int chint) { Log.d("gio","_encrypt"); runWhenConnected(chint, new Runnable() { public void run() { doEncrypt(data, chint); } }, 0); } private void doEncrypt(Intent data, int chint) { byte []dat = data.getByteArrayExtra("DATA"); InputStream is = new ByteArrayInputStream(dat); ByteArrayOutputStream os = new ByteArrayOutputStream(); OpenPgpApi api = new OpenPgpApi(this.ctx, mService); Intent result = api.executeApi(data, is, os); switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: { try { String ret = os.toString("UTF-8"); //Log.d(OpenPgpApi.TAG, "output: " + ret); stringResult(chint, ret); } catch (UnsupportedEncodingException e) { Log.e("gio", "UnsupportedEncodingException", e); stringResult(chint, null); } if (result.hasExtra(OpenPgpApi.RESULT_SIGNATURE)) { OpenPgpSignatureResult sigResult = result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE); } break; } case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: { PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT); try { IntentSender sender = pi.getIntentSender(); //Log.d("PgpConnect", "IntentSender:" + sender.toString()); startIntentSenderForResult(sender, chint, null, 0, 0, 0, null); } catch (IntentSender.SendIntentException e) { Log.e("gio", "SendIntentException", e); stringResult(chint, null); } break; } case OpenPgpApi.RESULT_CODE_ERROR: { OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); stringResult(chint, null); break; } } } static private native void installComplete(PgpConnect p); static private native void stringResult(int requestCode, String result); }