/**
   * Checks if key has a passphrase
   *
   * @param secretKeyId
   * @return true if it has a passphrase
   */
  private static boolean hasPassphrase(Context context, long secretKeyId) {
    // check if the key has no passphrase
    try {
      PGPSecretKey secretKey =
          PGPHelper.getMasterKey(ProviderHelper.getPGPSecretKeyRingByKeyId(context, secretKeyId));
      // PGPSecretKey secretKey =
      // PGPHelper.getMasterKey(PGPMain.getSecretKeyRing(secretKeyId));

      Log.d(Constants.TAG, "Check if key has no passphrase...");
      PBESecretKeyDecryptor keyDecryptor =
          new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build("".toCharArray());
      PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor);
      if (testKey != null) {
        Log.d(Constants.TAG, "Key has no passphrase! Caches empty passphrase!");

        // cache empty passphrase
        PassphraseCacheService.addCachedPassphrase(context, secretKey.getKeyID(), "");

        return false;
      }
    } catch (PGPException e) {
      // silently catch
    }

    return true;
  }
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // let the actionbar look like Android's contact app
    ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setIcon(android.R.color.transparent);
    actionBar.setHomeButtonEnabled(true);

    setContentView(R.layout.api_app_settings_activity);

    mSettingsFragment =
        (AppSettingsFragment)
            getSupportFragmentManager().findFragmentById(R.id.api_app_settings_fragment);

    Intent intent = getIntent();
    mAppUri = intent.getData();
    if (mAppUri == null) {
      Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!");
      finish();
      return;
    } else {
      Log.d(Constants.TAG, "uri: " + mAppUri);
      loadData(savedInstanceState, mAppUri);
    }
  }
  /** Set progress of ProgressDialog by sending message to handler on UI thread */
  public void setProgress(String message, int progress, int max) {
    Log.d(
        Constants.TAG,
        "Send message by setProgress with progressDialogUpdater=" + progress + ", max=" + max);

    Bundle data = new Bundle();
    if (message != null) {
      data.putString(ApgIntentServiceHandler.DATA_MESSAGE, message);
    }
    data.putInt(ApgIntentServiceHandler.DATA_PROGRESS, progress);
    data.putInt(ApgIntentServiceHandler.DATA_PROGRESS_MAX, max);

    sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_UPDATE_PROGRESS, null, data);
  }
  private void loadData(Bundle savedInstanceState, Uri appUri) {
    // TODO: load this also like other fragment with newInstance arguments?
    AppSettings settings = ProviderHelper.getApiAppSettings(this, appUri);
    mSettingsFragment.setAppSettings(settings);

    String appName;
    PackageManager pm = getPackageManager();
    try {
      ApplicationInfo ai = pm.getApplicationInfo(settings.getPackageName(), 0);
      appName = (String) pm.getApplicationLabel(ai);
    } catch (PackageManager.NameNotFoundException e) {
      // fallback
      appName = settings.getPackageName();
    }
    setTitle(appName);

    Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build();
    Log.d(Constants.TAG, "accountsUri: " + accountsUri);
    startListFragment(savedInstanceState, accountsUri);
  }
Example #5
0
  /**
   * Get a file path from a Uri.
   *
   * <p>from https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/
   * afilechooser/utils/FileUtils.java
   *
   * @param context
   * @param uri
   * @return
   * @author paulburke
   */
  public static String getPath(Context context, Uri uri) {

    Log.d(
        Constants.TAG + " File -",
        "Authority: "
            + uri.getAuthority()
            + ", Fragment: "
            + uri.getFragment()
            + ", Port: "
            + uri.getPort()
            + ", Query: "
            + uri.getQuery()
            + ", Scheme: "
            + uri.getScheme()
            + ", Host: "
            + uri.getHost()
            + ", Segments: "
            + uri.getPathSegments().toString());

    if ("content".equalsIgnoreCase(uri.getScheme())) {
      String[] projection = {"_data"};
      Cursor cursor = null;

      try {
        cursor = context.getContentResolver().query(uri, projection, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow("_data");
        if (cursor.moveToFirst()) {
          return cursor.getString(column_index);
        }
      } catch (Exception e) {
        // Eat it
      }
    } else if ("file".equalsIgnoreCase(uri.getScheme())) {
      return uri.getPath();
    }

    return null;
  }
Example #6
0
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.edit_key);

    mActionBar = getSupportActionBar();
    mActionBar.setDisplayShowTitleEnabled(true);

    // set actionbar without home button if called from another app
    if (getCallingPackage() != null && getCallingPackage().equals(Constants.PACKAGE_NAME)) {
      mActionBar.setDisplayHomeAsUpEnabled(true);
      mActionBar.setHomeButtonEnabled(true);
    } else {
      mActionBar.setDisplayHomeAsUpEnabled(false);
      mActionBar.setHomeButtonEnabled(false);
    }

    // find views
    mChangePassPhrase = (Button) findViewById(R.id.edit_key_btn_change_pass_phrase);
    mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase);

    mUserIds = new Vector<String>();
    mKeys = new Vector<PGPSecretKey>();
    mKeysUsages = new Vector<Integer>();

    // Catch Intents opened from other apps
    mIntent = getIntent();

    // Handle intents
    Bundle extras = mIntent.getExtras();
    if (ACTION_CREATE_KEY.equals(mIntent.getAction())) {
      mActionBar.setTitle(R.string.title_createKey);

      mCurrentPassPhrase = "";

      if (extras != null) {
        // if userId is given, prefill the fields
        if (extras.containsKey(EXTRA_USER_IDS)) {
          Log.d(Constants.TAG, "UserIds are given!");
          mUserIds.add(extras.getString(EXTRA_USER_IDS));
        }

        // if no passphrase is given
        if (extras.containsKey(EXTRA_NO_PASSPHRASE)) {
          boolean noPassphrase = extras.getBoolean(EXTRA_NO_PASSPHRASE);
          if (noPassphrase) {
            // check "no passphrase" checkbox and remove button
            mNoPassphrase.setChecked(true);
            mChangePassPhrase.setVisibility(View.GONE);
          }
        }

        // generate key
        if (extras.containsKey(EXTRA_GENERATE_DEFAULT_KEYS)) {
          boolean generateDefaultKeys = extras.getBoolean(EXTRA_GENERATE_DEFAULT_KEYS);
          if (generateDefaultKeys) {

            // build layout in handler after generating keys not directly in onCreate
            mBuildLayout = false;

            // Send all information needed to service generate keys in other thread
            Intent intent = new Intent(this, ApgService.class);
            intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_GENERATE_DEFAULT_RSA_KEYS);

            // fill values for this action
            Bundle data = new Bundle();
            data.putString(ApgService.SYMMETRIC_PASSPHRASE, mCurrentPassPhrase);

            intent.putExtra(ApgService.EXTRA_DATA, data);

            // show progress dialog
            mGeneratingDialog =
                ProgressDialogFragment.newInstance(
                    R.string.progress_generating, ProgressDialog.STYLE_SPINNER);

            // Message is received after generating is done in ApgService
            ApgHandler saveHandler =
                new ApgHandler(this, mGeneratingDialog) {
                  public void handleMessage(Message message) {
                    // handle messages by standard ApgHandler first
                    super.handleMessage(message);

                    if (message.arg1 == ApgHandler.MESSAGE_OKAY) {
                      // get new key from data bundle returned from service
                      Bundle data = message.getData();
                      PGPSecretKeyRing masterKeyRing =
                          PGPConversionHelper.BytesToPGPSecretKeyRing(
                              data.getByteArray(ApgService.RESULT_NEW_KEY));
                      PGPSecretKeyRing subKeyRing =
                          PGPConversionHelper.BytesToPGPSecretKeyRing(
                              data.getByteArray(ApgService.RESULT_NEW_KEY2));

                      // add master key
                      Iterator<PGPSecretKey> masterIt = masterKeyRing.getSecretKeys();
                      mKeys.add(masterIt.next());
                      mKeysUsages.add(Id.choice.usage.sign_only);

                      // add sub key
                      Iterator<PGPSecretKey> subIt = subKeyRing.getSecretKeys();
                      subIt.next(); // masterkey
                      mKeys.add(subIt.next());
                      mKeysUsages.add(Id.choice.usage.encrypt_only);

                      buildLayout();
                    }
                  };
                };

            // Create a new Messenger for the communication back
            Messenger messenger = new Messenger(saveHandler);
            intent.putExtra(ApgService.EXTRA_MESSENGER, messenger);

            mGeneratingDialog.show(getSupportFragmentManager(), "dialog");

            // start service with intent
            startService(intent);
          }
        }
      }
    } else if (ACTION_EDIT_KEY.equals(mIntent.getAction())) {
      mActionBar.setTitle(R.string.title_editKey);

      mCurrentPassPhrase = PGPMain.getEditPassPhrase();
      if (mCurrentPassPhrase == null) {
        mCurrentPassPhrase = "";
      }

      if (mCurrentPassPhrase.equals("")) {
        // check "no passphrase" checkbox and remove button
        mNoPassphrase.setChecked(true);
        mChangePassPhrase.setVisibility(View.GONE);
      }

      if (extras != null) {

        if (extras.containsKey(EXTRA_KEY_ID)) {
          long keyId = mIntent.getExtras().getLong(EXTRA_KEY_ID);

          if (keyId != 0) {
            PGPSecretKey masterKey = null;
            mKeyRing = PGPMain.getSecretKeyRing(keyId);
            if (mKeyRing != null) {
              masterKey = PGPHelper.getMasterKey(mKeyRing);
              for (PGPSecretKey key :
                  new IterableIterator<PGPSecretKey>(mKeyRing.getSecretKeys())) {
                mKeys.add(key);
                mKeysUsages.add(-1); // get usage when view is created
              }
            }
            if (masterKey != null) {
              for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
                mUserIds.add(userId);
              }
            }
          }
        }
      }
    }

    mChangePassPhrase.setOnClickListener(
        new OnClickListener() {
          public void onClick(View v) {
            showDialog(Id.dialog.new_pass_phrase);
          }
        });

    // disable passphrase when no passphrase checkobox is checked!
    mNoPassphrase.setOnCheckedChangeListener(
        new OnCheckedChangeListener() {

          @Override
          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
              // remove passphrase
              mNewPassPhrase = null;

              mChangePassPhrase.setVisibility(View.GONE);
            } else {
              mChangePassPhrase.setVisibility(View.VISIBLE);
            }
          }
        });

    if (mBuildLayout) {
      buildLayout();
    }
  }
  /**
   * The IntentService calls this method from the default worker thread with the intent that started
   * the service. When this method returns, IntentService stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
    Bundle extras = intent.getExtras();
    if (extras == null) {
      Log.e(Constants.TAG, "Extras bundle is null!");
      return;
    }

    if (!(extras.containsKey(EXTRA_MESSENGER)
        || extras.containsKey(EXTRA_DATA)
        || (intent.getAction() == null))) {
      Log.e(Constants.TAG, "Extra bundle must contain a messenger, a data bundle, and an action!");
      return;
    }

    Uri dataUri = intent.getData();

    mMessenger = (Messenger) extras.get(EXTRA_MESSENGER);
    Bundle data = extras.getBundle(EXTRA_DATA);

    OtherHelper.logDebugBundle(data, "EXTRA_DATA");

    String action = intent.getAction();

    // executeServiceMethod action from extra bundle
    if (ACTION_ENCRYPT_SIGN.equals(action)
        || "org.thialfihar.android.apg.intent.ENCRYPT_AND_RETURN".equals(action)) {
      try {
        /* Input */
        int target = data.getInt(TARGET);

        long signatureKeyId = data.getLong(ENCRYPT_SIGNATURE_KEY_ID);
        String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE);

        boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR);
        long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS);
        int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID);
        boolean generateSignature = data.getBoolean(ENCRYPT_GENERATE_SIGNATURE);
        InputStream inStream;
        long inLength;
        InputData inputData;
        OutputStream outStream;
        //                String streamFilename = null;
        switch (target) {
          case TARGET_BYTES: /* encrypting bytes directly */
            byte[] bytes = data.getByteArray(ENCRYPT_MESSAGE_BYTES);

            inStream = new ByteArrayInputStream(bytes);
            inLength = bytes.length;

            inputData = new InputData(inStream, inLength);
            outStream = new ByteArrayOutputStream();

            break;
          case TARGET_URI: /* encrypting file */
            String inputFile = data.getString(ENCRYPT_INPUT_FILE);
            String outputFile = data.getString(ENCRYPT_OUTPUT_FILE);

            // check if storage is ready
            if (!FileHelper.isStorageMounted(inputFile)
                || !FileHelper.isStorageMounted(outputFile)) {
              throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
            }

            inStream = new FileInputStream(inputFile);
            File file = new File(inputFile);
            inLength = file.length();
            inputData = new InputData(inStream, inLength);

            outStream = new FileOutputStream(outputFile);

            break;

            // TODO: not used currently
            //                    case TARGET_STREAM: /* Encrypting stream from content uri */
            //                        Uri providerUri = (Uri)
            // data.getParcelable(ENCRYPT_PROVIDER_URI);
            //
            //                        // InputStream
            //                        InputStream in =
            // getContentResolver().openInputStream(providerUri);
            //                        inLength = PgpHelper.getLengthOfStream(in);
            //                        inputData = new InputData(in, inLength);
            //
            //                        // OutputStream
            //                        try {
            //                            while (true) {
            //                                streamFilename = PgpHelper.generateRandomFilename(32);
            //                                if (streamFilename == null) {
            //                                    throw new PgpGeneralException("couldn't generate
            // random file name");
            //                                }
            //                                openFileInput(streamFilename).close();
            //                            }
            //                        } catch (FileNotFoundException e) {
            //                            // found a name that isn't used yet
            //                        }
            //                        outStream = openFileOutput(streamFilename,
            // Context.MODE_PRIVATE);
            //
            //                        break;

          default:
            throw new PgpGeneralException("No target choosen!");
        }

        /* Operation */
        PgpSignEncrypt.Builder builder =
            new PgpSignEncrypt.Builder(this, inputData, outStream, new ProviderHelper(this));
        builder.setProgressable(this);

        if (generateSignature) {
          Log.d(Constants.TAG, "generating signature...");
          builder
              .setEnableAsciiArmorOutput(useAsciiArmor)
              .setSignatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
              .setSignatureKeyId(signatureKeyId)
              .setSignatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
              .setSignaturePassphrase(
                  PassphraseCacheService.getCachedPassphrase(this, signatureKeyId));

          builder.build().generateSignature();
        } else {
          Log.d(Constants.TAG, "encrypt...");
          builder
              .setEnableAsciiArmorOutput(useAsciiArmor)
              .setCompressionId(compressionId)
              .setSymmetricEncryptionAlgorithm(
                  Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
              .setSignatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
              .setEncryptionKeyIds(encryptionKeyIds)
              .setSymmetricPassphrase(symmetricPassphrase)
              .setSignatureKeyId(signatureKeyId)
              .setSignatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
              .setSignaturePassphrase(
                  PassphraseCacheService.getCachedPassphrase(this, signatureKeyId));

          builder.build().execute();
        }

        outStream.close();

        /* Output */

        Bundle resultData = new Bundle();

        switch (target) {
          case TARGET_BYTES:
            byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();

            resultData.putByteArray(RESULT_BYTES, output);

            break;
          case TARGET_URI:
            // nothing, file was written, just send okay

            break;
            //                    case TARGET_STREAM:
            //                        String uri =
            // DataStream.buildDataStreamUri(streamFilename).toString();
            //                        resultData.putString(RESULT_URI, uri);
            //
            //                        break;
        }

        OtherHelper.logDebugBundle(resultData, "resultData");

        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY, resultData);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_DECRYPT_VERIFY.equals(action)) {
      try {
        /* Input */
        int target = data.getInt(TARGET);

        byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES);
        String passphrase = data.getString(DECRYPT_PASSPHRASE);

        InputStream inStream;
        long inLength;
        InputData inputData;
        OutputStream outStream;
        String streamFilename = null;
        switch (target) {
          case TARGET_BYTES: /* decrypting bytes directly */
            inStream = new ByteArrayInputStream(bytes);
            inLength = bytes.length;

            inputData = new InputData(inStream, inLength);
            outStream = new ByteArrayOutputStream();

            break;

          case TARGET_URI: /* decrypting file */
            String inputFile = data.getString(ENCRYPT_INPUT_FILE);
            String outputFile = data.getString(ENCRYPT_OUTPUT_FILE);

            // check if storage is ready
            if (!FileHelper.isStorageMounted(inputFile)
                || !FileHelper.isStorageMounted(outputFile)) {
              throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
            }

            // InputStream
            inLength = -1;
            inStream = new FileInputStream(inputFile);
            File file = new File(inputFile);
            inLength = file.length();
            inputData = new InputData(inStream, inLength);

            // OutputStream
            outStream = new FileOutputStream(outputFile);

            break;

            // TODO: not used, maybe contains code useful for new decrypt method for files?
            //                    case TARGET_STREAM: /* decrypting stream from content uri */
            //                        Uri providerUri = (Uri)
            // data.getParcelable(ENCRYPT_PROVIDER_URI);
            //
            //                        // InputStream
            //                        InputStream in =
            // getContentResolver().openInputStream(providerUri);
            //                        inLength = PgpHelper.getLengthOfStream(in);
            //                        inputData = new InputData(in, inLength);
            //
            //                        // OutputStream
            //                        try {
            //                            while (true) {
            //                                streamFilename = PgpHelper.generateRandomFilename(32);
            //                                if (streamFilename == null) {
            //                                    throw new PgpGeneralException("couldn't generate
            // random file name");
            //                                }
            //                                openFileInput(streamFilename).close();
            //                            }
            //                        } catch (FileNotFoundException e) {
            //                            // found a name that isn't used yet
            //                        }
            //                        outStream = openFileOutput(streamFilename,
            // Context.MODE_PRIVATE);
            //
            //                        break;

          default:
            throw new PgpGeneralException("No target choosen!");
        }

        /* Operation */

        Bundle resultData = new Bundle();

        // verifyText and decrypt returning additional resultData values for the
        // verification of signatures
        PgpDecryptVerify.Builder builder =
            new PgpDecryptVerify.Builder(this, inputData, outStream, new ProviderHelper(this));
        builder.setProgressable(this);

        builder.setAllowSymmetricDecryption(true).setPassphrase(passphrase);

        PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();

        outStream.close();

        resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult);

        /* Output */

        switch (target) {
          case TARGET_BYTES:
            byte output[] = ((ByteArrayOutputStream) outStream).toByteArray();
            resultData.putByteArray(RESULT_DECRYPTED_BYTES, output);
            break;
          case TARGET_URI:
            // nothing, file was written, just send okay and verification bundle

            break;
            //                    case TARGET_STREAM:
            //                        String uri =
            // DataStream.buildDataStreamUri(streamFilename).toString();
            //                        resultData.putString(RESULT_URI, uri);
            //
            //                        break;
        }

        OtherHelper.logDebugBundle(resultData, "resultData");

        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY, resultData);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_SAVE_KEYRING.equals(action)) {
      try {
        /* Input */
        SaveKeyringParcel saveParams = data.getParcelable(SAVE_KEYRING_PARCEL);
        String oldPassphrase = saveParams.oldPassphrase;
        String newPassphrase = saveParams.newPassphrase;
        boolean canSign = true;

        if (data.containsKey(SAVE_KEYRING_CAN_SIGN)) {
          canSign = data.getBoolean(SAVE_KEYRING_CAN_SIGN);
        }

        if (newPassphrase == null) {
          newPassphrase = oldPassphrase;
        }

        long masterKeyId = saveParams.keys.get(0).getKeyId();

        /* Operation */
        if (!canSign) {
          PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 50, 100));
          PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(this, masterKeyId);
          keyRing = keyOperations.changeSecretKeyPassphrase(keyRing, oldPassphrase, newPassphrase);
          setProgress(R.string.progress_saving_key_ring, 50, 100);
          ProviderHelper.saveKeyRing(this, keyRing);
          setProgress(R.string.progress_done, 100, 100);
        } else {
          PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100));
          PGPSecretKeyRing privkey =
              ProviderHelper.getPGPSecretKeyRingByMasterKeyId(this, masterKeyId);
          PGPPublicKeyRing pubkey =
              ProviderHelper.getPGPPublicKeyRingByMasterKeyId(this, masterKeyId);
          PgpKeyOperation.Pair<PGPSecretKeyRing, PGPPublicKeyRing> pair =
              keyOperations.buildSecretKey(privkey, pubkey, saveParams);
          setProgress(R.string.progress_saving_key_ring, 90, 100);
          ProviderHelper.saveKeyRing(this, pair.first);
          ProviderHelper.saveKeyRing(this, pair.second);
          setProgress(R.string.progress_done, 100, 100);
        }
        PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase);

        /* Output */
        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_GENERATE_KEY.equals(action)) {
      try {
        /* Input */
        int algorithm = data.getInt(GENERATE_KEY_ALGORITHM);
        String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE);
        int keysize = data.getInt(GENERATE_KEY_KEY_SIZE);
        boolean masterKey = data.getBoolean(GENERATE_KEY_MASTER_KEY);

        /* Operation */
        PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100));
        Key newKey = keyOperations.createKey(algorithm, keysize, passphrase, masterKey);

        /* Output */
        Bundle resultData = new Bundle();
        resultData.putSerializable(RESULT_NEW_KEY, newKey);

        OtherHelper.logDebugBundle(resultData, "resultData");

        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY, resultData);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_GENERATE_DEFAULT_RSA_KEYS.equals(action)) {
      // generate one RSA 4096 key for signing and one subkey for encrypting!
      try {
        /* Input */
        String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE);
        ArrayList<Key> newKeys = new ArrayList<Key>();
        ArrayList<Integer> keyUsageList = new ArrayList<Integer>();

        /* Operation */
        int keysTotal = 3;
        int keysCreated = 0;
        setProgress(
            getApplicationContext()
                .getResources()
                .getQuantityString(R.plurals.progress_generating, keysTotal),
            keysCreated,
            keysTotal);
        PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100));

        Key masterKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, true);
        newKeys.add(masterKey);
        keyUsageList.add(KeyFlags.CERTIFY_OTHER);
        keysCreated++;
        setProgress(keysCreated, keysTotal);

        Key subKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, false);
        newKeys.add(subKey);
        keyUsageList.add(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE);
        keysCreated++;
        setProgress(keysCreated, keysTotal);

        subKey = keyOperations.createKey(Id.choice.algorithm.rsa, 4096, passphrase, false);
        newKeys.add(subKey);
        keyUsageList.add(KeyFlags.SIGN_DATA);
        keysCreated++;
        setProgress(keysCreated, keysTotal);

        // TODO: default to one master for cert, one sub for encrypt and one sub
        //       for sign

        /* Output */

        Bundle resultData = new Bundle();
        resultData.putSerializable(RESULT_NEW_KEY, newKeys);
        resultData.putIntegerArrayList(RESULT_KEY_USAGES, keyUsageList);

        OtherHelper.logDebugBundle(resultData, "resultData");

        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY, resultData);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_DELETE_FILE_SECURELY.equals(action)) {
      try {
        /* Input */
        String deleteFile = data.getString(DELETE_FILE);

        /* Operation */
        try {
          PgpHelper.deleteFileSecurely(this, this, new File(deleteFile));
        } catch (FileNotFoundException e) {
          throw new PgpGeneralException(getString(R.string.error_file_not_found, deleteFile));
        } catch (IOException e) {
          throw new PgpGeneralException(getString(R.string.error_file_delete_failed, deleteFile));
        }

        /* Output */
        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_IMPORT_KEYRING.equals(action)) {
      try {
        List<ImportKeysListEntry> entries = data.getParcelableArrayList(IMPORT_KEY_LIST);

        Bundle resultData = new Bundle();

        PgpImportExport pgpImportExport = new PgpImportExport(this, this);
        resultData = pgpImportExport.importKeyRings(entries);

        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY, resultData);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_EXPORT_KEYRING.equals(action)) {
      try {

        /* Input */
        int keyType = Id.type.public_key;
        if (data.containsKey(EXPORT_KEY_TYPE)) {
          keyType = data.getInt(EXPORT_KEY_TYPE);
        }
        long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
        String outputFile = data.getString(EXPORT_FILENAME);

        // If not exporting all keys get the masterKeyIds of the keys to export from the intent
        boolean exportAll = data.getBoolean(EXPORT_ALL);

        /* Operation */

        // check if storage is ready
        if (!FileHelper.isStorageMounted(outputFile)) {
          throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
        }

        ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>();
        ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>();
        ArrayList<Long> allPublicMasterKeyIds = ProviderHelper.getPublicKeyRingsMasterKeyIds(this);
        ArrayList<Long> allSecretMasterKeyIds = ProviderHelper.getSecretKeyRingsMasterKeyIds(this);

        if (exportAll) {
          // get all public key ring MasterKey ids
          if (keyType == Id.type.public_key || keyType == Id.type.public_secret_key) {
            publicMasterKeyIds = allPublicMasterKeyIds;
          }
          // get all secret key ring MasterKey ids
          if (keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) {
            secretMasterKeyIds = allSecretMasterKeyIds;
          }
        } else {

          for (long masterKeyId : masterKeyIds) {
            if ((keyType == Id.type.public_key || keyType == Id.type.public_secret_key)
                && allPublicMasterKeyIds.contains(masterKeyId)) {
              publicMasterKeyIds.add(masterKeyId);
            }
            if ((keyType == Id.type.secret_key || keyType == Id.type.public_secret_key)
                && allSecretMasterKeyIds.contains(masterKeyId)) {
              secretMasterKeyIds.add(masterKeyId);
            }
          }
        }

        PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);

        Bundle resultData =
            pgpImportExport.exportKeyRings(
                publicMasterKeyIds, secretMasterKeyIds, new FileOutputStream(outputFile));

        if (mIsCanceled) {
          new File(outputFile).delete();
        }

        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY, resultData);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_UPLOAD_KEYRING.equals(action)) {
      try {

        /* Input */
        String keyServer = data.getString(UPLOAD_KEY_SERVER);
        // and dataUri!

        /* Operation */
        HkpKeyServer server = new HkpKeyServer(keyServer);

        KeyRing keyRing = ProviderHelper.getKeyRing(this, dataUri);
        if (keyRing != null) {
          PgpImportExport pgpImportExport = new PgpImportExport(this, null);

          boolean uploaded =
              pgpImportExport.uploadKeyRingToServer(server, new PublicKeyRing(keyRing));
          if (!uploaded) {
            throw new PgpGeneralException("Unable to export key to selected server");
          }
        }

        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action)) {
      try {
        ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST);
        String keyServer = data.getString(DOWNLOAD_KEY_SERVER);

        // TODO: add extra which requires fingerprint suport and force verification!
        // only supported by newer sks keyserver versions

        // this downloads the keys and places them into the ImportKeysListEntry entries
        HkpKeyServer server = new HkpKeyServer(keyServer);

        for (ImportKeysListEntry entry : entries) {
          // if available use complete fingerprint for get request
          byte[] downloadedKeyBytes;
          if (entry.getFingerPrintHex() != null) {
            downloadedKeyBytes = server.get("0x" + entry.getFingerPrintHex()).getBytes();
          } else {
            downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes();
          }

          // create PGPKeyRing object based on downloaded armored key
          PGPKeyRing downloadedKey = null;
          BufferedInputStream bufferedInput =
              new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes));
          if (bufferedInput.available() > 0) {
            InputStream in = PGPUtil.getDecoderStream(bufferedInput);
            PGPObjectFactory objectFactory = new PGPObjectFactory(in);

            // get first object in block
            Object obj;
            if ((obj = objectFactory.nextObject()) != null) {
              Log.d(Constants.TAG, "Found class: " + obj.getClass());

              if (obj instanceof PGPKeyRing) {
                downloadedKey = (PGPKeyRing) obj;
              } else {
                throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
              }
            }
          }

          // verify downloaded key by comparing fingerprints
          if (entry.getFingerPrintHex() != null) {
            String downloadedKeyFp =
                PgpKeyHelper.convertFingerprintToHex(downloadedKey.getPublicKey().getFingerprint());
            if (downloadedKeyFp.equals(entry.getFingerPrintHex())) {
              Log.d(
                  Constants.TAG,
                  "fingerprint of downloaded key is the same as " + "the requested fingerprint!");
            } else {
              throw new PgpGeneralException(
                  "fingerprint of downloaded key is "
                      + "NOT the same as the requested fingerprint!");
            }
          }

          // save key bytes in entry object for doing the
          // actual import afterwards
          entry.setBytes(downloadedKey.getEncoded());
        }

        Intent importIntent = new Intent(this, ApgIntentService.class);

        importIntent.setAction(ACTION_IMPORT_KEYRING);
        Bundle importData = new Bundle();
        importData.putParcelableArrayList(IMPORT_KEY_LIST, entries);
        importIntent.putExtra(EXTRA_DATA, importData);
        importIntent.putExtra(EXTRA_MESSENGER, mMessenger);

        // now import it with this service
        onHandleIntent(importIntent);

        // result is handled in ACTION_IMPORT_KEYRING
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    } else if (ACTION_CERTIFY_KEYRING.equals(action)) {
      try {

        /* Input */
        long masterKeyId = data.getLong(CERTIFY_KEY_MASTER_KEY_ID);
        long pubKeyId = data.getLong(CERTIFY_KEY_PUB_KEY_ID);
        ArrayList<String> userIds = data.getStringArrayList(CERTIFY_KEY_UIDS);

        /* Operation */
        String signaturePassphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId);
        if (signaturePassphrase == null) {
          throw new PgpGeneralException("Unable to obtain passphrase");
        }

        PgpKeyOperation keyOperation = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100));
        PGPPublicKeyRing publicRing = ProviderHelper.getPGPPublicKeyRingByKeyId(this, pubKeyId);
        PGPPublicKey publicKey = publicRing.getPublicKey(pubKeyId);
        PGPSecretKey certificationKey = PgpKeyHelper.getCertificationKey(this, masterKeyId);
        publicKey =
            keyOperation.certifyKey(certificationKey, publicKey, userIds, signaturePassphrase);
        publicRing = PGPPublicKeyRing.insertPublicKey(publicRing, publicKey);

        // store the signed key in our local cache
        PgpImportExport pgpImportExport = new PgpImportExport(this, null);
        int retval = pgpImportExport.storeKeyRingInCache(publicRing);
        if (retval != Id.return_value.ok && retval != Id.return_value.updated) {
          throw new PgpGeneralException("Failed to store signed key in local cache");
        }

        sendMessageToHandler(ApgIntentServiceHandler.MESSAGE_OKAY);
      } catch (Exception e) {
        sendErrorToHandler(e);
      }
    }
  }
  /** Creates dialog */
  @Override
  public Dialog onCreateDialog(Bundle savedInstanceState) {
    final Activity activity = getActivity();

    long secretKeyId = getArguments().getLong(ARG_SECRET_KEY_ID);
    mMessenger = getArguments().getParcelable(ARG_MESSENGER);

    AlertDialog.Builder alert = new AlertDialog.Builder(activity);

    alert.setTitle(R.string.title_authentication);

    final PGPSecretKey secretKey;

    if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) {
      secretKey = null;
      alert.setMessage(R.string.passPhraseForSymmetricEncryption);
    } else {
      // TODO: by master key id???
      secretKey =
          PGPHelper.getMasterKey(
              ProviderHelper.getPGPSecretKeyRingByMasterKeyId(activity, secretKeyId));
      // secretKey = PGPHelper.getMasterKey(PGPMain.getSecretKeyRing(secretKeyId));

      if (secretKey == null) {
        alert.setTitle(R.string.title_keyNotFound);
        alert.setMessage(getString(R.string.keyNotFound, secretKeyId));
        alert.setPositiveButton(
            android.R.string.ok,
            new OnClickListener() {
              public void onClick(DialogInterface dialog, int which) {
                dismiss();
              }
            });
        alert.setCancelable(false);
        return alert.create();
      }
      String userId = PGPHelper.getMainUserIdSafe(activity, secretKey);

      Log.d(Constants.TAG, "User id: '" + userId + "'");
      alert.setMessage(getString(R.string.passPhraseFor, userId));
    }

    LayoutInflater inflater = activity.getLayoutInflater();
    View view = inflater.inflate(R.layout.passphrase, null);
    alert.setView(view);

    mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase);

    alert.setPositiveButton(
        android.R.string.ok,
        new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int id) {
            dismiss();

            String passPhrase = mPassphraseEditText.getText().toString();
            long keyId;
            if (secretKey != null) {
              try {
                PBESecretKeyDecryptor keyDecryptor =
                    new JcePBESecretKeyDecryptorBuilder()
                        .setProvider(PGPMain.BOUNCY_CASTLE_PROVIDER_NAME)
                        .build(passPhrase.toCharArray());
                PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor);
                if (testKey == null) {
                  Toast.makeText(
                          activity, R.string.error_couldNotExtractPrivateKey, Toast.LENGTH_SHORT)
                      .show();
                  return;
                }
              } catch (PGPException e) {
                Toast.makeText(activity, R.string.wrongPassPhrase, Toast.LENGTH_SHORT).show();
                return;
              }
              keyId = secretKey.getKeyID();
            } else {
              keyId = Id.key.symmetric;
            }

            // cache the new passphrase
            Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
            PassphraseCacheService.addCachedPassphrase(activity, keyId, passPhrase);

            sendMessageToHandler(MESSAGE_OKAY);
          }
        });

    alert.setNegativeButton(
        android.R.string.cancel,
        new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int id) {
            dismiss();
          }
        });

    return alert.create();
  }