diff options
Diffstat (limited to 'app/src/main/java/se/leap')
4 files changed, 255 insertions, 25 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index 3c17ebb8..6f18b79a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -21,6 +21,7 @@ import org.json.JSONObject; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver; +import se.leap.bitmaskclient.SignUpDialog; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; @@ -50,7 +51,7 @@ import android.widget.Toast; * @author Sean Leonard <meanderingcode@aetherislands.net> * @author parmegv */ -public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver { +public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, SignUpDialog.SignUpDialogInterface, Receiver { protected static final int CONFIGURE_LEAP = 0; protected static final int SWITCH_PROVIDER = 1; @@ -204,6 +205,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf menu.findItem(R.id.login_button).setVisible(true); menu.findItem(R.id.logout_button).setVisible(false); } + menu.findItem(R.id.signup_button).setVisible(true); } } catch (JSONException e) { // TODO Auto-generated catch block @@ -243,6 +245,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf case R.id.logout_button: logOut(); return true; + case R.id.signup_button: + signUpDialog(((ViewGroup)findViewById(android.R.id.content)).getChildAt(0), Bundle.EMPTY); + return true; default: return super.onOptionsItemSelected(item); } @@ -286,6 +291,15 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf EipServiceFragment eipFragment = (EipServiceFragment) getFragmentManager().findFragmentByTag(EipServiceFragment.TAG); eipFragment.checkEipSwitch(false); } + + public void cancelLoginOrSignup() { + if(mProgressBar == null) mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); + if(mProgressBar != null) { + mProgressBar.setVisibility(ProgressBar.GONE); + if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus); + if(eipStatus != null) eipStatus.setText(""); + } + } /** * Asks ProviderAPI to log out. @@ -340,6 +354,58 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf newFragment.show(fragment_transaction, LogInDialog.TAG); } + @Override + public void signUp(String username, String password) { + mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); + eipStatus = (TextView) findViewById(R.id.eipStatus); + + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle parameters = new Bundle(); + parameters.putString(SignUpDialog.USERNAME, username); + parameters.putString(SignUpDialog.PASSWORD, password); + + JSONObject provider_json; + try { + provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); + parameters.putString(Provider.API_URL, provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + provider_API_command.setAction(ProviderAPI.SRP_REGISTER); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + + mProgressBar.setVisibility(ProgressBar.VISIBLE); + eipStatus.setText(R.string.signingup_message); + //mProgressBar.setMax(4); + startService(provider_API_command); + } + + /** + * Shows the sign up dialog. + * @param view from which the dialog is created. + */ + public void signUpDialog(View view, Bundle resultData) { + FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); + Fragment previous_sign_up_dialog = getFragmentManager().findFragmentByTag(SignUpDialog.TAG); + if (previous_sign_up_dialog != null) { + fragment_transaction.remove(previous_sign_up_dialog); + } + fragment_transaction.addToBackStack(null); + + DialogFragment newFragment = SignUpDialog.newInstance(); + if(resultData != null && !resultData.isEmpty()) { + newFragment.setArguments(resultData); + } + newFragment.show(fragment_transaction, SignUpDialog.TAG); + } + /** * Asks ProviderAPI to download an authenticated OpenVPN certificate. * @param session_id cookie for the server to allow us to download the certificate. @@ -364,7 +430,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL){ + if(resultCode == ProviderAPI.SRP_REGISTRATION_SUCCESSFUL){ + authenticate(resultData.getString(LogInDialog.USERNAME), resultData.getString(LogInDialog.PASSWORD)); + } else if(resultCode == ProviderAPI.SRP_REGISTRATION_FAILED){ + signUpDialog(((ViewGroup)findViewById(android.R.id.content)).getChildAt(0), resultData); + } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL){ String session_id_cookie_key = resultData.getString(ProviderAPI.SESSION_ID_COOKIE_KEY); String session_id_string = resultData.getString(ProviderAPI.SESSION_ID_KEY); setResult(RESULT_OK); @@ -379,7 +449,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf //Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); downloadAuthedUserCertificate(/*session_id*/); } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) { - logInDialog(getCurrentFocus(), resultData); + logInDialog(getCurrentFocus(), resultData); } else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) { authed_eip = false; getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java index a317d95e..29b429d1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java +++ b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java @@ -16,13 +16,13 @@ */ package se.leap.bitmaskclient; + import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; - import org.jboss.security.srp.SRPParameters; /** @@ -42,6 +42,7 @@ public class LeapSRPSession { final public static String M2 = "M2"; final public static String TOKEN = "token"; final public static String AUTHORIZATION_HEADER= "Authorization"; + final public static String TAG= "Leap SRP session class tag"; private SRPParameters params; private String username; @@ -155,14 +156,23 @@ public class LeapSRPSession { return x_digest_bytes; } + public byte[] calculateNewSalt() { + try { + BigInteger salt = new BigInteger(64, SecureRandom.getInstance("SHA1PRNG")); + return salt.toByteArray(); + } catch(NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } /** * Calculates the parameter V of the SRP-6a algorithm. - * @param k_string constant k predefined by the SRP server implementation. * @return the value of V */ - private BigInteger calculateV(String k_string) { - BigInteger k = new BigInteger(k_string, 16); - BigInteger v = k.multiply(g.modPow(x, N)); // g^x % N + public BigInteger calculateV(String username, String password, byte[] salt) { + byte[] x_bytes = calculatePasswordHash(username, password, ConfigHelper.trim(salt)); + x = new BigInteger(1, x_bytes); + BigInteger v = g.modPow(x, N); // g^x % N return v; } @@ -209,17 +219,11 @@ public class LeapSRPSession { * @return the parameter M1 * @throws NoSuchAlgorithmException */ - public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { + public byte[] response(byte[] salt_bytes, byte[] Bbytes) { // Calculate x = H(s | H(U | ':' | password)) byte[] M1 = null; if(new BigInteger(1, Bbytes).mod(new BigInteger(1, N_bytes)) != BigInteger.ZERO) { - byte[] xb = calculatePasswordHash(username, password, ConfigHelper.trim(salt_bytes)); - this.x = new BigInteger(1, xb); - - // Calculate v = kg^x mod N - String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; - this.v = calculateV(k_string); - + this.v = calculateV(username, password, salt_bytes); // H(N) byte[] digest_of_n = newDigest().digest(N_bytes); @@ -253,8 +257,7 @@ public class LeapSRPSession { byte[] S_bytes = ConfigHelper.trim(S.toByteArray()); // K = SessionHash(S) - String hash_algorithm = params.hashAlgorithm; - MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); + MessageDigest sessionDigest = newDigest(); K = ConfigHelper.trim(sessionDigest.digest(S_bytes)); // clientHash = H(N) xor H(g) | H(U) | A | B | K @@ -283,8 +286,9 @@ public class LeapSRPSession { BigInteger B = new BigInteger(1, Bbytes); BigInteger u = new BigInteger(1, u_bytes); - - BigInteger B_minus_v = B.subtract(v); + String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; + BigInteger k = new BigInteger(k_string, 16); + BigInteger B_minus_v = B.subtract(k.multiply(v)); BigInteger a_ux = a.add(u.multiply(x)); BigInteger S = B_minus_v.modPow(a_ux, N); return S; @@ -338,4 +342,8 @@ public class LeapSRPSession { } return md; } + + public byte[] getK() { + return K; + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java b/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java index a28c9049..45d3a373 100644 --- a/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java @@ -99,6 +99,14 @@ public class LogInDialog extends DialogFragment { .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); + interface_with_Dashboard.cancelLoginOrSignup(); + } + }) + .setNeutralButton(R.string.signup_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + String username = username_field.getText().toString(); + String password = password_field.getText().toString(); + interface_with_Dashboard.signUp(username, password); } }); @@ -112,13 +120,10 @@ public class LogInDialog extends DialogFragment { * */ public interface LogInDialogInterface { - /** - * Starts authentication process. - * @param username - * @param password - */ public void authenticate(String username, String password); public void cancelAuthedEipOn(); + public void signUp(String username, String password); + public void cancelLoginOrSignup(); } LogInDialogInterface interface_with_Dashboard; diff --git a/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java b/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java new file mode 100644 index 00000000..120d4eec --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) 2013 LEAP Encryption Access Project and contributers + * + * 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 se.leap.bitmaskclient; + +import se.leap.bitmaskclient.R; +import android.R.color; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.content.res.ColorStateList; +import android.os.Bundle; +import android.provider.CalendarContract.Colors; +import android.view.LayoutInflater; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.view.animation.BounceInterpolator; +import android.widget.EditText; +import android.widget.TextView; + +/** + * Implements the sign up dialog, currently without progress dialog. + * + * It returns to the previous fragment when finished, and sends username and password to the registration method. + * + * It also notifies the user if the password is not valid. + * + * @author parmegv + * + */ +public class SignUpDialog extends DialogFragment { + + final public static String TAG = "signUpDialog"; + final public static String VERB = "log in"; + final public static String USERNAME = "username"; + final public static String PASSWORD = "password"; + final public static String USERNAME_MISSING = "username missing"; + final public static String PASSWORD_INVALID_LENGTH = "password_invalid_length"; + + private static boolean is_eip_pending = false; + + public AlertDialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View log_in_dialog_view = inflater.inflate(R.layout.log_in_dialog, null); + + final TextView user_message = (TextView)log_in_dialog_view.findViewById(R.id.user_message); + if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { + user_message.setText(getArguments().getString(getResources().getString(R.string.user_message))); + } else { + user_message.setVisibility(View.GONE); + } + + final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); + if(getArguments() != null && getArguments().containsKey(USERNAME)) { + String username = getArguments().getString(USERNAME); + username_field.setText(username); + } + if (getArguments() != null && getArguments().containsKey(USERNAME_MISSING)) { + username_field.setError(getResources().getString(R.string.username_ask)); + } + + final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); + if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) { + password_field.requestFocus(); + } + if (getArguments() != null && getArguments().containsKey(PASSWORD_INVALID_LENGTH)) { + password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message)); + } + if(getArguments() != null && getArguments().getBoolean(EipServiceFragment.IS_EIP_PENDING, false)) { + is_eip_pending = true; + } + + + builder.setView(log_in_dialog_view) + .setPositiveButton(R.string.signup_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + String username = username_field.getText().toString(); + String password = password_field.getText().toString(); + dialog.dismiss(); + interface_with_Dashboard.signUp(username, password); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + interface_with_Dashboard.cancelLoginOrSignup(); + } + }); + + return builder.create(); + } + + /** + * Interface used to communicate SignUpDialog with Dashboard. + * + * @author parmegv + * + */ + public interface SignUpDialogInterface { + public void signUp(String username, String password); + public void cancelAuthedEipOn(); + public void cancelLoginOrSignup(); + } + + SignUpDialogInterface interface_with_Dashboard; + + /** + * @return a new instance of this DialogFragment. + */ + public static DialogFragment newInstance() { + SignUpDialog dialog_fragment = new SignUpDialog(); + return dialog_fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + interface_with_Dashboard = (SignUpDialogInterface) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement SignUpDialogListener"); + } + } + + @Override + public void onCancel(DialogInterface dialog) { + if(is_eip_pending) + interface_with_Dashboard.cancelAuthedEipOn(); + super.onCancel(dialog); + } +} |