From e96f619e466b1f9505cc6428ca729b5f2b356084 Mon Sep 17 00:00:00 2001 From: "mikgaw@st.amu.edu.pl" Date: Mon, 4 Dec 2023 00:12:07 +0100 Subject: [PATCH] zmiana hasla --- .../java/com/example/bsm_notatnik/Login.java | 74 +++++++---- .../example/bsm_notatnik/MainActivity.java | 118 +++++++++++++++++- .../com/example/bsm_notatnik/Register.java | 90 +++++++++---- .../res/layout/password_change_dialog.xml | 12 +- 4 files changed, 231 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/com/example/bsm_notatnik/Login.java b/app/src/main/java/com/example/bsm_notatnik/Login.java index eb9b3d3..1a6a629 100644 --- a/app/src/main/java/com/example/bsm_notatnik/Login.java +++ b/app/src/main/java/com/example/bsm_notatnik/Login.java @@ -1,13 +1,11 @@ package com.example.bsm_notatnik; -import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.TextUtils; -import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; @@ -15,17 +13,12 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; -import com.google.android.gms.tasks.OnCompleteListener; -import com.google.android.gms.tasks.Task; -import com.google.firebase.auth.AuthResult; -import com.google.firebase.auth.FirebaseAuth; -import com.google.firebase.auth.FirebaseUser; - +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Base64; -import java.util.Objects; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; @@ -66,8 +59,10 @@ public class Login extends AppCompatActivity { @Override public void onClick(View view) { //progressBar.setVisibility(View.VISIBLE); - String email, password; + String email, hashedEmail, password; email = String.valueOf(editTextEmail.getText()); + + hashedEmail = hashEmail(email); password = String.valueOf(editTextPassword.getText()); if (TextUtils.isEmpty(email)){ @@ -78,31 +73,39 @@ public class Login extends AppCompatActivity { Toast.makeText(Login.this, "Enter password!", Toast.LENGTH_SHORT).show(); return; } - if (!checkIfUserExists(email)){ + if (!checkIfUserExists(hashedEmail)){ Toast.makeText(Login.this, "No such username in database!", Toast.LENGTH_SHORT).show(); editTextPassword.setText(""); return; } - login(email, password); + login(hashedEmail, password); //progressBar.setVisibility(View.GONE); } }); } - private boolean checkIfUserExists(String email){ + private boolean checkIfUserExists(String hashedemail){ SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - return sharedPreferences.contains("user_" + email); + return sharedPreferences.contains("user_" + hashedemail); } - private void login(String email, String password){ + private String hashEmail(String email){ + byte[] emailSalt = new byte[16]; + emailSalt = getFirst16BytesOfHash(email); + + return hashCredential(email, emailSalt); + } + + private void login(String hashedemail, String password){ SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - String passwordHashFromData = sharedPreferences.getString("user_" + email, "err"); + String passwordHashFromData = sharedPreferences.getString("user_" + hashedemail, "err"); - byte[] salt = getSaltForUser(email); - String inputPasswordHash = hashPassword(password, salt); + byte[] salt = getSaltForUser(hashedemail); + + String inputPasswordHash = hashCredential(password, salt); assert inputPasswordHash != null; @@ -110,7 +113,7 @@ public class Login extends AppCompatActivity { Toast.makeText(getApplicationContext(), "Login Successful", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(getApplicationContext(), MainActivity.class); - intent.putExtra("CURRENT_USER_EMAIL", email); + intent.putExtra("CURRENT_USER_EMAIL_HASH", hashedemail); startActivity(intent); finish(); @@ -120,22 +123,22 @@ public class Login extends AppCompatActivity { } } - private byte[] getSaltForUser(String email){ + private byte[] getSaltForUser(String hashedemail){ SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - String saltFromData = sharedPreferences.getString("salt_" + email, "err"); + String saltFromData = sharedPreferences.getString("salt_" + hashedemail, "err"); return Base64.getDecoder().decode(saltFromData); } - private static String hashPassword(String password, byte[] salt){ + private static String hashCredential(String credential, byte[] salt){ int iteratiions = 1000; int keyLen = 256; - KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iteratiions, keyLen); + KeySpec keySpec = new PBEKeySpec(credential.toCharArray(), salt, iteratiions, keyLen); try{ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); SecretKey secretKey = secretKeyFactory.generateSecret(keySpec); - byte[] hashedPassword = secretKey.getEncoded(); - return Base64.getEncoder().encodeToString(hashedPassword); + byte[] hashedCredential = secretKey.getEncoded(); + return Base64.getEncoder().encodeToString(hashedCredential); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { e.printStackTrace(); @@ -144,4 +147,25 @@ public class Login extends AppCompatActivity { } + private byte[] getFirst16BytesOfHash(String input){ + try { + // Create MessageDigest instance for SHA-256 + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + + // Get the hash value by updating the digest with the input bytes + byte[] hashBytes = digest.digest(input.getBytes(StandardCharsets.UTF_8)); + + // Truncate the hash to the first 16 bytes + byte[] truncatedHash = new byte[16]; + System.arraycopy(hashBytes, 0, truncatedHash, 0, 16); + + return truncatedHash; + } catch (NoSuchAlgorithmException e) { + // Handle the exception (e.g., print an error message) + e.printStackTrace(); + return null; + } + } + + } \ No newline at end of file diff --git a/app/src/main/java/com/example/bsm_notatnik/MainActivity.java b/app/src/main/java/com/example/bsm_notatnik/MainActivity.java index 9ea5c55..bb8bdad 100644 --- a/app/src/main/java/com/example/bsm_notatnik/MainActivity.java +++ b/app/src/main/java/com/example/bsm_notatnik/MainActivity.java @@ -1,7 +1,9 @@ package com.example.bsm_notatnik; import android.content.DialogInterface; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -14,12 +16,25 @@ import android.widget.Toast; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; public class MainActivity extends AppCompatActivity { Button buttonLogout, buttonChangePassword; + private static final String SHARED_NAME_CREDENTIALS = "Credentials"; + @Override protected void onCreate(Bundle savedInstanceState) { @@ -27,7 +42,7 @@ public class MainActivity extends AppCompatActivity { setContentView(R.layout.activity_main); Intent intent = getIntent(); - String currentu_username = intent.getStringExtra("CURRENT_USER_EMAIL"); + String current_username_hashed = intent.getStringExtra("CURRENT_USER_EMAIL_HASH"); buttonLogout = findViewById(R.id.btn_logout); buttonChangePassword = findViewById(R.id.btn_change_password); @@ -44,7 +59,7 @@ public class MainActivity extends AppCompatActivity { buttonChangePassword.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - showPasswordChangeDialog(); + showPasswordChangeDialog(current_username_hashed); } }); @@ -58,7 +73,10 @@ public class MainActivity extends AppCompatActivity { finish(); } - private void showPasswordChangeDialog(){ + + + + private void showPasswordChangeDialog(String hashedEmail){ // Inflate the dialog layout LayoutInflater inflater = getLayoutInflater(); View dialogView = inflater.inflate(R.layout.password_change_dialog, null); @@ -73,18 +91,36 @@ public class MainActivity extends AppCompatActivity { @Override public void onClick(DialogInterface dialogInterface, int i) { // Handle password change logic here + EditText editTextOldPassword = dialogView.findViewById(R.id.editTextOldPassword); EditText editTextNewPassword = dialogView.findViewById(R.id.editTextNewPassword); EditText editTextConfirmPassword = dialogView.findViewById(R.id.editTextConfirmPassword); + String oldPassword = editTextOldPassword.getText().toString(); String newPassword = editTextNewPassword.getText().toString(); String confirmPassword = editTextConfirmPassword.getText().toString(); + if (TextUtils.isEmpty(oldPassword) || TextUtils.isEmpty(newPassword) || TextUtils.isEmpty(confirmPassword)) { + Toast.makeText(MainActivity.this, "Fill out all 3 fields!", Toast.LENGTH_SHORT).show(); + return; + } + + if(!validatePassword(newPassword)){ + Toast.makeText(MainActivity.this, "Wrong format of new password!", Toast.LENGTH_SHORT).show(); + return; + } + + if(!validateOldPassword(hashedEmail, oldPassword)){ + Toast.makeText(MainActivity.this, "Old password not correct!", Toast.LENGTH_SHORT).show(); + return; + } + // Perform password change validation and logic if (newPassword.equals(confirmPassword)) { - // Passwords match, implement your password change logic here + updatePassword(hashedEmail, newPassword); + Toast.makeText(MainActivity.this, "Password Changed", Toast.LENGTH_SHORT).show(); } else { - // Passwords do not match, show an error message - // You can use a Toast or any other method to display the message + Toast.makeText(MainActivity.this, "New passwords don't match!", Toast.LENGTH_SHORT).show(); + return; } } }); @@ -102,5 +138,75 @@ public class MainActivity extends AppCompatActivity { alertDialog.show(); } + + private boolean validatePassword(String password){ + final String PASSWORD_PATTERN = "^.{6,}$"; + Pattern pattern = Pattern.compile(PASSWORD_PATTERN); + Matcher matcher = pattern.matcher(password); + + return matcher.matches(); + } + + private void updatePassword(String hashedEmail, String newPassword){ + SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + + byte[] newSalt = generateSalt(); + String newSaltString = Base64.getEncoder().encodeToString(newSalt); + editor.putString("salt_" + hashedEmail, newSaltString); + + String hashedNewPassword = hashCredential(newPassword, newSalt); + editor.putString("user_" + hashedEmail, hashedNewPassword); + editor.apply(); + } + + private boolean validateOldPassword(String hashedEmail, String oldPassword){ + byte[] salt = getSaltForUser(hashedEmail); + String hashedOldPassword = hashCredential(oldPassword, salt); + String hashedCorrectPassword = getPasswordFromShared(hashedEmail); + + assert hashedOldPassword != null; + if (hashedOldPassword.equals(hashedCorrectPassword)){ + return true; + } else { + return false; + } + } + + private byte[] getSaltForUser(String hashedEmail){ + SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); + String saltFromData = sharedPreferences.getString("salt_" + hashedEmail, "err"); + return Base64.getDecoder().decode(saltFromData); + } + + private String getPasswordFromShared(String hashedEmail){ + SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); + return sharedPreferences.getString("user_" + hashedEmail, "err"); + } + + private static byte[] generateSalt(){ + SecureRandom random = new SecureRandom(); + byte[] salt = new byte[16]; + random.nextBytes(salt); + return salt; + } + + private static String hashCredential(String credential, byte[] salt){ + int iteratiions = 1000; + int keyLen = 256; + + KeySpec keySpec = new PBEKeySpec(credential.toCharArray(), salt, iteratiions, keyLen); + try{ + SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + SecretKey secretKey = secretKeyFactory.generateSecret(keySpec); + byte[] hashedCredential = secretKey.getEncoded(); + return Base64.getEncoder().encodeToString(hashedCredential); + + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + e.printStackTrace(); + return null; + } + } + } diff --git a/app/src/main/java/com/example/bsm_notatnik/Register.java b/app/src/main/java/com/example/bsm_notatnik/Register.java index 6adbed9..c4ff5d4 100644 --- a/app/src/main/java/com/example/bsm_notatnik/Register.java +++ b/app/src/main/java/com/example/bsm_notatnik/Register.java @@ -2,12 +2,10 @@ package com.example.bsm_notatnik; import androidx.appcompat.app.AppCompatActivity; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.TextUtils; -import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; @@ -17,13 +15,15 @@ import android.widget.Toast; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Base64; -import java.security.SecureRandom; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -67,7 +67,8 @@ public class Register extends AppCompatActivity { @Override public void onClick(View view) { //progressBar.setVisibility(View.VISIBLE); - String email, password; + String email, hashedEmail, password, hashedPassword; + email = String.valueOf(editTextEmail.getText()); password = String.valueOf(editTextPassword.getText()); @@ -81,8 +82,11 @@ public class Register extends AppCompatActivity { Toast.makeText(Register.this, "Enter password!", Toast.LENGTH_SHORT).show(); return; } + + hashedEmail = hashEmail(email); + //checks if given username is already registered in database - if (checkIfUserExists(email)){ + if (checkIfUserExists(hashedEmail)){ editTextEmail.setText(""); editTextPassword.setText(""); Toast.makeText(Register.this, "Account with this username already exists!", Toast.LENGTH_SHORT).show(); @@ -101,11 +105,13 @@ public class Register extends AppCompatActivity { } - byte[] salt = generateSalt(); - saveSaltForUser(email, salt); - String hashPassword = hashPassword(password, salt); - saveNewUser(email, hashPassword); + byte[] salt = generateSalt(); + saveSaltForUser(hashedEmail, salt); + + hashedPassword = hashCredential(password, salt); + + saveNewUser(hashedEmail, hashedPassword); Toast.makeText(Register.this, "Konto utworzone z email: " + email + " oraz hasłem: " + password, Toast.LENGTH_SHORT).show(); editTextEmail.setText(""); @@ -115,16 +121,10 @@ public class Register extends AppCompatActivity { } - private void saveNewUser(String email, String password){ - SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString("user_" + email, password); - editor.apply(); - } - private boolean checkIfUserExists(String email){ + private boolean checkIfUserExists(String hashedemail){ SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - return sharedPreferences.contains("user_" + email); + return sharedPreferences.contains("user_" + hashedemail); } private boolean validateEmail(String email){ @@ -143,13 +143,11 @@ public class Register extends AppCompatActivity { return matcher.matches(); } - private void saveSaltForUser(String email, byte[] salt){ - SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPreferences.edit(); + private String hashEmail(String email){ + byte[] emailSalt; + emailSalt = getFirst16BytesOfHash(email); - String saltString = Base64.getEncoder().encodeToString(salt); - editor.putString("salt_" + email, saltString); - editor.apply(); + return hashCredential(email, emailSalt); } private static byte[] generateSalt(){ @@ -159,16 +157,34 @@ public class Register extends AppCompatActivity { return salt; } - private static String hashPassword(String password, byte[] salt){ + private void saveSaltForUser(String hashedemail, byte[] salt){ + SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + + String saltString = Base64.getEncoder().encodeToString(salt); + editor.putString("salt_" + hashedemail, saltString); + editor.apply(); + } + + private void saveNewUser(String hashedemail, String password){ + SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString("user_" + hashedemail, password); + editor.apply(); + } + + + + private static String hashCredential(String credential, byte[] salt){ int iteratiions = 1000; int keyLen = 256; - KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iteratiions, keyLen); + KeySpec keySpec = new PBEKeySpec(credential.toCharArray(), salt, iteratiions, keyLen); try{ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); SecretKey secretKey = secretKeyFactory.generateSecret(keySpec); - byte[] hashedPassword = secretKey.getEncoded(); - return Base64.getEncoder().encodeToString(hashedPassword); + byte[] hashedCredential = secretKey.getEncoded(); + return Base64.getEncoder().encodeToString(hashedCredential); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { e.printStackTrace(); @@ -176,5 +192,25 @@ public class Register extends AppCompatActivity { } } + private byte[] getFirst16BytesOfHash(String input){ + try { + // Create MessageDigest instance for SHA-256 + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + + // Get the hash value by updating the digest with the input bytes + byte[] hashBytes = digest.digest(input.getBytes(StandardCharsets.UTF_8)); + + // Truncate the hash to the first 16 bytes + byte[] truncatedHash = new byte[16]; + System.arraycopy(hashBytes, 0, truncatedHash, 0, 16); + + return truncatedHash; + } catch (NoSuchAlgorithmException e) { + // Handle the exception (e.g., print an error message) + e.printStackTrace(); + return null; + } + } + } \ No newline at end of file diff --git a/app/src/main/res/layout/password_change_dialog.xml b/app/src/main/res/layout/password_change_dialog.xml index 85e6297..f361deb 100644 --- a/app/src/main/res/layout/password_change_dialog.xml +++ b/app/src/main/res/layout/password_change_dialog.xml @@ -5,6 +5,13 @@ android:orientation="vertical" android:padding="16dp"> + + -