@Override
  public CertifyActionsParcel createOperationInput() {

    // Bail out if there is not at least one user id selected
    ArrayList<CertifyAction> certifyActions = mUserIdsAdapter.getSelectedCertifyActions();
    if (certifyActions.isEmpty()) {
      Notify.create(getActivity(), "No identities selected!", Notify.Style.ERROR).show();
      return null;
    }

    long selectedKeyId = mCertifyKeySpinner.getSelectedKeyId();

    // fill values for this action
    CertifyActionsParcel actionsParcel = new CertifyActionsParcel(selectedKeyId);
    actionsParcel.mCertifyActions.addAll(certifyActions);

    if (mUploadKeyCheckbox.isChecked()) {
      actionsParcel.keyServerUri =
          Preferences.getPreferences(getActivity()).getPreferredKeyserver();
    }

    // cached for next cryptoOperation loop
    cacheActionsParcel(actionsParcel);

    return actionsParcel;
  }
  @Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == REQUEST_CODE_IMPORT_KEY) {
      if (resultCode == Activity.RESULT_OK) {
        if (mCreateKeyActivity.mFirstTime) {
          Preferences prefs = Preferences.getPreferences(mCreateKeyActivity);
          prefs.setFirstTime(false);
          mCreateKeyActivity.finish();
        } else {
          // just finish activity and return data
          mCreateKeyActivity.setResult(Activity.RESULT_OK, data);
          mCreateKeyActivity.finish();
        }
      }
    } else {
      Log.e(Constants.TAG, "No valid request code!");
    }
  }
Example #3
0
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
      mMessage = getArguments().getString(ARG_TEXT);
    }

    Preferences prefs = Preferences.getPreferences(getActivity());

    Bundle args = savedInstanceState == null ? getArguments() : savedInstanceState;

    mUseCompression = args.getBoolean(ARG_USE_COMPRESSION, true);
    if (args.containsKey(ARG_USE_COMPRESSION)) {
      mUseCompression = args.getBoolean(ARG_USE_COMPRESSION, true);
    } else {
      mUseCompression = prefs.getTextUseCompression();
    }

    setHasOptionsMenu(true);
  }
    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
      final Activity activity = getActivity();

      ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);

      mRequiredInput = getArguments().getParcelable(EXTRA_REQUIRED_INPUT);

      CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);

      // No title, see http://www.google.com/design/spec/components/dialogs.html#dialogs-alerts
      // alert.setTitle()

      if (mRequiredInput.mType == RequiredInputType.BACKUP_CODE) {
        LayoutInflater inflater = LayoutInflater.from(theme);
        View view = inflater.inflate(R.layout.passphrase_dialog_backup_code, null);
        alert.setView(view);

        mBackupCodeEditText = new EditText[4];
        mBackupCodeEditText[0] = (EditText) view.findViewById(R.id.backup_code_1);
        mBackupCodeEditText[1] = (EditText) view.findViewById(R.id.backup_code_2);
        mBackupCodeEditText[2] = (EditText) view.findViewById(R.id.backup_code_3);
        mBackupCodeEditText[3] = (EditText) view.findViewById(R.id.backup_code_4);
        setupEditTextFocusNext(mBackupCodeEditText);

        AlertDialog dialog = alert.create();
        dialog.setButton(
            DialogInterface.BUTTON_POSITIVE,
            activity.getString(R.string.btn_unlock),
            (DialogInterface.OnClickListener) null);
        return dialog;
      }

      long subKeyId = mRequiredInput.getSubKeyId();

      LayoutInflater inflater = LayoutInflater.from(theme);
      mLayout = (ViewAnimator) inflater.inflate(R.layout.passphrase_dialog, null);
      alert.setView(mLayout);

      mPassphraseText = (TextView) mLayout.findViewById(R.id.passphrase_text);
      mPassphraseEditText = (EditText) mLayout.findViewById(R.id.passphrase_passphrase);

      View vTimeToLiveLayout = mLayout.findViewById(R.id.remember_layout);
      vTimeToLiveLayout.setVisibility(mRequiredInput.mSkipCaching ? View.GONE : View.VISIBLE);

      mTimeToLiveSpinner = (CacheTTLSpinner) mLayout.findViewById(R.id.ttl_spinner);

      alert.setNegativeButton(
          android.R.string.cancel,
          new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int id) {
              dialog.cancel();
            }
          });

      String userId;
      CanonicalizedSecretKey.SecretKeyType keyType =
          CanonicalizedSecretKey.SecretKeyType.PASSPHRASE;

      String message;
      String hint;
      if (mRequiredInput.mType == RequiredInputType.PASSPHRASE_SYMMETRIC) {
        message = getString(R.string.passphrase_for_symmetric_encryption);
        hint = getString(R.string.label_passphrase);
      } else {
        try {
          ProviderHelper helper = new ProviderHelper(activity);
          mSecretRing =
              helper.getCanonicalizedSecretKeyRing(
                  KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId));
          // yes the inner try/catch block is necessary, otherwise the final variable
          // above can't be statically verified to have been set in all cases because
          // the catch clause doesn't return.
          try {
            String mainUserId = mSecretRing.getPrimaryUserIdWithFallback();
            KeyRing.UserId mainUserIdSplit = KeyRing.splitUserId(mainUserId);
            if (mainUserIdSplit.name != null) {
              userId = mainUserIdSplit.name;
            } else {
              userId = getString(R.string.user_id_no_name);
            }
          } catch (PgpKeyNotFoundException e) {
            userId = null;
          }

          keyType = mSecretRing.getSecretKey(subKeyId).getSecretKeyType();
          switch (keyType) {
            case PASSPHRASE:
              message = getString(R.string.passphrase_for, userId);
              hint = getString(R.string.label_passphrase);
              break;
            case PIN:
              message = getString(R.string.pin_for, userId);
              hint = getString(R.string.label_pin);
              break;
            case DIVERT_TO_CARD:
              message = getString(R.string.yubikey_pin_for, userId);
              hint = getString(R.string.label_pin);
              break;
              // special case: empty passphrase just returns the empty passphrase
            case PASSPHRASE_EMPTY:
              finishCaching(new Passphrase(""));
            default:
              throw new AssertionError("Unhandled SecretKeyType (should not happen)");
          }

        } catch (ProviderHelper.NotFoundException e) {
          alert.setTitle(R.string.title_key_not_found);
          alert.setMessage(getString(R.string.key_not_found, mRequiredInput.getSubKeyId()));
          alert.setPositiveButton(
              android.R.string.ok,
              new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                  dismiss();
                }
              });
          alert.setCancelable(false);
          return alert.create();
        }
      }

      mPassphraseText.setText(message);
      mPassphraseEditText.setHint(hint);

      // Hack to open keyboard.
      // This is the only method that I found to work across all Android versions
      // http://turbomanage.wordpress.com/2012/05/02/show-soft-keyboard-automatically-when-edittext-receives-focus/
      // Notes: * onCreateView can't be used because we want to add buttons to the dialog
      //        * opening in onActivityCreated does not work on Android 4.4
      mPassphraseEditText.setOnFocusChangeListener(
          new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
              mPassphraseEditText.post(
                  new Runnable() {
                    @Override
                    public void run() {
                      if (getActivity() == null || mPassphraseEditText == null) {
                        return;
                      }
                      InputMethodManager imm =
                          (InputMethodManager)
                              getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                      imm.showSoftInput(mPassphraseEditText, InputMethodManager.SHOW_IMPLICIT);
                    }
                  });
            }
          });
      mPassphraseEditText.requestFocus();

      mPassphraseEditText.setImeActionLabel(
          getString(android.R.string.ok), EditorInfo.IME_ACTION_DONE);
      mPassphraseEditText.setOnEditorActionListener(this);

      if ((keyType == CanonicalizedSecretKey.SecretKeyType.DIVERT_TO_CARD
              && Preferences.getPreferences(activity).useNumKeypadForYubiKeyPin())
          || keyType == CanonicalizedSecretKey.SecretKeyType.PIN) {
        mPassphraseEditText.setInputType(InputType.TYPE_CLASS_NUMBER);
        mPassphraseEditText.setTransformationMethod(PasswordTransformationMethod.getInstance());
      } else {
        mPassphraseEditText.setRawInputType(
            InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
      }

      mPassphraseEditText.setTransformationMethod(PasswordTransformationMethod.getInstance());

      AlertDialog dialog = alert.create();
      dialog.setButton(
          DialogInterface.BUTTON_POSITIVE,
          activity.getString(R.string.btn_unlock),
          (DialogInterface.OnClickListener) null);

      return dialog;
    }
  /** Executed when service is started by intent */
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(Constants.TAG, "PassphraseCacheService.onStartCommand()");

    if (intent == null || intent.getAction() == null) {
      updateService();
      return START_STICKY;
    }

    String action = intent.getAction();
    switch (action) {
      case ACTION_PASSPHRASE_CACHE_ADD:
        {
          long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
          long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1);
          long timeoutTtl = intent.getIntExtra(EXTRA_TTL, DEFAULT_TTL);

          Passphrase passphrase = intent.getParcelableExtra(EXTRA_PASSPHRASE);
          String primaryUserID = intent.getStringExtra(EXTRA_USER_ID);

          Log.d(
              Constants.TAG,
              "PassphraseCacheService: Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with masterkeyId: "
                  + masterKeyId
                  + ", subKeyId: "
                  + subKeyId
                  + ", ttl: "
                  + timeoutTtl
                  + ", usrId: "
                  + primaryUserID);

          // if we don't cache by specific subkey id, or the requested subkey is the master key,
          // just add master key id to the cache, otherwise, add this specific subkey to the cache
          long referenceKeyId =
              Preferences.getPreferences(mContext).getPassphraseCacheSubs()
                  ? subKeyId
                  : masterKeyId;

          CachedPassphrase cachedPassphrase;
          if (timeoutTtl == 0L) {
            cachedPassphrase = CachedPassphrase.getPassphraseLock(passphrase, primaryUserID);
          } else if (timeoutTtl >= Integer.MAX_VALUE) {
            cachedPassphrase = CachedPassphrase.getPassphraseNoTimeout(passphrase, primaryUserID);
          } else {
            cachedPassphrase =
                CachedPassphrase.getPassphraseTtlTimeout(passphrase, primaryUserID, timeoutTtl);

            long triggerTime = new Date().getTime() + (timeoutTtl * 1000);
            // register new alarm with keyId for this passphrase
            AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
            am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, referenceKeyId));
          }

          mPassphraseCache.put(referenceKeyId, cachedPassphrase);

          break;
        }
      case ACTION_PASSPHRASE_CACHE_GET:
        {
          long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, Constants.key.symmetric);
          long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, Constants.key.symmetric);
          Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);

          Message msg = Message.obtain();
          try {
            // If only one of these is symmetric, error out!
            if (masterKeyId == Constants.key.symmetric ^ subKeyId == Constants.key.symmetric) {
              Log.e(
                  Constants.TAG,
                  "PassphraseCacheService: Bad request, missing masterKeyId or subKeyId!");
              msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
            } else {
              Passphrase passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId);
              msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY;
              Bundle bundle = new Bundle();
              bundle.putParcelable(EXTRA_PASSPHRASE, passphrase);
              msg.setData(bundle);
            }
          } catch (ProviderHelper.NotFoundException e) {
            Log.e(
                Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
            msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
          }

          try {
            messenger.send(msg);
          } catch (RemoteException e) {
            Log.e(Constants.TAG, "PassphraseCacheService: Sending message failed", e);
          }
          break;
        }
      case ACTION_PASSPHRASE_CACHE_CLEAR:
        {
          AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);

          if (intent.hasExtra(EXTRA_SUBKEY_ID) && intent.hasExtra(EXTRA_KEY_ID)) {

            long referenceKeyId;
            if (Preferences.getPreferences(mContext).getPassphraseCacheSubs()) {
              referenceKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, 0L);
            } else {
              referenceKeyId = intent.getLongExtra(EXTRA_KEY_ID, 0L);
            }
            // Stop specific ttl alarm and
            am.cancel(buildIntent(this, referenceKeyId));
            mPassphraseCache.delete(referenceKeyId);

          } else {

            // Stop all ttl alarms
            for (int i = 0; i < mPassphraseCache.size(); i++) {
              CachedPassphrase cachedPassphrase = mPassphraseCache.valueAt(i);
              if (cachedPassphrase.mTimeoutMode == TimeoutMode.TTL) {
                am.cancel(buildIntent(this, mPassphraseCache.keyAt(i)));
              }
            }
            mPassphraseCache.clear();
          }
          break;
        }
      default:
        {
          Log.e(Constants.TAG, "PassphraseCacheService: Intent or Intent Action not supported!");
          break;
        }
    }

    updateService();

    return START_STICKY;
  }
  /** Internal implementation to get cached passphrase. */
  private Passphrase getCachedPassphraseImpl(long masterKeyId, long subKeyId)
      throws ProviderHelper.NotFoundException {
    // on "none" key, just do nothing
    if (masterKeyId == Constants.key.none) {
      return null;
    }

    // passphrase for symmetric encryption?
    if (masterKeyId == Constants.key.symmetric) {
      Log.d(
          Constants.TAG,
          "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
      CachedPassphrase cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric);
      if (cachedPassphrase == null) {
        return null;
      }
      return cachedPassphrase.mPassphrase;
    }

    // try to get master key id which is used as an identifier for cached passphrases
    Log.d(
        Constants.TAG,
        "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId "
            + masterKeyId
            + ", subKeyId "
            + subKeyId);

    // get the type of key (from the database)
    CachedPublicKeyRing keyRing = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId);
    SecretKeyType keyType = keyRing.getSecretKeyType(subKeyId);

    switch (keyType) {
      case PASSPHRASE_EMPTY:
        return new Passphrase("");
      case UNAVAILABLE:
        throw new ProviderHelper.NotFoundException("secret key for this subkey is not available");
      case GNU_DUMMY:
        throw new ProviderHelper.NotFoundException(
            "secret key for stripped subkey is not available");
    }

    // get cached passphrase
    CachedPassphrase cachedPassphrase = mPassphraseCache.get(subKeyId);
    if (cachedPassphrase == null) {

      // If we cache strictly by subkey, exit early
      if (Preferences.getPreferences(mContext).getPassphraseCacheSubs()) {
        Log.d(
            Constants.TAG,
            "PassphraseCacheService: specific subkey passphrase not (yet) cached, returning null");
        // not really an error, just means the passphrase is not cached but not empty either
        return null;
      }

      if (subKeyId == masterKeyId) {
        Log.d(
            Constants.TAG,
            "PassphraseCacheService: masterkey passphrase not (yet) cached, returning null");
        // not really an error, just means the passphrase is not cached but not empty either
        return null;
      }

      cachedPassphrase = mPassphraseCache.get(masterKeyId);
      // If we cache strictly by subkey, exit early
      if (cachedPassphrase == null) {
        Log.d(
            Constants.TAG,
            "PassphraseCacheService: keyring passphrase not (yet) cached, returning null");
        // not really an error, just means the passphrase is not cached but not empty either
        return null;
      }
    }

    return cachedPassphrase.mPassphrase;
  }