diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-01-06 14:52:07 +0100 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-01-06 14:52:07 +0100 |
commit | e34ad18ed26166751f6897169056044c2d19ce67 (patch) | |
tree | 546a51fe1be350e9aeb8899903df82ff251da532 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain | |
parent | ccde6add70ea9b5c559910d42dfb2e0bf79f5989 (diff) | |
download | open-keychain-e34ad18ed26166751f6897169056044c2d19ce67.tar.gz open-keychain-e34ad18ed26166751f6897169056044c2d19ce67.tar.bz2 open-keychain-e34ad18ed26166751f6897169056044c2d19ce67.zip |
Passphrase wizard tests
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain')
3 files changed, 628 insertions, 22 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index a965d4819..fa7460915 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -98,6 +98,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { return GNU_DUMMY; case 2: return PASSPHRASE; +// return PATTERN; case 3: return PASSPHRASE_EMPTY; case 4: diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 7acd62c72..2c4834e02 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -382,29 +382,32 @@ public class EditKeyFragment extends LoaderFragment implements } private void changePassphrase() { + Intent passIntent = new Intent(getActivity(), PassphraseWizardActivity.class); + passIntent.setAction(PassphraseWizardActivity.CREATE_METHOD); + startActivityForResult(passIntent, 12); // Message is received after passphrase is cached - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) { - Bundle data = message.getData(); - - // cache new returned passphrase! - mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel( - data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), - null - ); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance( - messenger, mCurrentPassphrase, R.string.title_change_passphrase); - - setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog"); +// Handler returnHandler = new Handler() { +// @Override +// public void handleMessage(Message message) { +// if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) { +// Bundle data = message.getData(); +// +// // cache new returned passphrase! +// mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel( +// data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), +// null +// ); +// } +// } +// }; +// +// // Create a new Messenger for the communication back +// Messenger messenger = new Messenger(returnHandler); +// +// SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance( +// messenger, mCurrentPassphrase, R.string.title_change_passphrase); +// +// setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog"); } private void editUserId(final int position) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java new file mode 100644 index 000000000..93778fd0c --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java @@ -0,0 +1,602 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + +import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.app.PendingIntent; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.nfc.FormatException; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.Ndef; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.haibison.android.lockpattern.LockPatternFragment; +import com.haibison.android.lockpattern.LockPatternFragmentOld; +import com.haibison.android.lockpattern.widget.LockPatternView; + +import org.sufficientlysecure.keychain.R; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.List; + +@TargetApi(Build.VERSION_CODES.HONEYCOMB) +public class PassphraseWizardActivity extends FragmentActivity implements LockPatternView.OnPatternListener { + //create or authenticate + public String selectedAction; + //for lockpattern + public static char[] pattern; + private static String passphrase = ""; + //nfc string + private static byte[] output = new byte[8]; + + public static final String CREATE_METHOD = "create"; + public static final String AUTHENTICATION = "authenticate"; + + NfcAdapter adapter; + PendingIntent pendingIntent; + IntentFilter writeTagFilters[]; + boolean writeMode; + Tag myTag; + boolean writeNFC = false; + boolean readNFC = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getActionBar() != null) { + getActionBar().setTitle(R.string.unlock_method); + } + + selectedAction = getIntent().getAction(); + if (savedInstanceState == null) { + SelectMethods selectMethods = new SelectMethods(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.fragmentContainer, selectMethods).commit(); + } + setContentView(R.layout.passphrase_wizard); + + adapter = NfcAdapter.getDefaultAdapter(this); + if (adapter != null) { + pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, PassphraseWizardActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); + IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); + tagDetected.addCategory(Intent.CATEGORY_DEFAULT); + writeTagFilters = new IntentFilter[]{tagDetected}; + } + } + + public void noPassphrase(View view) { + passphrase = ""; + Toast.makeText(this, R.string.no_passphrase_set, Toast.LENGTH_SHORT).show(); + this.finish(); + } + + public void passphrase(View view) { + Passphrase passphrase = new Passphrase(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragmentContainer, passphrase).addToBackStack(null).commit(); + } + + public void startLockpattern(View view) { + if (getActionBar() != null) { + getActionBar().setTitle(R.string.draw_lockpattern); + } +// LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction); + LockPatternFragment lpf = LockPatternFragment.newInstance("asd"); + + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); + } + + public void cancel(View view) { + this.finish(); + } + + public void savePassphrase(View view) { + EditText passphrase = (EditText) findViewById(R.id.passphrase); + passphrase.setError(null); + String pw = passphrase.getText().toString(); + //check and save passphrase + if (selectedAction.equals(CREATE_METHOD)) { + EditText passphraseAgain = (EditText) findViewById(R.id.passphraseAgain); + passphraseAgain.setError(null); + String pwAgain = passphraseAgain.getText().toString(); + + if (!TextUtils.isEmpty(pw)) { + if (!TextUtils.isEmpty(pwAgain)) { + if (pw.equals(pwAgain)) { + PassphraseWizardActivity.passphrase = pw; + Toast.makeText(this, getString(R.string.passphrase_saved), Toast.LENGTH_SHORT).show(); + this.finish(); + } else { + passphrase.setError(getString(R.string.passphrase_invalid)); + passphrase.requestFocus(); + } + } else { + passphraseAgain.setError(getString(R.string.missing_passphrase)); + passphraseAgain.requestFocus(); + } + } else { + passphrase.setError(getString(R.string.missing_passphrase)); + passphrase.requestFocus(); + } + } + //check for right passphrase + if (selectedAction.equals(AUTHENTICATION)) { + if (pw.equals(PassphraseWizardActivity.passphrase)) { + Toast.makeText(this, getString(R.string.unlocked), Toast.LENGTH_SHORT).show(); + this.finish(); + } else { + passphrase.setError(getString(R.string.passphrase_invalid)); + passphrase.requestFocus(); + } + } + } + + public void NFC(View view) { + if (adapter != null) { + if (getActionBar() != null) { + getActionBar().setTitle(R.string.nfc_title); + } + NFCFragment nfc = new NFCFragment(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragmentContainer, nfc).addToBackStack(null).commit(); + + //if you want to create a new method or just authenticate + if (CREATE_METHOD.equals(selectedAction)) { + writeNFC = true; + } else if (AUTHENTICATION.equals(selectedAction)) { + readNFC = true; + } + + if (!adapter.isEnabled()) { + showAlertDialog(getString(R.string.enable_nfc), true); + } + } else { + showAlertDialog(getString(R.string.no_nfc_support), false); + } + } + + @Override + protected void onNewIntent(Intent intent) { + if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { + myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + + if (writeNFC && CREATE_METHOD.equals(selectedAction)) { + //write new password on NFC tag + try { + if (myTag != null) { + write(myTag); + writeNFC = false; //just write once + Toast.makeText(this, R.string.nfc_write_succesful, Toast.LENGTH_SHORT).show(); + //advance to lockpattern + LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); + } + } catch (IOException e) { + e.printStackTrace(); + } catch (FormatException e) { + e.printStackTrace(); + } + + } else if (readNFC && AUTHENTICATION.equals(selectedAction)) { + //read pw from NFC tag + try { + if (myTag != null) { + //if tag detected, read tag + String pwtag = read(myTag); + if (output != null && pwtag.equals(output.toString())) { + + //passwort matches, go to next view + Toast.makeText(this, R.string.passphrases_match + "!", Toast.LENGTH_SHORT).show(); + + LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); + readNFC = false; //just once + } else { + //passwort doesnt match + TextView nfc = (TextView) findViewById(R.id.nfcText); + nfc.setText(R.string.nfc_wrong_tag); + } + } + } catch (IOException e) { + e.printStackTrace(); + } catch (FormatException e) { + e.printStackTrace(); + } + } + } + } + + private void write(Tag tag) throws IOException, FormatException { + //generate new random key and write them on the tag + SecureRandom sr = new SecureRandom(); + sr.nextBytes(output); + NdefRecord[] records = {createRecord(output.toString())}; + NdefMessage message = new NdefMessage(records); + Ndef ndef = Ndef.get(tag); + ndef.connect(); + ndef.writeNdefMessage(message); + ndef.close(); + } + + private String read(Tag tag) throws IOException, FormatException { + //read string from tag + String password = null; + Ndef ndef = Ndef.get(tag); + ndef.connect(); + NdefMessage ndefMessage = ndef.getCachedNdefMessage(); + + NdefRecord[] records = ndefMessage.getRecords(); + for (NdefRecord ndefRecord : records) { + if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) { + try { + password = readText(ndefRecord); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + } + ndef.close(); + return password; + } + + private String readText(NdefRecord record) throws UnsupportedEncodingException { + //low-level method for reading nfc + byte[] payload = record.getPayload(); + String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; + int languageCodeLength = payload[0] & 0063; + return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding); + } + + private NdefRecord createRecord(String text) throws UnsupportedEncodingException { + //low-level method for writing nfc + String lang = "en"; + byte[] textBytes = text.getBytes(); + byte[] langBytes = lang.getBytes("US-ASCII"); + int langLength = langBytes.length; + int textLength = textBytes.length; + byte[] payload = new byte[1 + langLength + textLength]; + + // set status byte (see NDEF spec for actual bits) + payload[0] = (byte) langLength; + // copy langbytes and textbytes into payload + System.arraycopy(langBytes, 0, payload, 1, langLength); + System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength); + return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload); + } + + public void showAlertDialog(String message, boolean nfc) { + //This method shows an AlertDialog + AlertDialog.Builder alert = new AlertDialog.Builder(this); + alert.setTitle("Information").setMessage(message).setPositiveButton("Ok", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + } + } + ); + if (nfc) { + + alert.setNeutralButton(R.string.nfc_settings, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialogInterface, int i) { + startActivity(new Intent(Settings.ACTION_NFC_SETTINGS)); + } + } + ); + } + alert.show(); + } + + @Override + public void onPause() { + //pause this app and free nfc intent + super.onPause(); + if (adapter != null) { + WriteModeOff(); + } + } + + @Override + public void onResume() { + //resume this app and get nfc intent + super.onResume(); + if (adapter != null) { + WriteModeOn(); + } + } + + private void WriteModeOn() { + //enable nfc for this view + writeMode = true; + adapter.enableForegroundDispatch(this, pendingIntent, writeTagFilters, null); + } + + private void WriteModeOff() { + //disable nfc for this view + writeMode = false; + adapter.disableForegroundDispatch(this); + } + + @Override + public void onPatternStart() { + + } + + @Override + public void onPatternCleared() { + + } + + @Override + public void onPatternCellAdded(List<LockPatternView.Cell> pattern) { + + } + + @Override + public void onPatternDetected(List<LockPatternView.Cell> pattern) { + + } + + public static class SelectMethods extends Fragment { +// private OnFragmentInteractionListener mListener; + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + */ + public SelectMethods() { + + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public void onResume() { + super.onResume(); + if (getActivity().getActionBar() != null) { + getActivity().getActionBar().setTitle(R.string.unlock_method); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.passphrase_wizard_fragment_select_methods, container, false); + } + +// @Override +// public void onAttach(Activity activity) { +// super.onAttach(activity); +// try { +// mListener = (OnFragmentInteractionListener) activity; +// } catch (ClassCastException e) { +// throw new ClassCastException(activity.toString() +// + " must implement OnFragmentInteractionListener"); +// } +// } +// +// @Override +// public void onDetach() { +// super.onDetach(); +// mListener = null; +// } + + /** + * This interface must be implemented by activities that contain this + * fragment to allow an interaction in this fragment to be communicated + * to the activity and potentially other fragments contained in that + * activity. + * <p/> + * See the Android Training lesson <a href= + * "http://developer.android.com/training/basics/fragments/communicating.html" + * >Communicating with Other Fragments</a> for more information. + */ +// public static interface OnFragmentInteractionListener { +// public void onFragmentInteraction(Uri uri); +// } + + } + + + // /** +// * A simple {@link android.support.v4.app.Fragment} subclass. +// * Activities that contain this fragment must implement the +// * {@link com.haibison.android.lockpattern.Passphrase.OnFragmentInteractionListener} interface +// * to handle interaction events. +// */ + public static class Passphrase extends Fragment { + +// private OnFragmentInteractionListener mListener; + + public Passphrase() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View view = inflater.inflate(R.layout.passphrase_wizard_fragment_passphrase, container, false); + EditText passphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain); + TextView passphraseText = (TextView) view.findViewById(R.id.passphraseText); + TextView passphraseTextAgain = (TextView) view.findViewById(R.id.passphraseTextAgain); + String selectedAction = getActivity().getIntent().getAction(); + if (selectedAction.equals(AUTHENTICATION)) { + passphraseAgain.setVisibility(View.GONE); + passphraseTextAgain.setVisibility(View.GONE); + passphraseText.setText(R.string.enter_passphrase); +// getActivity().getActionBar().setTitle(R.string.enter_passphrase); + } else if (selectedAction.equals(CREATE_METHOD)) { + passphraseAgain.setVisibility(View.VISIBLE); + passphraseTextAgain.setVisibility(View.VISIBLE); + passphraseText.setText(R.string.passphrase); +// getActivity().getActionBar().setTitle(R.string.set_passphrase); + } + return view; + } + +// @Override +// public void onAttach(Activity activity) { +// super.onAttach(activity); +// try { +// mListener = (OnFragmentInteractionListener) activity; +// } catch (ClassCastException e) { +// throw new ClassCastException(activity.toString() +// + " must implement OnFragmentInteractionListener"); +// } +// } +// +// @Override +// public void onDetach() { +// super.onDetach(); +// mListener = null; +// } + +// /** +// * This interface must be implemented by activities that contain this +// * fragment to allow an interaction in this fragment to be communicated +// * to the activity and potentially other fragments contained in that +// * activity. +// * <p/> +// * See the Android Training lesson <a href= +// * "http://developer.android.com/training/basics/fragments/communicating.html" +// * >Communicating with Other Fragments</a> for more information. +// */ +// public interface OnFragmentInteractionListener { +// public void onFragmentInteraction(Uri uri); +// } + } + + + /** + * A simple {@link android.support.v4.app.Fragment} subclass. + * Activities that contain this fragment must implement the + * interface + * to handle interaction events. + * Use the method to + * create an instance of this fragment. + */ + public static class NFCFragment extends Fragment { + // TODO: Rename parameter arguments, choose names that match + // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER + private static final String ARG_PARAM1 = "param1"; + private static final String ARG_PARAM2 = "param2"; + + // TODO: Rename and change types of parameters + private String mParam1; + private String mParam2; + +// private OnFragmentInteractionListener mListener; + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @param param1 Parameter 1. + * @param param2 Parameter 2. + * @return A new instance of fragment SelectMethods. + */ + // TODO: Rename and change types and number of parameters + public static NFCFragment newInstance(String param1, String param2) { + NFCFragment fragment = new NFCFragment(); + Bundle args = new Bundle(); + args.putString(ARG_PARAM1, param1); + args.putString(ARG_PARAM2, param2); + fragment.setArguments(args); + return fragment; + } + + public NFCFragment() { + // Required empty public constructor + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mParam1 = getArguments().getString(ARG_PARAM1); + mParam2 = getArguments().getString(ARG_PARAM2); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.passphrase_wizard_fragment_nfc, container, false); + } + +// // TODO: Rename method, update argument and hook method into UI event +// public void onButtonPressed(Uri uri) { +// if (mListener != null) { +// mListener.onFragmentInteraction(uri); +// } +// } + +// @Override +// public void onAttach(Activity activity) { +// super.onAttach(activity); +// try { +// mListener = (OnFragmentInteractionListener) activity; +// } catch (ClassCastException e) { +// throw new ClassCastException(activity.toString() +// + " must implement OnFragmentInteractionListener"); +// } +// } + + +// @Override +// public void onDetach() { +// super.onDetach(); +// mListener = null; +// } + } + +} |