aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-03-21 19:52:10 +0100
committerVincent Breitmoser <valodim@mugenguild.com>2015-03-21 19:52:10 +0100
commit1ad3635d139ea5033b06e5cdd87a7b2eab5f2e75 (patch)
treec19b5db3ecfaa2b2bf933d22d6fde80b406a6953 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain
parent147003123fffc84b1d658f78d0a888479ce4ff35 (diff)
downloadopen-keychain-1ad3635d139ea5033b06e5cdd87a7b2eab5f2e75.tar.gz
open-keychain-1ad3635d139ea5033b06e5cdd87a7b2eab5f2e75.tar.bz2
open-keychain-1ad3635d139ea5033b06e5cdd87a7b2eab5f2e75.zip
work on ad-hoc yubikey import support
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java22
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java259
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java7
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[]{