What is the best way to hash passwords to SHA1 in a mobile java application using SQLite?
Below is how the data is inserted into the database. I want the password to be hashed, preferably in SHA1. It will be used to Login on another page aswell so do i need to do a similar process in that java class?
SignUp.Java
public void onSignUpClick(View v) {
if (v.getId() == R.id.Bsignupbutton) {
EditText name = (EditText) findViewById(R.id.TFname);
EditText email = (EditText) findViewById(R.id.TFemail);
EditText uname = (EditText) findViewById(R.id.TFuname);
EditText pass1 = (EditText) findViewById(R.id.TFpass1);
EditText pass2 = (EditText) findViewById(R.id.TFpass2);
String namestr = name.getText().toString();
String emailstr = email.getText().toString();
String unamestr = uname.getText().toString();
String pass1str = pass1.getText().toString();
String pass2str = pass2.getText().toString();
if (!pass1str.equals(pass2str)) {
//popup msg
Toast pass = Toast.makeText(SignUp.this, "Passwords don't match!", Toast.LENGTH_SHORT);
pass.show();
} else {
if (name.getText().toString().length() == 0) {
name.setError("Name Required");
} else if (!email.getText().toString().matches("[a-zA-Z]{1}\\.[a-zA-Z]*[0-9]{4}#student\\.leedsbeckett\\.ac\\.uk")) {
email.setError("Incorrect Email Format");
} else if (!uname.getText().toString().matches("[cC][0-9]{7}")) {
uname.setError("Incorrect ID Format");
} else if (!pass1.getText().toString().matches("(?=.*[\\d])(?=.*[a-z])(?=.*[A-Z]).{8,}")) {
pass1.setError("Incorrect Password Format");
} else {
//insert the details in database
Contact c = new Contact();
c.setName(namestr);
c.setEmail(emailstr);
c.setUname(unamestr);
c.setPass(pass1str);
helper.insertContact(c);
Toast pass = Toast.makeText(SignUp.this, "User Registered", Toast.LENGTH_LONG);
pass.show();
Intent i = new Intent(SignUp.this, com.example.oliver.beckettreg.MainActivity.class);
startActivity(i);
}
}
}
}
You should not invent your own hashing and salting mechanisms.
Look at JBCrypt--a Java implementation of BCrypt:
http://www.mindrot.org/projects/jBCrypt/
The API is very simple:
// Hash a password for the first time
String hashed = BCrypt.hashpw(password, BCrypt.gensalt());
// gensalt's log_rounds parameter determines the complexity
// the work factor is 2**log_rounds, and the default is 10
String hashed = BCrypt.hashpw(password, BCrypt.gensalt(12));
// Check that an unencrypted password matches one that has
// previously been hashed
if (BCrypt.checkpw(candidate, hashed))
System.out.println("It matches");
else
System.out.println("It does not match");
Take a use in Apache Commons Codec library.
https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/DigestUtils.html#sha1Hex(java.lang.String)
final String SALT = "any strange string that you like";
String mySha1String = DigestUtils.sha1Hex(myString + SALT);
For database purposes, you should not change the salt, so, the sha1 will not be the same to the same string as input. Another thing, will not be better use SHA-3? A best standard?
It will be used to Login on another page aswell so do i need to do a similar process in that java class?
Yes, you would have to replicate the hashing procedure when checking if a password is valid or not. The point of passwords is that they are stored in your database using a one way hash (with salt) so that if someone obtains maliciously obtains the hash of a password, there is no way for them to get the original password from the hash (in theory). In this way, password hashing is somewhat different than cryptography since once the original password is hashed (i.e encrypted), you don't really care about the original value of the password, meaning there is no need to have a hashing algorithm which can be reversed (decrypted) usually leading to stronger ciphers.
To more explicitly answer your question, in your Login Class (or wherever you do your password checking), once the user gives you their password, you will need to hash it again (using the same algorithm and the same salt) and test to see if this hash matches the password hash stored in the DB.
As for the hashing itself, as Jason pointed out, you shouldn't implement your own version of the algorithm since you're surely to make mistakes due to the complexity of such an algorithm. You should look for some packages which implement what you need.
I suggest to use jBCrypt
jBCrypt is a Java™ implementation of OpenBSD's Blowfish password hashing code
Check it from here http://www.mindrot.org/projects/jBCrypt/
and this one : http://techblog.bozho.net/bcrypt-salt-its-the-bare-minimum/
For more info : How can I hash a password in Java?
Related
MessageDigest alg = MessageDigest.getInstance("MD5");
alg.reset();
alg.update(password.getBytes());
byte[] digest = alg.digest();
StringBuffer hashedpasswd = new StringBuffer();
String hx;
for (int i=0;i<digest.length;i++){
hx = Integer.toHexString(0xFF & digest[i]);
//0x03 is equal to 0x3, but we need 0x03 for our md5sum
if(hx.length() == 1){hx = "0" + hx;}
hashedpasswd.append(hx);
}
I followed the above code for password encryption. But when login the password checks with database password and login fails as the db entry is encrypted password. How will i check the database's encrypted password with original password on login?
While checking with the database, Hash the password you entered with the same algorithm as the one you used to save it in the Data Base. That's how Hashing works. You don't need to "Decrypt" the password from the database, that's not possible. You would rather want to Hash the password you're entering and check whether both the hash values (i.e. the one in db and the one you just hashed) are equal. That is the entire concept of hashing. You can't "DeHash" something. You can only hash the coming data and compare it with previously hashed value.
encrypt(user_entered_password) == getPasswordFromDatabase()
I'm very new to this Android, so I'm very sorry if this question will make you laugh.
Recently I'm trying an Android tutorial about 'Creating Login Screen With SQLite'. I'm successfully creating that Login along with Register and with SQLite DB. What I want to know is how to change the Text Input from Email to Username.
I have searched the code for how to changing the validation from Email to Username but still don't get that.
FYI, I have created the Username table in the DB.
public boolean validate() {
boolean valid = false;
// Get values from EditText fields
String Email = editTextUsername.getText().toString();
String Password = editTextPassword.getText().toString();
// Handling validation for Email Address
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(Email).matches()){
valid = false;
textInputLayoutUsername.setError("Input Correct Username");
} else {
valid = true;
textInputLayoutUsername.setError(null);
}
}
Here is my login screen.
I had to change the text from Email to Username on that EditText. But when I run it, the EditText always validate the email. I think there's something to change in this line.
!android.util.Patterns.EMAIL_ADDRESS.matcher(Email).matches()
Thanks before for all the help, I really appreciate it.
Your current implementation is validating the input from the editTextUsername and trying to validate if the input is a valid email address. If you do not want that, just remove the validation for this specific view in your code like the following.
public boolean validate() {
boolean valid = false;
//Get values from EditText fields
String userName = editTextUsername.getText().toString();
String Password = editTextPassword.getText().toString();
// Handle the validation for the user name.
// Let us assume, you just want to validate that the user has put something as a user name
if(userName.length() > 0) {
valid = true;
textInputLayoutUsername.setError(null);
} else {
valid = false;
textInputLayoutUsername.setError("Please provide the user name.");
}
}
You can always change the logic of your validation. I just showed an example. I hope that helps!
Just use plain text field and use regular express in backend code ( [A-Za-z0-9]* ) to validate your input.
//it's saying if email contains alpnum char and ._- of length min 3 i.e >=3 then its true
if(Email.matches(^[a-zA-Z0-9._-]{3,}$)) {
// valid input code
} else {
// invalid input code
}
please check the blow code.
public boolean validate() {
//Get values from EditText fields
String userName = editTextUsername.getText().toString().trim();
String Password = editTextPassword.getText().toString().trim();
if (userName.isEmpty()) {
//set error message
return false;
} else if (Password.isEmpty()) {
//set error message
return false;
} else if (Password.length()<6 || Password.length()>15) {
// set error message
return false;
}
return true;
}
i am having issues with hashing passwords in java so when i try to log in and write my password i want to get that written password hash it using $2y$ as the same format in my database because that it what the FOSBundle is using as encryption methode the BCrypt but instead i get a hashed password which starts with $2a$ instead of $2y$ so i can't compare them is there anyway to change that $2a$ hash into $2y$ hash ?
My function :
public void CheckLogin(String username,String password) throws SQLException{
String requete = "Select * from user WHERE username ='"+username+"';";
ste = con.createStatement();
res = ste.executeQuery(requete);
while(res.next()) {
if (res.getString(2).equals(username)) {
System.out.println("Password FOS ="+res.getString(8));
String hashed2 = BCrypt.hashpw(password, BCrypt.gensalt(12));
hashed2 = "$2y$" + hashed2.substring(4);
System.out.println("HASHED PASSWORD =" + hashed2);
if (BCrypt.checkpw(res.getString(8),hashed2)) {
System.out.println("It matches");
} else {
System.out.println("It does not match");
}
}
}
}
he can't find the user i am looking for because the hashed password i passed to him " hashed2 " is not the same in my database because in my database it stars with $2y$ and this hash methode give a $2a$ hashed password
Based on BCrypt wiki the prefix $2a$, $2y$ and $2b$ are used to store the algorithm version. Although $2y$ fixed a bug in previous implementation this fix seems to be limited to PHP:
In June 2011, a bug was discovered in crypt_blowfish, a PHP implementation of BCrypt.
...
Nobody else, including canonical OpenBSD, adopted the idea of 2x/2y.
This version marker change was limited to crypt_blowfish.
Since it looks like you are using JBCrypt you will always get $2a$ version. Latest version 0.4 definitely uses it.
You can try comparing the hashed password without the version prefix. I never had to compare PHP and Java BCrypt implementation so I've no idea if this will work. In your code you can do following:
// JBCrypt requires version $2a, change the prefix
String hashed2 = "$2a" + res.getString(8).substring(3);
if (BCrypt.checkpw(password, hashed2)) {
System.out.println("It matches");
}
It's my first time dealing with Password hashing in a web application.
I used https://www.codeproject.com/articles/704865/salted-password-hashing-doing-it-right for theory and copied a sample from https://github.com/defuse/password-hashing.
In my understanding, the salt should be unique for every account. So my question would be:
why is the salt generated in this method:
public static String createHash(char[] password)
throws CannotPerformOperationException
{
// Generate a random salt
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_BYTE_SIZE];
random.nextBytes(salt);
// Hash the password
byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
int hashSize = hash.length;
// format: algorithm:iterations:hashSize:salt:hash
String parts = "sha1:" +
PBKDF2_ITERATIONS +
":" + hashSize +
":" +
toBase64(salt) +
":" +
toBase64(hash);
return parts;
}
What I would Need is a function which stores a hashed password and the used salt from a database. How can I retrieve the used salt from here?
System.out.println(salt);
Always writes
[B#29453f44
In the console. Why is this the case? And what data type would I Need to store the salt in the mysql database? Or do I have the wrong Approach?
If I understand your questions correctly then:
In my understanding, the salt should be unique for every account.
byte[] salt = new byte[SALT_BYTE_SIZE];
random.nextBytes(salt);
Generates a random salt, which makes it unique.
You could also use use the ID for the user from the database or something else unique, but a randomly generated salt is also unique, since afterall, for each new user a new salt is randomly generated.
This salt is then in your code concatenated together with the hash, the hashSize, the algorithm and the number of iterations into parts
// format: algorithm:iterations:hashSize:salt:hash
String parts = "sha1:" +
PBKDF2_ITERATIONS +
":" + hashSize +
":" +
toBase64(salt) +
":" +
toBase64(hash);
return parts;
Often you know the lengths (byte size) of the different parts in parts and can thus extract the part you need. In your case you have even added a : as a separator which makes it even simpler to extract the part you are interested in.
And what data type would I Need to store the salt in the mysql database?
Once you have gotten your parts, this is what you save in the database as text (varchar or char). You do not separate it and store salt separately. Just mash it all in together.
When a user then wants to sign in, they provide a password. Now you fetch parts for the user from the database, you extract the salt, number of iterations and so on from parts, since afterall, you know exactly how it is concatenated. Then you use that information to hash the inputted password from the user again. Now you compare the new hash, with the old hash. If they are the same, well, then the user gave the correct password, if not, he didn't.
Always writes [B#29453f44 In the console.
As #JonSkeet said, the answer is given in Converting String to Sha-256 Hash
String[] userAttrList = {"cn", "sn","pwdHistory};
SearchResult searchResult = lc.search(baseDN, SearchScope.SUB, searchFilter, userAttrList);
List<SearchResultEntry> result = searchResult.getSearchEntries();
for (SearchResultEntry sre : result) {
value = sre.getAttributeValue("pwdHistory");
System.out.println(sre.getAttributeValue("pwdHistory"));
return value; }
I'm using unboundidsdk to get the user's details from LDAP.
Attribute(name=cn, values={'Test User'}),
Attribute(name=sn, values={'User'}),
Attribute(name=pwdHistory, values={'20150902093503Z#2.5.4.35#32#{AES256}33243DD8jnwa8a8asbaaa==', '20150903091818Z#2.5.4.35#32#{AES256}PJiYUi+ssasassasaasa==', '20150902090417Z#2.5.4.35#32#{AES256}asasasAAA222221211221=='})}, controls={})]
I get the password history in the LDAP default encrypted form.
Is there an API available to get it in a decrypted format?
get decrypted pwdHistory values
You can't, because they aren't encrypted is the first place. They are hashed.
Any system that allows you to retreive passwords in plaintext is ill-designed. OpenLDAP isn't one of them.