diff options
Diffstat (limited to 'OpenKeychain/src/main/java')
5 files changed, 278 insertions, 21 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java index af9aff84a..d6c7a1ee0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java @@ -31,13 +31,18 @@ public class PromoteKeyResult extends OperationResult {      public PromoteKeyResult(Parcel source) {          super(source); -        mMasterKeyId = source.readLong(); +        mMasterKeyId = source.readInt() != 0 ? source.readLong() : null;      }      @Override      public void writeToParcel(Parcel dest, int flags) {          super.writeToParcel(dest, flags); -        dest.writeLong(mMasterKeyId); +        if (mMasterKeyId != null) { +            dest.writeInt(1); +            dest.writeLong(mMasterKeyId); +        } else { +            dest.writeInt(0); +        }      }      public static Creator<PromoteKeyResult> CREATOR = new Creator<PromoteKeyResult>() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index ed6453e9d..5a9c146f7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -487,7 +487,7 @@ public class KeychainIntentService extends IntentService implements Progressable              case ACTION_PROMOTE_KEYRING: {                  // Input -                long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID); +                long keyRingId = data.getLong(PROMOTE_MASTER_KEY_ID);                  // Operation                  PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 4ae901c6c..9919e2aab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -17,23 +17,18 @@  package org.sufficientlysecure.keychain.ui; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.IntentFilter; -import android.nfc.NfcAdapter;  import android.os.Bundle;  import android.support.v4.app.Fragment;  import android.support.v4.app.FragmentTransaction; -import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.base.BaseActivity; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;  import org.sufficientlysecure.keychain.util.Passphrase; +import java.io.IOException;  import java.util.ArrayList; -public class CreateKeyActivity extends BaseActivity { +public class CreateKeyActivity extends BaseNfcActivity {      public static final String EXTRA_NAME = "name";      public static final String EXTRA_EMAIL = "email"; @@ -86,6 +81,13 @@ public class CreateKeyActivity extends BaseActivity {      }      @Override +    protected void onNfcPerform() throws IOException { +        if (mCurrentFragment instanceof NfcListenerFragment) { +            ((NfcListenerFragment) mCurrentFragment).onNfcPerform(); +        } +    } + +    @Override      protected void onSaveInstanceState(Bundle outState) {          super.onSaveInstanceState(outState); @@ -135,4 +137,8 @@ public class CreateKeyActivity extends BaseActivity {          getSupportFragmentManager().executePendingTransactions();      } +    interface NfcListenerFragment { +        public void onNfcPerform() throws IOException; +    } +  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java index 665c68d65..483a5f4e5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java @@ -17,26 +17,77 @@  package org.sufficientlysecure.keychain.ui; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +  import android.app.Activity; +import android.app.ProgressDialog;  import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri;  import android.os.Bundle; +import android.os.Message; +import android.os.Messenger;  import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader;  import android.view.LayoutInflater;  import android.view.View;  import android.view.ViewGroup;  import android.widget.EditText; +import android.widget.TextView; +import android.widget.ViewAnimator; +import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;  import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment; +import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.Style;  import org.sufficientlysecure.keychain.ui.widget.NameEditText; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; -public class CreateKeyYubiFragment extends Fragment { +public class CreateKeyYubiFragment extends Fragment implements NfcListenerFragment, +        LoaderManager.LoaderCallbacks<Cursor> {      CreateKeyActivity mCreateKeyActivity;      NameEditText mNameEdit;      View mBackButton;      View mNextButton; +    private TextView mUnknownFingerprint; + +    public static final String ARGS_MASTER_KEY_ID = "master_key_id"; +    private byte[] mScannedFingerprint; +    private long mScannedMasterKeyId; +    private ViewAnimator mAnimator; +    private TextView mFingerprint; +    private TextView mUserId; + +    private YubiImportState mState = YubiImportState.SCAN; + +    enum YubiImportState { +        SCAN, // waiting for scan +        UNKNOWN, // scanned unknown key (ready to import) +        BAD_FINGERPRINT, // scanned key, bad fingerprint +        IMPORTED, // imported key (ready to promote) +    }      private static boolean isEditTextNotEmpty(Context context, EditText editText) {          boolean output = true; @@ -55,6 +106,16 @@ public class CreateKeyYubiFragment extends Fragment {      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {          View view = inflater.inflate(R.layout.create_yubikey_fragment, container, false); +        mAnimator = (ViewAnimator) view.findViewById(R.id.create_yubikey_animator); + +        mUnknownFingerprint = (TextView) view.findViewById(R.id.create_yubikey_unknown_fp); + +        mFingerprint = (TextView) view.findViewById(R.id.create_yubikey_fingerprint); +        mUserId = (TextView) view.findViewById(R.id.create_yubikey_user_id); + +        mBackButton = view.findViewById(R.id.create_key_back_button); +        mNextButton = view.findViewById(R.id.create_key_next_button); +          mBackButton.setOnClickListener(new View.OnClickListener() {              @Override              public void onClick(View v) { @@ -77,14 +138,200 @@ public class CreateKeyYubiFragment extends Fragment {          mCreateKeyActivity = (CreateKeyActivity) getActivity();      } +    @Override +    public void onNfcPerform() throws IOException { + +        mScannedFingerprint = mCreateKeyActivity.nfcGetFingerprint(0); +        mScannedMasterKeyId = getKeyIdFromFingerprint(mScannedFingerprint); + +        getLoaderManager().initLoader(0, null, this); + +    } + +    // These are the rows that we will retrieve. +    static final String[] UNIFIED_PROJECTION = new String[]{ +            KeychainContract.KeyRings._ID, +            KeychainContract.KeyRings.MASTER_KEY_ID, +            KeychainContract.KeyRings.USER_ID, +            KeychainContract.KeyRings.IS_REVOKED, +            KeychainContract.KeyRings.IS_EXPIRED, +            KeychainContract.KeyRings.HAS_ANY_SECRET, +            KeychainContract.KeyRings.FINGERPRINT, +    }; + +    static final int INDEX_MASTER_KEY_ID = 1; +    static final int INDEX_USER_ID = 2; +    static final int INDEX_IS_REVOKED = 3; +    static final int INDEX_IS_EXPIRED = 4; +    static final int INDEX_HAS_ANY_SECRET = 5; +    static final int INDEX_FINGERPRINT = 6; + +    @Override +    public Loader<Cursor> onCreateLoader(int id, Bundle args) { +        Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri( +                KeyRings.buildUnifiedKeyRingUri(mScannedMasterKeyId) +        ); +        return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); +    } + +    @Override +    public void onLoadFinished(Loader<Cursor> loader, Cursor data) { +        if (data.moveToFirst()) { + +            byte[] fingerprint = data.getBlob(INDEX_FINGERPRINT); +            if (!Arrays.equals(fingerprint, mScannedFingerprint)) { +                mState = YubiImportState.BAD_FINGERPRINT; +                Notify.create(getActivity(), "Fingerprint mismatch!", Style.ERROR); +                return; +            } + +            showKey(data); + +        } else { +            showUnknownKey(); +        } +    } + +    public void showUnknownKey() { +        String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); +        mUnknownFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); + +        mAnimator.setDisplayedChild(1); +        mState = YubiImportState.UNKNOWN; +    } + +    public void showKey(Cursor data) { +        String userId = data.getString(INDEX_USER_ID); +        boolean hasSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; + +        String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); +        mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); + +        mUserId.setText(userId); + +        mAnimator.setDisplayedChild(2); +        mState = YubiImportState.IMPORTED; +    } + +      private void nextClicked() { -        if (isEditTextNotEmpty(getActivity(), mNameEdit)) { -            // save state -            mCreateKeyActivity.mName = mNameEdit.getText().toString(); -            CreateKeyEmailFragment frag = CreateKeyEmailFragment.newInstance(); -            mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); +        switch (mState) { +            case UNKNOWN: +                importKey(); +                break; +            case IMPORTED: +                promoteKey(); +                break;          } + +    } + +    public void promoteKey() { + +        // Message is received after decrypting is done in KeychainIntentService +        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity()) { +            public void handleMessage(Message message) { +                // handle messages by standard KeychainIntentServiceHandler first +                super.handleMessage(message); + +                if (message.arg1 == MessageStatus.OKAY.ordinal()) { +                    // get returned data bundle +                    Bundle returnData = message.getData(); + +                    PromoteKeyResult result = +                            returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); + +                    result.createNotify(getActivity()).show(); +                } + +            } +        }; + +        // Send all information needed to service to decrypt in other thread +        Intent intent = new Intent(getActivity(), KeychainIntentService.class); + +        // fill values for this action + +        intent.setAction(KeychainIntentService.ACTION_PROMOTE_KEYRING); + +        Bundle data = new Bundle(); +        data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, mScannedMasterKeyId); +        intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + +        // Create a new Messenger for the communication back +        Messenger messenger = new Messenger(saveHandler); +        intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + +        // start service with intent +        getActivity().startService(intent); + +    } + +    public void importKey() { + +        // Message is received after decrypting is done in KeychainIntentService +        KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity()) { +            public void handleMessage(Message message) { +                // handle messages by standard KeychainIntentServiceHandler first +                super.handleMessage(message); + +                if (message.arg1 == MessageStatus.OKAY.ordinal()) { +                    // get returned data bundle +                    Bundle returnData = message.getData(); + +                    ImportKeyResult result = +                            returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); + +                    result.createNotify(getActivity()).show(); +                } + +            } +        }; + +        // Send all information needed to service to decrypt in other thread +        Intent intent = new Intent(getActivity(), KeychainIntentService.class); + +        // fill values for this action +        Bundle data = new Bundle(); + +        intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); + +        String hexFp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); +        ArrayList<ParcelableKeyRing> keyList = new ArrayList<>(); +        keyList.add(new ParcelableKeyRing(hexFp, null, null)); +        data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, keyList); + +        { +            Preferences prefs = Preferences.getPreferences(getActivity()); +            Preferences.CloudSearchPrefs cloudPrefs = +                    new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); +            data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); +        } + +        intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + +        // Create a new Messenger for the communication back +        Messenger messenger = new Messenger(saveHandler); +        intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + +        // start service with intent +        getActivity().startService(intent); + +    } + + +    @Override +    public void onLoaderReset(Loader<Cursor> loader) { + +    } + +    static long getKeyIdFromFingerprint(byte[] fingerprint) { +        ByteBuffer buf = ByteBuffer.wrap(fingerprint); +        // skip first 12 bytes of the fingerprint +        buf.position(12); +        // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) +        return buf.getLong();      }  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 0a7b7611b..ca1d79155 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -18,7 +18,6 @@ import org.spongycastle.util.encoders.Hex;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;  import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -import org.sufficientlysecure.keychain.ui.NfcOperationActivity;  import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;  import org.sufficientlysecure.keychain.util.Iso7816TLV;  import org.sufficientlysecure.keychain.util.Log; @@ -72,7 +71,7 @@ public abstract class BaseNfcActivity extends BaseActivity {       */      public void onPause() {          super.onPause(); -        Log.d(Constants.TAG, "NfcOperationActivity.onPause"); +        Log.d(Constants.TAG, "BaseNfcActivity.onPause");          disableNfcForegroundDispatch();      } @@ -83,7 +82,7 @@ public abstract class BaseNfcActivity extends BaseActivity {       */      public void onResume() {          super.onResume(); -        Log.d(Constants.TAG, "NfcOperationActivity.onResume"); +        Log.d(Constants.TAG, "BaseNfcActivity.onResume");          enableNfcForegroundDispatch();      } @@ -397,7 +396,7 @@ public abstract class BaseNfcActivity extends BaseActivity {       */      public void enableNfcForegroundDispatch() {          mNfcAdapter = NfcAdapter.getDefaultAdapter(this); -        Intent nfcI = new Intent(this, NfcOperationActivity.class) +        Intent nfcI = new Intent(this, getClass())                  .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);          PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT);          IntentFilter[] writeTagFilters = new IntentFilter[]{  | 
