package com.zeapo.pwdstore.crypto; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentSender; import android.content.SharedPreferences; import android.graphics.Typeface; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.zeapo.pwdstore.R; import com.zeapo.pwdstore.UserPreference; import org.apache.commons.io.FileUtils; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpServiceConnection; import org.openintents.openpgp.util.OpenPgpUtils; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.io.UnsupportedEncodingException; public class PgpHandler extends Activity { private OpenPgpServiceConnection mServiceConnection; public static final int REQUEST_CODE_SIGN = 9910; public static final int REQUEST_CODE_ENCRYPT = 9911; public static final int REQUEST_CODE_SIGN_AND_ENCRYPT = 9912; public static final int REQUEST_CODE_DECRYPT_AND_VERIFY = 9913; public static final int REQUEST_CODE_GET_KEY = 9914; public static final int REQUEST_CODE_GET_KEY_IDS = 9915; public final class Constants { public static final String TAG = "Keychain"; } private String filePath; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pgp_handler); Bundle extra = getIntent().getExtras(); ((TextView) findViewById(R.id.crypto_password_file)).setText(extra.getString("NAME")); // some persistance SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); String providerPackageName = settings.getString("openpgp_provider_list", ""); String accountName = settings.getString("openpgp_account_name", ""); if (TextUtils.isEmpty(providerPackageName)) { Toast.makeText(this, "No OpenPGP Provider selected!", Toast.LENGTH_LONG).show(); Intent intent = new Intent(this, UserPreference.class); startActivity(intent); } // bind to service mServiceConnection = new OpenPgpServiceConnection( PgpHandler.this, providerPackageName); mServiceConnection.bindToService(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.pgp_handler, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public void decrypt(View view) { decryptAndVerify(new Intent()); // getKeyIds(new Intent()); } private void handleError(final OpenPgpError error) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(PgpHandler.this, "onError id:" + error.getErrorId() + "\n\n" + error.getMessage(), Toast.LENGTH_LONG).show(); Log.e(Constants.TAG, "onError getErrorId:" + error.getErrorId()); Log.e(Constants.TAG, "onError getMessage:" + error.getMessage()); } }); } private void showToast(final String message) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(PgpHandler.this, message, Toast.LENGTH_SHORT).show(); } }); } public class DelayShow extends AsyncTask { int count = 0; final int SHOW_TIME = 10; ProgressBar pb; @Override protected void onPreExecute() { ((LinearLayout) findViewById(R.id.crypto_password_show_layout)).setVisibility(View.VISIBLE); TextView extraText = (TextView) findViewById(R.id.crypto_extra_show); if (extraText.getText().length() != 0) ((LinearLayout) findViewById(R.id.crypto_extra_show_layout)).setVisibility(View.VISIBLE); this.pb = (ProgressBar) findViewById(R.id.pbLoading); this.pb.setVisibility(ProgressBar.VISIBLE); this.pb.setMax(SHOW_TIME); } @Override protected Boolean doInBackground(Void... params) { while (this.count < SHOW_TIME) { SystemClock.sleep(1000); this.count++; publishProgress(this.count); } return true; } @Override protected void onPostExecute(Boolean b) { //clear password ((TextView) findViewById(R.id.crypto_password_show)).setText(""); ((LinearLayout) findViewById(R.id.crypto_password_show_layout)).setVisibility(View.INVISIBLE); ((LinearLayout) findViewById(R.id.crypto_extra_show_layout)).setVisibility(View.INVISIBLE); // run a background job and once complete this.pb.setVisibility(ProgressBar.INVISIBLE); } @Override protected void onProgressUpdate(Integer... values) { this.pb.setProgress(values[0]); } } private class MyCallback implements OpenPgpApi.IOpenPgpCallback { boolean returnToCiphertextField; ByteArrayOutputStream os; int requestCode; private MyCallback(boolean returnToCiphertextField, ByteArrayOutputStream os, int requestCode) { this.returnToCiphertextField = returnToCiphertextField; this.os = os; this.requestCode = requestCode; } @Override public void onReturn(Intent result) { switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: { showToast("RESULT_CODE_SUCCESS"); // encrypt/decrypt/sign/verify if (os != null) { try { Log.d(OpenPgpApi.TAG, "result: " + os.toByteArray().length + " str=" + os.toString("UTF-8")); if (returnToCiphertextField) { String[] passContent = os.toString("UTF-8").split("\n"); ((TextView) findViewById(R.id.crypto_password_show)) .setText(passContent[0]); String extraContent = os.toString("UTF-8").replaceFirst(".*\n",""); if (extraContent.length() != 0) { ((TextView) findViewById(R.id.crypto_extra_show)) .setText(extraContent); } new DelayShow().execute(); } else { showToast(os.toString()); } } catch (UnsupportedEncodingException e) { Log.e(Constants.TAG, "UnsupportedEncodingException", e); } } // verify if (result.hasExtra(OpenPgpApi.RESULT_SIGNATURE)) { OpenPgpSignatureResult sigResult = result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE); showToast(sigResult.toString()); } // get key ids if (result.hasExtra(OpenPgpApi.RESULT_KEY_IDS)) { long[] keyIds = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS); String out = "keyIds: "; for (int i = 0; i < keyIds.length; i++) { out += OpenPgpUtils.convertKeyIdToHex(keyIds[i]) + ", "; } showToast(out); } break; } case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: { showToast("RESULT_CODE_USER_INTERACTION_REQUIRED"); PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT); try { PgpHandler.this.startIntentSenderForResult(pi.getIntentSender(), requestCode, null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e(Constants.TAG, "SendIntentException", e); } break; } case OpenPgpApi.RESULT_CODE_ERROR: { showToast("RESULT_CODE_ERROR"); OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR); handleError(error); break; } } } } public void decryptAndVerify(Intent data) { data.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); try { InputStream is = FileUtils.openInputStream(new File(getIntent().getExtras().getString("FILE_PATH"))); ByteArrayOutputStream os = new ByteArrayOutputStream(); OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService()); api.executeApiAsync(data, is, os, new MyCallback(true, os, REQUEST_CODE_DECRYPT_AND_VERIFY)); } catch (Exception e) { e.printStackTrace(); } } public void getKeyIds(Intent data) { data.setAction(OpenPgpApi.ACTION_GET_KEY_IDS); data.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[]{getIntent().getExtras().getString("PGP-ID")}); OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService()); api.executeApiAsync(data, null, null, new MyCallback(false, null, REQUEST_CODE_GET_KEY_IDS)); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Log.d(Constants.TAG, "onActivityResult resultCode: " + resultCode); // try again after user interaction if (resultCode == RESULT_OK) { /* * The data originally given to one of the methods above, is again * returned here to be used when calling the method again after user * interaction. The Intent now also contains results from the user * interaction, for example selected key ids. */ switch (requestCode) { // case REQUEST_CODE_SIGN: { // sign(data); // break; // } // case REQUEST_CODE_ENCRYPT: { // encrypt(data); // break; // } // case REQUEST_CODE_SIGN_AND_ENCRYPT: { // signAndEncrypt(data); // break; // } case REQUEST_CODE_DECRYPT_AND_VERIFY: { decryptAndVerify(data); break; } // case REQUEST_CODE_GET_KEY: { // getKey(data); // break; // } case REQUEST_CODE_GET_KEY_IDS: { getKeyIds(data); break; } } } } }