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");
}
Related
I'm looking a way to do something like this. I don't know how to call it, so i don't know if it exist or how to find it. Some keyword would be welcome :)
String var_1 = "user data";
String fix_1 = "supply data";
String mix = mixer(var_1,fix_1);
// mix = " something fully random "
String var_2 = "user data changed";
String fix_2 = fixer(var_2,mix);
And mix == mixer(var_2, fix_2);
So to resume, I need to generate a random data from 2 variables. 1 is variable from user and 1 is supply by me.
First time , I generate the data with these 2 variables with one function.
Then, if the user data change, with another function, I compute the new supply data with the first result and the new user data. And if I use again the computed data and the new user data, I must obtain the same data computed the first time.
Is there something to do that ? Like some cipher technique or so?
Thanks for Intel.
In fact there is something like this already which may satisfy you needs. In fact you know this function too. It's the good old XOR. And yes, it is used in crypto a lot. In fact it's the core idea of the stream ciphers and the One Time Pad.
It goes like this:
Assume you have a byte array of length n called var_1.
Assume you have a random value fix_1 of the same length.
If you do var_1 XOR fix_1 you get mix.
If you do mix XOR fix_1 you get var_1 again. (Basic math: fix_1 XOR fix_1 equals chain of zero value bytes and var_1 XOR zero bytes = var_1.
This whole thing will be as random and secure as random and secret fix_1 remains. If one of the values is not random the approach is not secure at all.
So following the idea of User253751 in comment, I was able to do it.
Step:
generate the private constant key => privateKey = encrypt(publicKey, Password_1) (the first public key is random )
if password change, generate a new public key by decoding the private constant key with password_2 => publicKey_Updated = decrypt(privateKey, Password_2)
Check if the new public key is valid : privateKey_Rebuild = encrypt(publicKey_Updated, Password_2) ====> if everything is ok, privateKey == privateKey_Rebuild.
---> I test it only with a low cryptage i use just for obfuscation, but it should work with symmetric key too. I'm not sur about Asymetric key, because to make this work, you need a crypting protocol who always give you the same crypted data with the same input. And RSA do not gave you the same crypted data even with the same input.
Here my code (not a copy/paste snippet beacause it use my own library), but you can catch the idea easily with the function name.
KeyObfusc publicKey_1 = KeyObfusc.fromPassword("publicKey_1");
KeyObfusc password_1 = KeyObfusc.fromPassword("password_1");
Encoder encoder_1 = new Encoder(password_1, CipherFormat.HEX);
Decoder decoder_1 = new Decoder(password_1, CipherFormat.HEX);
byte[] privateKey = encoder_1.toBytes(publicKey_1.getEncoded());
byte[] publicKey_1_Rebuild = decoder_1.fromBytesToBytes(privateKey);
LogDelay.send("password_1 : " + BytesTo.stringHex(password_1.getEncoded()));
LogDelay.send("publicKey_1 : " + BytesTo.stringHex(publicKey_1.getEncoded()));
LogDelay.send("privateKey : " + BytesTo.stringHex(privateKey));
LogDelay.send("publicKey_1 Rebuild : " + Arrays.equals(publicKey_1.getEncoded(), publicKey_1_Rebuild) +
" " + BytesTo.stringHex(publicKey_1_Rebuild));
LogDelay.send();
KeyObfusc password_2 = KeyObfusc.fromPassword("password_2");
Encoder encoder_2 = new Encoder(password_2, CipherFormat.HEX);
Decoder decoder_2 = new Decoder(password_2, CipherFormat.HEX);
byte[] publicKey_2 = decoder_2.fromBytesToBytes(privateKey);
byte[] privateKey_Rebuild = encoder_2.toBytes(publicKey_2);
LogDelay.send("password_2 : " + BytesTo.stringHex(password_2.getEncoded()));
LogDelay.send("publicKey_2 : " + BytesTo.stringHex(publicKey_2));
LogDelay.send("privateKey Rebuild: " + Arrays.equals(privateKey, privateKey_Rebuild) +
" " + BytesTo.stringHex(privateKey_Rebuild));
LogDelay.send();
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()
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
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?
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.