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 171961a..1bf86e7 100644 --- a/app/src/main/java/com/example/bsm_notatnik/Login.java +++ b/app/src/main/java/com/example/bsm_notatnik/Login.java @@ -6,33 +6,26 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.TextUtils; -import android.view.View; import android.widget.Button; import android.widget.EditText; -import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; -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 javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; public class Login extends AppCompatActivity { private static final String SHARED_NAME_CREDENTIALS = "Credentials"; EditText editTextEmail, editTextPassword; Button buttonLogin; - ProgressBar progressBar; TextView textView; + private static final int MAX_LOGIN_ATTEMPTS = 5; + private static final long LOGIN_LOCKOUT_TIME = 60000; + private int loginAttempts = 0; + private long lastLoginAttemptTime = 0; + @Override protected void onCreate(Bundle savedInstanceState) { @@ -42,70 +35,68 @@ public class Login extends AppCompatActivity { editTextEmail = findViewById(R.id.username); editTextPassword = findViewById(R.id.password); buttonLogin = findViewById(R.id.btn_login); - progressBar = findViewById(R.id.progressBar); textView = findViewById(R.id.registerNow); - textView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(getApplicationContext(), Register.class); - startActivity(intent); - finish(); // finishes current activity - } + textView.setOnClickListener(view -> { + Intent intent = new Intent(getApplicationContext(), Register.class); + startActivity(intent); + finish(); // finishes current activity }); - buttonLogin.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - //progressBar.setVisibility(View.VISIBLE); - String email, hashedEmail, password; - email = String.valueOf(editTextEmail.getText()); - - hashedEmail = Utility.hashEmail(email); - password = String.valueOf(editTextPassword.getText()); - - if (TextUtils.isEmpty(email)){ - Toast.makeText(Login.this, "Enter email!", Toast.LENGTH_SHORT).show(); - return; - } - if (TextUtils.isEmpty(password)){ - Toast.makeText(Login.this, "Enter password!", Toast.LENGTH_SHORT).show(); - return; - } - if (!checkIfUserExists(hashedEmail)){ - Toast.makeText(Login.this, "No such username in database!", Toast.LENGTH_SHORT).show(); - editTextPassword.setText(""); - return; - } - - try { - login(hashedEmail, password); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } catch (InvalidKeySpecException e) { - throw new RuntimeException(e); - } - //progressBar.setVisibility(View.GONE); + buttonLogin.setOnClickListener(view -> { + long currentTime = System.currentTimeMillis(); + if (currentTime - lastLoginAttemptTime >= LOGIN_LOCKOUT_TIME) { + loginAttempts = 0; } + loginAttempts++; + lastLoginAttemptTime = currentTime; + if (loginAttempts > MAX_LOGIN_ATTEMPTS) { + Toast.makeText(Login.this, "Too many login attempts.", Toast.LENGTH_SHORT).show(); + return; + } + + + String email, hashedEmail, password; + + email = String.valueOf(editTextEmail.getText()); + hashedEmail = Utility.hashEmail(email); + + password = String.valueOf(editTextPassword.getText()); + + + if (TextUtils.isEmpty(email)){ + Toast.makeText(Login.this, "Enter email!", Toast.LENGTH_SHORT).show(); + return; + } + if (TextUtils.isEmpty(password)){ + Toast.makeText(Login.this, "Enter password!", Toast.LENGTH_SHORT).show(); + return; + } + if (!checkIfUserExists(hashedEmail)){ + Toast.makeText(Login.this, "No such username in database!", Toast.LENGTH_SHORT).show(); + editTextPassword.setText(""); + return; + } + + login(hashedEmail, password); }); } - private boolean checkIfUserExists(String hashedemail){ + private boolean checkIfUserExists(String hashedEmail){ SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - return sharedPreferences.contains("user_" + hashedemail); + return sharedPreferences.contains("user_" + hashedEmail); } - private void login(String hashedemail, String password) throws NoSuchAlgorithmException, InvalidKeySpecException { + private void login(String hashedEmail, String password) { SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - String passwordHashFromData = sharedPreferences.getString("user_" + hashedemail, "err"); + String passwordHashFromData = sharedPreferences.getString("user_" + hashedEmail, "err"); + byte[] salt = getSaltForUser(hashedEmail); - byte[] salt = getSaltForUser(hashedemail, false); - - String inputPasswordHash = Utility.hashCredential(password, salt, 1000); + String inputPasswordHash = Utility.hashCredential(password, salt); assert inputPasswordHash != null; @@ -113,8 +104,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_HASH", hashedemail); - //intent.putExtra("KEY", getKeyFromPassword(password, getSalt2(hashedemail))); + intent.putExtra("CURRENT_USER_EMAIL_HASH", hashedEmail); intent.putExtra("PAS", password); startActivity(intent); finish(); @@ -125,37 +115,10 @@ public class Login extends AppCompatActivity { } } - public static SecretKey getKeyFromPassword(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException { - - SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); - KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256); - SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); - - return secret; - } - - private String genKeyHash(String hashedemail, String password){ - byte[] salt2 = getSaltForUser(hashedemail, true); - return Utility.hashCredential(password, salt2, 5000); - } - - private byte[] getSaltForUser(String hashedEmail, boolean salt2){ + private byte[] getSaltForUser(String hashedEmail){ SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - String saltFromData; - - if (salt2){ - saltFromData = sharedPreferences.getString("salt_2_" + hashedEmail, "err"); - } - else { - saltFromData = sharedPreferences.getString("salt_" + hashedEmail, "err"); - } + String saltFromData = sharedPreferences.getString("salt_" + hashedEmail, "err"); return Base64.getDecoder().decode(saltFromData); - - } - - private String getSalt2(String hashedEmail){ - SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - return sharedPreferences.getString("salt_2_" + hashedEmail, "err"); } } \ 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 a77c9fa..2ed83c8 100644 --- a/app/src/main/java/com/example/bsm_notatnik/MainActivity.java +++ b/app/src/main/java/com/example/bsm_notatnik/MainActivity.java @@ -1,4 +1,5 @@ package com.example.bsm_notatnik; +import android.annotation.SuppressLint; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; @@ -106,7 +107,7 @@ public class MainActivity extends AppCompatActivity { } if(!validatePassword(newPassword)){ - Toast.makeText(MainActivity.this, "Wrong format of new password!", Toast.LENGTH_SHORT).show(); + Toast.makeText(MainActivity.this, "New password to weak!", Toast.LENGTH_SHORT).show(); return; } @@ -160,9 +161,10 @@ public class MainActivity extends AppCompatActivity { throw new RuntimeException(e); } createNoteView(note); + + Toast.makeText(MainActivity.this, "Note saved!", Toast.LENGTH_SHORT).show(); } - Toast.makeText(MainActivity.this, "Note saved!", Toast.LENGTH_SHORT).show(); }); builder.setNegativeButton("Cancel", (dialogInterface, i) -> dialogInterface.dismiss()); @@ -239,7 +241,7 @@ public class MainActivity extends AppCompatActivity { private boolean validatePassword(String password){ - final String PASSWORD_PATTERN = "^.{6,}$"; + final String PASSWORD_PATTERN = "^(?=.*[0-9])(?=.*[A-Z])(.{8,})$"; Pattern pattern = Pattern.compile(PASSWORD_PATTERN); Matcher matcher = pattern.matcher(password); @@ -254,7 +256,7 @@ public class MainActivity extends AppCompatActivity { String newSaltString = Base64.getEncoder().encodeToString(newSalt); editor.putString("salt_" + hashedEmail, newSaltString); - String hashedNewPassword = Utility.hashCredential(newPassword, newSalt, 1000); + String hashedNewPassword = Utility.hashCredential(newPassword, newSalt); editor.putString("user_" + hashedEmail, hashedNewPassword); editor.apply(); @@ -264,7 +266,7 @@ public class MainActivity extends AppCompatActivity { private boolean validateOldPassword(String hashedEmail, String oldPassword){ byte[] salt = getSaltForUser(hashedEmail, false); - String hashedOldPassword = Utility.hashCredential(oldPassword, salt, 1000); + String hashedOldPassword = Utility.hashCredential(oldPassword, salt); String hashedCorrectPassword = gerPasswordHashFromShared(hashedEmail); assert hashedOldPassword != null; @@ -313,7 +315,7 @@ public class MainActivity extends AppCompatActivity { for(int i=0; i showDeleteDialog(note)); + deleteNoteButton.setOnClickListener(view -> showDeleteDialog(note)); noteView.setOnLongClickListener(view -> { showEditNoteDialog(note); diff --git a/app/src/main/java/com/example/bsm_notatnik/Note.java b/app/src/main/java/com/example/bsm_notatnik/Note.java index 9e1c922..7750ece 100644 --- a/app/src/main/java/com/example/bsm_notatnik/Note.java +++ b/app/src/main/java/com/example/bsm_notatnik/Note.java @@ -4,13 +4,11 @@ public class Note { private String title; private String content; - private int id; - public Note(){ } - public Note(String title, String content, int id){ + public Note(String title, String content){ this.title = title; this.content = content; } 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 b8533bd..fdec677 100644 --- a/app/src/main/java/com/example/bsm_notatnik/Register.java +++ b/app/src/main/java/com/example/bsm_notatnik/Register.java @@ -6,10 +6,8 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.TextUtils; -import android.view.View; import android.widget.Button; import android.widget.EditText; -import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; @@ -22,10 +20,8 @@ import java.util.regex.Pattern; public class Register extends AppCompatActivity { private static final String SHARED_NAME_CREDENTIALS = "Credentials"; - EditText editTextEmail, editTextPassword; Button buttonReg; - ProgressBar progressBar; TextView loginNowTextView; @@ -38,86 +34,75 @@ public class Register extends AppCompatActivity { editTextEmail = findViewById(R.id.username); editTextPassword = findViewById(R.id.password); buttonReg = findViewById(R.id.btn_register); - progressBar = findViewById(R.id.progressBar); loginNowTextView = findViewById(R.id.loginNow); - //goes to login page - loginNowTextView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(getApplicationContext(), Login.class); - startActivity(intent); - finish(); // finishes current activity - } + loginNowTextView.setOnClickListener(view -> { + Intent intent = new Intent(getApplicationContext(), Login.class); + startActivity(intent); + finish(); // finishes current activity }); //when register button is clicked - buttonReg.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - //progressBar.setVisibility(View.VISIBLE); - String email, hashedEmail, password, hashedPassword; + buttonReg.setOnClickListener(view -> { + String email, hashedEmail, password, hashedPassword; - email = String.valueOf(editTextEmail.getText()); - password = String.valueOf(editTextPassword.getText()); + email = String.valueOf(editTextEmail.getText()); + password = String.valueOf(editTextPassword.getText()); - //checks if email field is not empty - if (TextUtils.isEmpty(email)){ - Toast.makeText(Register.this, "Enter email!", Toast.LENGTH_SHORT).show(); - return; - } - //checks if password field is not empty - if (TextUtils.isEmpty(password)){ - Toast.makeText(Register.this, "Enter password!", Toast.LENGTH_SHORT).show(); - return; - } + //checks if email field is not empty + if (TextUtils.isEmpty(email)){ + Toast.makeText(Register.this, "Enter email!", Toast.LENGTH_SHORT).show(); + return; + } + //checks if password field is not empty + if (TextUtils.isEmpty(password)){ + Toast.makeText(Register.this, "Enter password!", Toast.LENGTH_SHORT).show(); + return; + } - hashedEmail = Utility.hashEmail(email); + hashedEmail = Utility.hashEmail(email); - //checks if given username is already registered in database - if (checkIfUserExists(hashedEmail)){ - editTextEmail.setText(""); - editTextPassword.setText(""); - Toast.makeText(Register.this, "Account with this username already exists!", Toast.LENGTH_SHORT).show(); - return; - } - //checks if email has correct format - if (!validateEmail(email)){ - editTextPassword.setText(""); - Toast.makeText(Register.this, "Email format not correct!", Toast.LENGTH_SHORT).show(); - return; - } - //checks password wymagania - if (!validatePassword(password)){ - Toast.makeText(Register.this, "Password to weak!", Toast.LENGTH_SHORT).show(); - return; - } - - - - byte[] salt1 = Utility.generateSalt(); - byte[] salt2 = Utility.generateSalt(); - saveSaltsForUser(hashedEmail, salt1, salt2); - - - hashedPassword = Utility.hashCredential(password, salt1, 1000); - - saveNewUser(hashedEmail, hashedPassword); - - Toast.makeText(Register.this, "Konto utworzone z email: " + email + " oraz hasłem: " + password, Toast.LENGTH_SHORT).show(); + //checks if given username is already registered in database + if (checkIfUserExists(hashedEmail)){ editTextEmail.setText(""); editTextPassword.setText(""); + Toast.makeText(Register.this, "Account with this username already exists!", Toast.LENGTH_SHORT).show(); + return; } + //checks if email has correct format + if (!validateEmail(email)){ + editTextPassword.setText(""); + Toast.makeText(Register.this, "Email format not correct!", Toast.LENGTH_SHORT).show(); + return; + } + //checks password requirements + if (!validatePassword(password)){ + Toast.makeText(Register.this, "Password to weak!", Toast.LENGTH_SHORT).show(); + return; + } + + byte[] salt1 = Utility.generateSalt(); + byte[] salt2 = Utility.generateSalt(); + + saveSaltsForUser(hashedEmail, salt1, salt2); + + hashedPassword = Utility.hashCredential(password, salt1); + + saveNewUser(hashedEmail, hashedPassword); + + Toast.makeText(Register.this, "Created account with email: " + email, Toast.LENGTH_SHORT).show(); + editTextEmail.setText(""); + editTextPassword.setText(""); }); } - private boolean checkIfUserExists(String hashedemail){ + private boolean checkIfUserExists(String hashedEmail){ SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); - return sharedPreferences.contains("user_" + hashedemail); + return sharedPreferences.contains("user_" + hashedEmail); } private boolean validateEmail(String email){ @@ -129,31 +114,30 @@ public class Register extends AppCompatActivity { } private boolean validatePassword(String password){ - final String PASSWORD_PATTERN = "^.{6,}$"; + final String PASSWORD_PATTERN = "^(?=.*[0-9])(?=.*[A-Z])(.{8,})$"; Pattern pattern = Pattern.compile(PASSWORD_PATTERN); Matcher matcher = pattern.matcher(password); return matcher.matches(); } - private void saveSaltsForUser(String hashedemail, byte[] salt1, byte[] salt2){ + private void saveSaltsForUser(String hashedEmail, byte[] salt1, byte[] salt2){ SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); String salt1String = Base64.getEncoder().encodeToString(salt1); String salt2String = Base64.getEncoder().encodeToString(salt2); - editor.putString("salt_" + hashedemail, salt1String); - editor.putString("salt_2_" + hashedemail, salt2String); - + editor.putString("salt_" + hashedEmail, salt1String); + editor.putString("salt_2_" + hashedEmail, salt2String); editor.apply(); } - private void saveNewUser(String hashedemail, String password){ + 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.putString("user_" + hashedEmail, password); editor.apply(); } } \ No newline at end of file diff --git a/app/src/main/java/com/example/bsm_notatnik/Utility.java b/app/src/main/java/com/example/bsm_notatnik/Utility.java index af285c1..4a945e2 100644 --- a/app/src/main/java/com/example/bsm_notatnik/Utility.java +++ b/app/src/main/java/com/example/bsm_notatnik/Utility.java @@ -25,13 +25,12 @@ public class Utility { byte[] emailSalt; emailSalt = getFirst16BytesOfHash(email); - return hashCredential(email, emailSalt, 1000); + return hashCredential(email, emailSalt); } - protected static String hashCredential(String credential, byte[] salt, int iterations){ - int iteratiions = iterations; + protected static String hashCredential(String credential, byte[] salt){ int keyLen = 256; - KeySpec keySpec = new PBEKeySpec(credential.toCharArray(), salt, iteratiions, keyLen); + KeySpec keySpec = new PBEKeySpec(credential.toCharArray(), salt, 1000, keyLen); try{ SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); SecretKey secretKey = secretKeyFactory.generateSecret(keySpec); @@ -46,21 +45,19 @@ public class Utility { protected static 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; } } + + } diff --git a/app/src/main/java/com/example/bsm_notatnik/UtilityAES.java b/app/src/main/java/com/example/bsm_notatnik/UtilityAES.java index 5cfa7cf..09154f7 100644 --- a/app/src/main/java/com/example/bsm_notatnik/UtilityAES.java +++ b/app/src/main/java/com/example/bsm_notatnik/UtilityAES.java @@ -6,7 +6,6 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; -import java.util.Arrays; import java.util.Base64; import javax.crypto.BadPaddingException; diff --git a/app/src/main/res/layout/create_note_dialog.xml b/app/src/main/res/layout/create_note_dialog.xml index b215c02..0bf1b8e 100644 --- a/app/src/main/res/layout/create_note_dialog.xml +++ b/app/src/main/res/layout/create_note_dialog.xml @@ -1,4 +1,3 @@ -