I'm running a first-time setup where a user creates a password and it's stored in sharedpreferences (I understand the implications of this) the only problem is that when I run the password entered by the user on the login page, it always comes to a different password and therefore won't validate.
AFAIK I'm hashing the passwords correctly according to this article and I'm open to suggestions but it's driving me crazy as I've debugged the app in every place I could and I just can't see the error
First-time setup code
package com.example.myapplication;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class FirstTimeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//reset login
SharedPreferences pref = getApplicationContext().getSharedPreferences("DocStorage Preferences", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.remove("isFirstTime");
editor.remove("PasswordHash");
editor.commit();
//message view box
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void attemptFirstTimeSetup(View v) throws InvalidKeySpecException, NoSuchAlgorithmException {
if (((CheckBox)findViewById(R.id.riskCheckBox)).isChecked()){
if (TextUtils.isEmpty(((EditText)findViewById(R.id.SetPassword)).getText().toString()))
{
((EditText)findViewById(R.id.SetPassword)).setError("Can't be blank!");
}
else {
String passwordtopass = ((EditText)findViewById(R.id.SetPassword)).getText().toString();
String hashedpassword = PBKDF2_Encrypt(passwordtopass);
SharedPreferences pref = getApplicationContext().getSharedPreferences("DocStorage Preferences", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putString("isFirstTime","No");
editor.putString("PasswordHash",hashedpassword);
editor.commit();
Intent backToMain = new Intent(this, LoginActivity.class);
startActivity(backToMain);
}
}
else {
Toast.makeText(this, "Please check read and check the checkbox before continuing!", Toast.LENGTH_SHORT).show();
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public String PBKDF2_Encrypt(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
//salting
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
//
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = factory.generateSecret(spec).getEncoded();
String finalString = new String(hash, StandardCharsets.UTF_8);
return finalString;
}
}
login activity code
package com.example.myapplication;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
setTitle("Login page");
SharedPreferences pref = getApplicationContext().getSharedPreferences("DocStorage Preferences", MODE_PRIVATE);
String firstTimeCheck = pref.getString("isFirstTime", "Yes");
if (firstTimeCheck.equals("Yes")) {
Intent firstTimeActivityIntent = new Intent(this, FirstTimeActivity.class);
startActivity(firstTimeActivityIntent);
} else {}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public void AttemptLogin(View v) throws InvalidKeySpecException, NoSuchAlgorithmException {
SharedPreferences pref = getApplicationContext().getSharedPreferences("DocStorage Preferences", MODE_PRIVATE);
String SavedPasswordHash = pref.getString("PasswordHash", "nothing here yet!");
String passwordtopass2 = ((EditText)findViewById(R.id.passwordtext)).getText().toString();
String loginPassword = PBKDF2_Encrypt(passwordtopass2);
if (TextUtils.isEmpty(((EditText) findViewById(R.id.passwordtext)).getText().toString())) {
((EditText) findViewById(R.id.passwordtext)).setError("Can't be blank!");
}
else {
if (loginPassword.equals(SavedPasswordHash)) {
Toast.makeText(this, "Password is correct!", Toast.LENGTH_SHORT).show();
Intent forwardToMain = new Intent(this, MainActivity.class);
startActivity(forwardToMain);
} else {
Toast.makeText(this, "Password is incorrect!", Toast.LENGTH_SHORT).show();
}
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public String PBKDF2_Encrypt(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
//salting
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
//
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = factory.generateSecret(spec).getEncoded();
String finalString = new String(hash, StandardCharsets.UTF_8);
return finalString;
}
}
For my specific part. Each time it was run random.nextBytes() code was run which was randomising the output, meaning that they never match on input validation. Removing it worked.
random.nextBytes(salt);