before final cleaning and salt
This commit is contained in:
parent
081c9cb909
commit
cca9f2c1da
@ -1,51 +0,0 @@
|
|||||||
package com.example.bsm_notatnik;
|
|
||||||
|
|
||||||
import javax.crypto.*;
|
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
public class AESUtils {
|
|
||||||
|
|
||||||
private static final String ALGORITHM = "AES";
|
|
||||||
private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding"; // Use ECB mode without an IV
|
|
||||||
|
|
||||||
public static String encrypt(String data, String key) {
|
|
||||||
try {
|
|
||||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
|
||||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
|
|
||||||
|
|
||||||
byte[] encryptedData = cipher.doFinal(data.getBytes());
|
|
||||||
|
|
||||||
return Base64.getEncoder().encodeToString(encryptedData);
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
|
|
||||||
IllegalBlockSizeException | BadPaddingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String decrypt(String encryptedData, String key) {
|
|
||||||
try {
|
|
||||||
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
|
|
||||||
|
|
||||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
|
||||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
|
|
||||||
|
|
||||||
byte[] decryptedData = cipher.doFinal(encryptedBytes);
|
|
||||||
return new String(decryptedData);
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
|
|
||||||
IllegalBlockSizeException | BadPaddingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
|||||||
package com.example.bsm_notatnik;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.security.keystore.KeyGenParameterSpec;
|
|
||||||
import android.security.keystore.KeyProperties;
|
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.KeyGenerator;
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
|
|
||||||
public class CryptoManager {
|
|
||||||
|
|
||||||
private final KeyStore keyStore;
|
|
||||||
|
|
||||||
public CryptoManager() throws Exception {
|
|
||||||
keyStore = KeyStore.getInstance("AndroidKeyStore");
|
|
||||||
keyStore.load(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Cipher getEncryptCipher() throws Exception {
|
|
||||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, getKey());
|
|
||||||
return cipher;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Cipher getDecryptCipherForIv(byte[] iv) throws Exception {
|
|
||||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(iv));
|
|
||||||
return cipher;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SecretKey getKey() throws Exception {
|
|
||||||
KeyStore.SecretKeyEntry existingKey = (KeyStore.SecretKeyEntry) keyStore.getEntry("secret", null);
|
|
||||||
return (existingKey != null) ? existingKey.getSecretKey() : createKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SecretKey createKey() throws Exception {
|
|
||||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
|
|
||||||
keyGenerator.init(new KeyGenParameterSpec.Builder(
|
|
||||||
"secret",
|
|
||||||
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
|
||||||
.setBlockModes(BLOCK_MODE)
|
|
||||||
.setEncryptionPaddings(PADDING)
|
|
||||||
.setUserAuthenticationRequired(false)
|
|
||||||
.setRandomizedEncryptionRequired(true)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
return keyGenerator.generateKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public byte[] encrypt(byte[] bytes, OutputStream outputStream) throws Exception {
|
|
||||||
Cipher encryptCipher = getEncryptCipher();
|
|
||||||
byte[] encryptedBytes = encryptCipher.doFinal(bytes);
|
|
||||||
try {
|
|
||||||
outputStream.write(encryptCipher.getIV().length);
|
|
||||||
outputStream.write(encryptCipher.getIV());
|
|
||||||
outputStream.write(encryptedBytes.length);
|
|
||||||
outputStream.write(encryptedBytes);
|
|
||||||
} finally {
|
|
||||||
outputStream.close();
|
|
||||||
}
|
|
||||||
return encryptedBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] decrypt(InputStream inputStream) throws Exception {
|
|
||||||
byte[] iv;
|
|
||||||
byte[] encryptedBytes;
|
|
||||||
try {
|
|
||||||
int ivSize = inputStream.read();
|
|
||||||
iv = new byte[ivSize];
|
|
||||||
inputStream.read(iv);
|
|
||||||
|
|
||||||
int encryptedBytesSize = inputStream.read();
|
|
||||||
encryptedBytes = new byte[encryptedBytesSize];
|
|
||||||
inputStream.read(encryptedBytes);
|
|
||||||
} finally {
|
|
||||||
inputStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return getDecryptCipherForIv(iv).doFinal(encryptedBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;
|
|
||||||
private static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC;
|
|
||||||
private static final String PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7;
|
|
||||||
private static final String TRANSFORMATION = ALGORITHM + "/" + BLOCK_MODE + "/" + PADDING;
|
|
||||||
}
|
|
@ -23,6 +23,7 @@ import java.util.Base64;
|
|||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.SecretKeyFactory;
|
import javax.crypto.SecretKeyFactory;
|
||||||
import javax.crypto.spec.PBEKeySpec;
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
public class Login extends AppCompatActivity {
|
public class Login extends AppCompatActivity {
|
||||||
|
|
||||||
@ -79,7 +80,13 @@ public class Login extends AppCompatActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
login(hashedEmail, password);
|
try {
|
||||||
|
login(hashedEmail, password);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
//progressBar.setVisibility(View.GONE);
|
//progressBar.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -91,7 +98,7 @@ public class Login extends AppCompatActivity {
|
|||||||
return sharedPreferences.contains("user_" + hashedemail);
|
return sharedPreferences.contains("user_" + hashedemail);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login(String hashedemail, String password){
|
private void login(String hashedemail, String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE);
|
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE);
|
||||||
String passwordHashFromData = sharedPreferences.getString("user_" + hashedemail, "err");
|
String passwordHashFromData = sharedPreferences.getString("user_" + hashedemail, "err");
|
||||||
|
|
||||||
@ -107,7 +114,8 @@ public class Login extends AppCompatActivity {
|
|||||||
|
|
||||||
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
|
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
|
||||||
intent.putExtra("CURRENT_USER_EMAIL_HASH", hashedemail);
|
intent.putExtra("CURRENT_USER_EMAIL_HASH", hashedemail);
|
||||||
intent.putExtra("KEY_HASH", genKeyHash(hashedemail, password));
|
//intent.putExtra("KEY", getKeyFromPassword(password, getSalt2(hashedemail)));
|
||||||
|
intent.putExtra("KEY", password);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish();
|
finish();
|
||||||
|
|
||||||
@ -117,6 +125,15 @@ 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){
|
private String genKeyHash(String hashedemail, String password){
|
||||||
byte[] salt2 = getSaltForUser(hashedemail, true);
|
byte[] salt2 = getSaltForUser(hashedemail, true);
|
||||||
return Utility.hashCredential(password, salt2, 5000);
|
return Utility.hashCredential(password, salt2, 5000);
|
||||||
@ -136,4 +153,9 @@ public class Login extends AppCompatActivity {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getSalt2(String hashedEmail){
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE);
|
||||||
|
return sharedPreferences.getString("salt_2_" + hashedEmail, "err");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -3,7 +3,6 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
@ -15,71 +14,80 @@ import android.widget.Toast;
|
|||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.security.InvalidKeyException;
|
||||||
import java.io.OutputStream;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.SecureRandom;
|
import java.security.spec.KeySpec;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
private CryptoManager cryptoManager;
|
|
||||||
|
|
||||||
Button buttonLogout, buttonChangePassword, buttonAddNewNote;
|
Button buttonLogout, buttonChangePassword, buttonAddNewNote;
|
||||||
private static final String SHARED_NAME_CREDENTIALS = "Credentials";
|
private static final String SHARED_NAME_CREDENTIALS = "Credentials";
|
||||||
private static final String SHARED_NOTES_NAME = "Notes";
|
private static final String SHARED_NAME_NOTES = "Notes";
|
||||||
private static String HASHED_EMAIL = "";
|
private static String HASHED_EMAIL = "";
|
||||||
private static String KEY_HASH = "";
|
private static String KEY = "";
|
||||||
private List<Note> noteList;
|
private List<Note> noteList;
|
||||||
private LinearLayout notesContainer;
|
private LinearLayout notesContainer;
|
||||||
|
|
||||||
private static final String ALGORITHM = "AES";
|
|
||||||
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
||||||
try {
|
|
||||||
cryptoManager = new CryptoManager();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace(); // Handle exceptions according to your needs
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
String current_username_hashed = intent.getStringExtra("CURRENT_USER_EMAIL_HASH");
|
String current_username_hashed = intent.getStringExtra("CURRENT_USER_EMAIL_HASH");
|
||||||
HASHED_EMAIL = current_username_hashed;
|
HASHED_EMAIL = current_username_hashed;
|
||||||
KEY_HASH = intent.getStringExtra("KEY_HASH");
|
KEY = intent.getStringExtra("KEY");
|
||||||
|
|
||||||
notesContainer = findViewById(R.id.notesContainer);
|
notesContainer = findViewById(R.id.notesContainer);
|
||||||
noteList = new ArrayList<>();
|
noteList = new ArrayList<>();
|
||||||
loadNotesFromPreferencesToList();
|
try {
|
||||||
|
loadNotesFromPreferencesToList();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
displayNotes();
|
displayNotes();
|
||||||
|
|
||||||
buttonLogout = findViewById(R.id.btn_logout);
|
buttonLogout = findViewById(R.id.btn_logout);
|
||||||
buttonChangePassword = findViewById(R.id.btn_change_password);
|
buttonChangePassword = findViewById(R.id.btn_change_password);
|
||||||
buttonAddNewNote = findViewById(R.id.btn_add_note);
|
buttonAddNewNote = findViewById(R.id.btn_add_note);
|
||||||
|
|
||||||
Log.i("KURWAAAAAAAAAAAAAAAAA", KEY_HASH);
|
|
||||||
|
|
||||||
buttonLogout.setOnClickListener(view -> logOut());
|
buttonLogout.setOnClickListener(view -> logOut());
|
||||||
|
|
||||||
buttonChangePassword.setOnClickListener(view -> showPasswordChangeDialog(current_username_hashed));
|
buttonChangePassword.setOnClickListener(view -> showPasswordChangeDialog(current_username_hashed));
|
||||||
|
|
||||||
buttonAddNewNote.setOnClickListener(view -> showAddNewNoteDialog());
|
buttonAddNewNote.setOnClickListener(view -> showAddNewNoteDialog());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -127,77 +135,36 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newPassword.equals(confirmPassword)) {
|
if (newPassword.equals(confirmPassword)) {
|
||||||
updatePassword(hashedEmail, newPassword);
|
try {
|
||||||
|
updatePassword(hashedEmail, newPassword);
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
Toast.makeText(MainActivity.this, "Password Changed", Toast.LENGTH_SHORT).show();
|
Toast.makeText(MainActivity.this, "Password Changed", Toast.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(MainActivity.this, "New passwords don't match!", Toast.LENGTH_SHORT).show();
|
Toast.makeText(MainActivity.this, "New passwords don't match!", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up the negative (Cancel) button
|
|
||||||
builder.setNegativeButton("Cancel", (dialogInterface, i) -> dialogInterface.dismiss());
|
builder.setNegativeButton("Cancel", (dialogInterface, i) -> dialogInterface.dismiss());
|
||||||
|
|
||||||
// Create and show the AlertDialog
|
|
||||||
AlertDialog alertDialog = builder.create();
|
AlertDialog alertDialog = builder.create();
|
||||||
alertDialog.show();
|
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 = Utility.generateSalt();
|
|
||||||
String newSaltString = Base64.getEncoder().encodeToString(newSalt);
|
|
||||||
editor.putString("salt_" + hashedEmail, newSaltString);
|
|
||||||
|
|
||||||
String hashedNewPassword = Utility.hashCredential(newPassword, newSalt, 1000);
|
|
||||||
editor.putString("user_" + hashedEmail, hashedNewPassword);
|
|
||||||
editor.apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean validateOldPassword(String hashedEmail, String oldPassword){
|
|
||||||
byte[] salt = getSaltForUser(hashedEmail, false);
|
|
||||||
String hashedOldPassword = Utility.hashCredential(oldPassword, salt, 1000);
|
|
||||||
String hashedCorrectPassword = getPasswordFromShared(hashedEmail);
|
|
||||||
|
|
||||||
assert hashedOldPassword != null;
|
|
||||||
return hashedOldPassword.equals(hashedCorrectPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] getSaltForUser(String hashedEmail, boolean salt2){
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
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 void showAddNewNoteDialog(){
|
private void showAddNewNoteDialog(){
|
||||||
LayoutInflater inflater = getLayoutInflater();
|
LayoutInflater inflater = getLayoutInflater();
|
||||||
@ -220,7 +187,23 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
noteList.add(note);
|
noteList.add(note);
|
||||||
|
|
||||||
saveNotesToPreferences("add");
|
try {
|
||||||
|
saveNotesToPreferences("add");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
createNoteView(note);
|
createNoteView(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,14 +234,46 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
String content = noteContentEditText.getText().toString();
|
String content = noteContentEditText.getText().toString();
|
||||||
|
|
||||||
if (!title.isEmpty() && !content.isEmpty()){
|
if (!title.isEmpty() && !content.isEmpty()){
|
||||||
deleteNoteAndRefresh(note);
|
try {
|
||||||
|
deleteNoteAndRefresh(note);
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
note.setTitle(title);
|
note.setTitle(title);
|
||||||
note.setContent(content);
|
note.setContent(content);
|
||||||
|
|
||||||
noteList.add(note);
|
noteList.add(note);
|
||||||
|
|
||||||
saveNotesToPreferences("add");
|
try {
|
||||||
|
saveNotesToPreferences("add");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
createNoteView(note);
|
createNoteView(note);
|
||||||
}else {
|
}else {
|
||||||
Toast.makeText(MainActivity.this, "Enter title and content!", Toast.LENGTH_SHORT).show();
|
Toast.makeText(MainActivity.this, "Enter title and content!", Toast.LENGTH_SHORT).show();
|
||||||
@ -274,8 +289,94 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void saveNotesToPreferences(String mode){
|
private void showDeleteDialog(final Note note){
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NOTES_NAME, MODE_PRIVATE);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setTitle("Delete this note");
|
||||||
|
builder.setMessage("Are you sure you want to delete it?");
|
||||||
|
builder.setPositiveButton("Delete", (dialogInterface, i) -> {
|
||||||
|
try {
|
||||||
|
deleteNoteAndRefresh(note);
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton("Cancel", null);
|
||||||
|
builder.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) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, InvalidKeySpecException, BadPaddingException, InvalidKeyException {
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
|
||||||
|
byte[] newSalt = Utility.generateSalt();
|
||||||
|
String newSaltString = Base64.getEncoder().encodeToString(newSalt);
|
||||||
|
editor.putString("salt_" + hashedEmail, newSaltString);
|
||||||
|
|
||||||
|
String hashedNewPassword = Utility.hashCredential(newPassword, newSalt, 1000);
|
||||||
|
editor.putString("user_" + hashedEmail, hashedNewPassword);
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
KEY = newPassword;
|
||||||
|
saveNotesToPreferences("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateOldPassword(String hashedEmail, String oldPassword){
|
||||||
|
byte[] salt = getSaltForUser(hashedEmail, false);
|
||||||
|
String hashedOldPassword = Utility.hashCredential(oldPassword, salt, 1000);
|
||||||
|
String hashedCorrectPassword = gerPasswrodHashFromShared(hashedEmail);
|
||||||
|
|
||||||
|
assert hashedOldPassword != null;
|
||||||
|
return hashedOldPassword.equals(hashedCorrectPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getSaltForUser(String hashedEmail, boolean salt2){
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
return Base64.getDecoder().decode(saltFromData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String gerPasswrodHashFromShared(String hashedEmail){
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_CREDENTIALS, MODE_PRIVATE);
|
||||||
|
return sharedPreferences.getString("user_" + hashedEmail, "err");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void saveNotesToPreferences(String mode) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_NOTES, MODE_PRIVATE);
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
if (mode.equals("del")){
|
if (mode.equals("del")){
|
||||||
int noteCount = sharedPreferences.getInt("notecount_"+HASHED_EMAIL, 0);
|
int noteCount = sharedPreferences.getInt("notecount_"+HASHED_EMAIL, 0);
|
||||||
@ -288,7 +389,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
editor.putInt("notecount_" + HASHED_EMAIL, noteList.size());
|
editor.putInt("notecount_" + HASHED_EMAIL, noteList.size());
|
||||||
for(int i=0; i<noteList.size(); i++){
|
for(int i=0; i<noteList.size(); i++){
|
||||||
Note note = noteList.get(i);
|
Note note = noteList.get(i);
|
||||||
editor.putString(i + "_title_" + HASHED_EMAIL, encryptCesar(note.getTitle(), 2));
|
editor.putString(i + "_title_" + HASHED_EMAIL, encrypt("AES/CBC/PKCS5Padding", note.getTitle(), getKeyFromPassword(KEY, getSaltForUser(HASHED_EMAIL, true)), generateIv()));
|
||||||
editor.putString(i + "_content_" + HASHED_EMAIL, note.getContent());
|
editor.putString(i + "_content_" + HASHED_EMAIL, note.getContent());
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -296,9 +397,18 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SecretKey getKeyFromPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||||
|
|
||||||
private void loadNotesFromPreferencesToList(){
|
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NOTES_NAME, MODE_PRIVATE);
|
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
|
||||||
|
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
|
||||||
|
|
||||||
|
return secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void loadNotesFromPreferencesToList() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_NAME_NOTES, MODE_PRIVATE);
|
||||||
int noteCount = sharedPreferences.getInt("notecount_" + HASHED_EMAIL, 0);
|
int noteCount = sharedPreferences.getInt("notecount_" + HASHED_EMAIL, 0);
|
||||||
|
|
||||||
for(int i=0; i<noteCount; i++){
|
for(int i=0; i<noteCount; i++){
|
||||||
@ -306,13 +416,44 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
String content = sharedPreferences.getString(i + "_content_" + HASHED_EMAIL, "");
|
String content = sharedPreferences.getString(i + "_content_" + HASHED_EMAIL, "");
|
||||||
|
|
||||||
Note note = new Note();
|
Note note = new Note();
|
||||||
note.setTitle(decryptCesar(title, 2));
|
note.setTitle(decrypt("AES/CBC/PKCS5Padding", title, getKeyFromPassword(KEY, getSaltForUser(HASHED_EMAIL, true)), generateIv()) );
|
||||||
note.setContent(content);
|
note.setContent(content);
|
||||||
|
|
||||||
noteList.add(note);
|
noteList.add(note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final byte[] FIXED_IV = {
|
||||||
|
0x01, 0x02, 0x03, 0x04,
|
||||||
|
0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0x0A, 0x0B, 0x0C,
|
||||||
|
0x0D, 0x0E, 0x0F, 0x10
|
||||||
|
};
|
||||||
|
|
||||||
|
public static IvParameterSpec generateIv() {
|
||||||
|
return new IvParameterSpec(Arrays.copyOf(FIXED_IV, FIXED_IV.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encrypt(String algorithm, String input, SecretKey key, IvParameterSpec iv) throws
|
||||||
|
NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,
|
||||||
|
BadPaddingException, IllegalBlockSizeException {
|
||||||
|
|
||||||
|
Cipher cipher = Cipher.getInstance(algorithm);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
|
||||||
|
byte[] cipherText = cipher.doFinal(input.getBytes());
|
||||||
|
return Base64.getEncoder().encodeToString(cipherText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String decrypt(String algorithm, String cipherText, SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException,
|
||||||
|
InvalidAlgorithmParameterException, InvalidKeyException,
|
||||||
|
BadPaddingException, IllegalBlockSizeException{
|
||||||
|
|
||||||
|
Cipher cipher = Cipher.getInstance(algorithm);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, key, iv);
|
||||||
|
byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));
|
||||||
|
return new String(plainText);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void createNoteView(final Note note){
|
private void createNoteView(final Note note){
|
||||||
View noteView = getLayoutInflater().inflate(R.layout.note_item, null);
|
View noteView = getLayoutInflater().inflate(R.layout.note_item, null);
|
||||||
@ -323,31 +464,19 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
noteTitleTextView.setText(note.getTitle());
|
noteTitleTextView.setText(note.getTitle());
|
||||||
noteContentTextView.setText(note.getContent());
|
noteContentTextView.setText(note.getContent());
|
||||||
|
|
||||||
deleteNoteDutton.setOnClickListener(view -> {
|
deleteNoteDutton.setOnClickListener(view -> showDeleteDialog(note));
|
||||||
showDeleteDialog(note);
|
|
||||||
});
|
|
||||||
|
|
||||||
noteView.setOnLongClickListener(new View.OnLongClickListener() {
|
noteView.setOnLongClickListener(view -> {
|
||||||
@Override
|
showEditNoteDialog(note);
|
||||||
public boolean onLongClick(View view) {
|
return true;
|
||||||
showEditNoteDialog(note);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
notesContainer.addView(noteView);
|
notesContainer.addView(noteView);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDeleteDialog(final Note note){
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setTitle("Delete this note");
|
|
||||||
builder.setMessage("Are you sure you want to delete it?");
|
|
||||||
builder.setPositiveButton("Delete", (dialogInterface, i) -> deleteNoteAndRefresh(note));
|
|
||||||
builder.setNegativeButton("Cancel", null);
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteNoteAndRefresh(Note note){
|
|
||||||
|
private void deleteNoteAndRefresh(Note note) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, InvalidKeySpecException, BadPaddingException, InvalidKeyException {
|
||||||
noteList.remove(note);
|
noteList.remove(note);
|
||||||
saveNotesToPreferences("del");
|
saveNotesToPreferences("del");
|
||||||
refreshNotesView();
|
refreshNotesView();
|
||||||
@ -364,94 +493,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final byte[] CONSTANT_IV = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
|
|
||||||
|
|
||||||
// Function to encrypt a message using AES in CBC mode with a constant IV
|
|
||||||
public static String encrypt(String data, String key) {
|
|
||||||
try {
|
|
||||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
|
||||||
|
|
||||||
// Use the constant IV
|
|
||||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(CONSTANT_IV);
|
|
||||||
|
|
||||||
// Create a SecretKeySpec using the provided key
|
|
||||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
|
|
||||||
|
|
||||||
// Initialize the cipher for encryption
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
|
|
||||||
|
|
||||||
// Encrypt the data
|
|
||||||
byte[] encryptedBytes = cipher.doFinal(data.getBytes());
|
|
||||||
|
|
||||||
// Combine IV and encrypted data for later decryption
|
|
||||||
byte[] combined = new byte[CONSTANT_IV.length + encryptedBytes.length];
|
|
||||||
System.arraycopy(CONSTANT_IV, 0, combined, 0, CONSTANT_IV.length);
|
|
||||||
System.arraycopy(encryptedBytes, 0, combined, CONSTANT_IV.length, encryptedBytes.length);
|
|
||||||
|
|
||||||
// Base64 encode the result for easy storage and transmission
|
|
||||||
return Base64.getEncoder().encodeToString(combined);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to decrypt a message using AES in CBC mode with a constant IV
|
|
||||||
public static String decrypt(String encryptedData, String key) {
|
|
||||||
try {
|
|
||||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
|
||||||
|
|
||||||
// Decode the Base64-encoded input
|
|
||||||
byte[] combined = Base64.getDecoder().decode(encryptedData);
|
|
||||||
|
|
||||||
// Extract IV from the combined data
|
|
||||||
byte[] iv = new byte[CONSTANT_IV.length];
|
|
||||||
System.arraycopy(combined, 0, iv, 0, CONSTANT_IV.length);
|
|
||||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
|
|
||||||
|
|
||||||
// Create a SecretKeySpec using the provided key
|
|
||||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
|
|
||||||
|
|
||||||
// Initialize the cipher for decryption
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
|
|
||||||
|
|
||||||
// Decrypt the data
|
|
||||||
byte[] decryptedBytes = cipher.doFinal(combined, CONSTANT_IV.length, combined.length - CONSTANT_IV.length);
|
|
||||||
|
|
||||||
return new String(decryptedBytes);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to encrypt a message using Caesar Cipher
|
|
||||||
public static String encryptCesar(String message, int key) {
|
|
||||||
StringBuilder encryptedMessage = new StringBuilder();
|
|
||||||
|
|
||||||
for (char character : message.toCharArray()) {
|
|
||||||
if (Character.isLetter(character)) {
|
|
||||||
char base = Character.isUpperCase(character) ? 'A' : 'a';
|
|
||||||
char encryptedChar = (char) ((character - base + key) % 26 + base);
|
|
||||||
encryptedMessage.append(encryptedChar);
|
|
||||||
} else {
|
|
||||||
// Keep non-alphabetic characters unchanged
|
|
||||||
encryptedMessage.append(character);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return encryptedMessage.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to decrypt a message using Caesar Cipher with a key
|
|
||||||
public static String decryptCesar(String encryptedMessage, int key) {
|
|
||||||
return encryptCesar(encryptedMessage, 26 - (key % 26)); // Decryption is equivalent to shifting in the opposite direction
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user