Hashing vulnerability - java

I want to add some security to my project so I added a password field. In, order to store the password I was going to use a txt and save it in there, to add a bit more security I used the below code to hash the password(theirs more than one password saved this way if that's important). This is just and example of how I have done the hashing, the actual program uses text files etc.
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println("Enter Password: ");
Scanner scanner = new Scanner(System.in);
String enteredPassword = scanner.nextLine();
String storedPassword = "�D�Ϛ-�UK�c�=�,�}��}��D��Zj>�m";
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(enteredPassword.getBytes());
String hashedString = new String(messageDigest.digest());
System.out.println(hashedString);
if(storedPassword.equals(hashedString)){
System.out.println("Passwords Match!");
}else{
System.out.println("Passwords Do Not Match!");
}
}
My question is am I doing this securely, besides decompiling my project and bypassing this feature is my project secure or can this method be exploited? Also, is there a way to secure a project against being decompiled and the code re-written to bypass security features?? Thank You

The approach itself is good; SHA-256 by itself is a strong, one-way hashing function. It cannot be "decrypted". But it's fast, thus allowing rapid brute-forcing of the password using a dictionary.
For better security you can slow things down with e.g. bcrypt or PBKDF2. Some 100ms will not be noticeable by the user, but makes brute-forcing impractical.
Here's an example with PBKDF2 using 100000 iterations of SHA-256. It also uses a random salt.
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec("my-secret-password".toCharArray(), salt, 100000, 256);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
System.out.printf("salt: %s%n", enc.encodeToString(salt));
System.out.printf("hash: %s%n", enc.encodeToString(hash));
Note: PBKDF2WithHmacSHA256 is available since Java 8.
Here's a more complete example:
private static final SecureRandom random = new SecureRandom();
/**
* One-way encrypts (hashes) the given password.
*
* #param saltpw the salt (will be generated when null)
* #param pw the password to encrypt
* #return encrypted salted password
*/
public static String encrypt(String saltpw, String pw) throws GeneralSecurityException {
byte[] salt;
if (saltpw == null) {
salt = new byte[16];
random.nextBytes(salt);
} else {
salt = Base64.getDecoder().decode(saltpw.replaceFirst("\\$.*", ""));
}
KeySpec spec = new PBEKeySpec(pw.toCharArray(), salt, 100000, 256);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
return enc.encodeToString(salt) + "$" + enc.encodeToString(hash);
}
public static void main(String[] args) throws Exception {
String enc = encrypt(null, "my-secret-password");
System.out.printf("enc : %s\n", enc);
String test1 = encrypt(enc, "my-secret-password");
System.out.printf("test 1: %s, valid: %b\n", test1, enc.equals(test1));
String test2 = encrypt(enc, "some-other-password");
System.out.printf("test 2: %s, valid: %b\n", test2, enc.equals(test2));
}
Prints:
enc : B5V6SjkjJpeOxvMAkPf7EA==$NNDA7o+Dpd+M+H99WVxY0B8adqVWJHZ+HIjgPxMljwo=
test 1: B5V6SjkjJpeOxvMAkPf7EA==$NNDA7o+Dpd+M+H99WVxY0B8adqVWJHZ+HIjgPxMljwo=, valid: true
test 2: B5V6SjkjJpeOxvMAkPf7EA==$4H1SpH8N+/jqU40G6RWb+ReHUB3C58iAaU4l39j+TV8=, valid: false
Notice how test 1 results in exactly the same encrypted string as the original password, and that test 2 (with a wrong password) doesn't. So that's how you can verify that the provided password is valid or not, by just comparing the hashes.

There is no way to prohibit decompiling of java.
But you can make it hard to understand the decompiled code if you use an obfuscator.
E.g. https://www.guardsquare.com/en/products/proguard
This changes all you method-, class-, variable- names to meaningless short names.
A side-effect is that your class file will shrink too.

Related

How do I compare salt with a generated password?

So I'm trying to compare my original password to a password that was salted. I know how to compare a hash password, I take the original password add hash to it and it works. However, I don't know how to compare the salt.
public static String saltPassword(String password) throws NoSuchAlgorithmException{
String salt = getSalt();
return password + salt;
}
public static String getSalt(){
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return Base64.getEncoder().encodeToString(saltBytes);
}
What do I have to do to compare the original password with this?
this is literally what my assignment says,
"Compare the generated password with the stored salt and hashed password".
You should also store the salt. Salt is used to prevenet generating the same hashed password when two user choose same password. something like the following codes can be used for saving password as hashedPassord and verifying entered password.It's not complete but can be used as a sample code.
private static void savePassword(String rawPassword) throws InvalidKeySpecException, NoSuchAlgorithmException {
byte[] salt = getSalt();
String hashedPassword = getHashedPassword(rawPassword, salt);
String encodedSalt = base64Encode(salt);
/* todo: store hashPassword and encodedSalt */
}
private static boolean verifyPassword(String rawPassword, String hashedPassword, String encodedSalt) throws InvalidKeySpecException, NoSuchAlgorithmException {
return Objects.equals(hashedPassword, getHashedPassword(rawPassword, base64Decode(encodedSalt)));
}
private static String getHashedPassword(String rawPassword, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(rawPassword.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = factory.generateSecret(spec).getEncoded();
return base64Encode(hash);
}
private static byte[] getSalt() {
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return saltBytes;
}
private static String base64Encode(byte[] src) {
return Base64.getEncoder().encodeToString(src);
}
private static byte[] base64Decode(String src) {
return Base64.getDecoder().decode(src);
}
Ok here is what i have. I would love to look up a stored password but my teacher is not doing it that way in her solution video
public static String saltPassword(String password) throws NoSuchAlgorithmException{
String salt = getSalt();
return hashPassword(password + salt);
}
public static String getSalt(){
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return Base64.getEncoder().encodeToString(saltBytes);
}
public static String generatePassword(){
String charSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-+!##$%";
String password = "";
int start = 0;
int stop = 0;
int minLength = 8;
for (int i = 0; i <= minLength; i++) {
// get a random character from the chars string
start = getRandomNumber(charSet.length());
stop = start + 1;
password += charSet.substring(start, stop);
}
return password;
}
private static int getRandomNumber(int maxValue){
double randomNumber;
randomNumber = Math.floor(Math.random() * maxValue);
return (int)randomNumber;
}
public static String hashPassword(String password)throws NoSuchAlgorithmException{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
byte[] mdArray = md.digest();
StringBuilder sb = new StringBuilder(mdArray.length * 2);
for (byte b : mdArray){
int v = b & 0xff;
if(v < 16){
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString();
}
Then to create it I am going to go
String newPassword = PasswordUtil.generatePassword();
String hashedPassword = "";
String saltedPassword = "";
try{
hashedPassword = PasswordUtil.hashPassword(newPassword);
}
catch(NoSuchAlgorithmException e){
System.out.println();
}
try{
saltedPassword = PasswordUtil.saltPassword(hashedPassword);
}
catch(NoSuchAlgorithmException e) {
System.out.println();
}
What happens next?
this is the hashed password:
50f99d2a635cc9bac7e001506789b55a7c603d93c89d362cc5d95ab257fc2666
and this is the hash with the salt
e954fbc2309cc359cd603effb6d0644947a3253110ad6c3b2416dd49168331a3
How do I compare salt with a generated password?
What do I have to do to compare the original password with this?
The answer is that you don't do either if these things.
To register the original password you do the following:
Obtain a salt1
Combine the original password with the salt
Hash that.
Store the salt and the hash.
You then discard the original password.
To check that a supplied password you do the following:
Lookup the stored hash and the corresponding salt that were created when registering; see above.
Combine the supplied password and salt in the same way as above.
Hash that as above.
Compare the resulting hash with the stored hash. If they are the same, then the supplied password is the correct password.
As you can see, you don't compare either the salt or the original password with anything.
But it is also essential that you use the same salt when generating the hashes for the original password and the password that you are checking. If you don't, the password check doesn't work.
1 - The salt is just a number or string. Ideally the salt values should be different. The purpose of the salt is to avoid a so-called "rainbow table" attack to recover the original password from a stolen (un-salted) password hash. If there are (say) a million possible salt values, then the bad guys need to generate a million different rainbow tables. Generating and storing many rainbow tables becomes impractical.

String to byte[] with a defined size

What i am trying to do is convert a String into a byte[] but i need the byte[] size to be 64 bytes always, independently of what string is on the input in order to be used with Realm encryption. However, after some research, I couldn't find anything similar, or is there any other way I can use a string as the Realm encryption?
This is my code:
String passphrase = "ASDYB982234235512";
byte[] key = passphrase.getBytes();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder()
.encryptionKey(key)
.build();
This is the error:
java.lang.IllegalArgumentException: The provided key must be 64 bytes. Yours was: 17
You want to use a Key Derivation Function to generate an encryption key from the user's passphrase. The simplest form of this is to add a salt to the user's passphrase and then feed it into SHA-2 to get a 256-bit hash, but ideally you want to use something like scrypt to make it harder to brute-force the passphrase.
Here https://android-developers.googleblog.com/2013/02/using-cryptography-to-store-credentials.html you can find the function you can use (I just changed the key size):
public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase
// computation time. You should select a value that causes computation
// to take >100ms.
final int iterations = 1000;
// Generate a 512-bit key
final int outputKeyLength = 512;
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
return secretKey;
}
And then use secretKey.getEncoded().
To generate salt:
final Random secureRandom = new SecureRandom();
byte[] salt = new byte[32];
secureRandom.nextBytes(salt);
Remember to save the salt and keep it somewhere (in Preferences for instance).
Try encoding the string using Base64.encode, i guess the output will be useful to you.
Or try using a string with 64 characters in it your current passphrase contains 17 characters

Symfony FOSUser Hash algorithm in java

hey everyone am trying to find out which algorithm of hash is used my symfony FOS User Bundle I've done some research , and it's mentioned that FOSUser Bundle default security config uses Sha512() and itirate it over 5000 times + salt then bas64 encoding i'm actually new with these hash algorithms ,however this is the algorithm in php
$password = 'toto';
$salt = '1234';
$salted = $password.'{'.$salt.'}';
$digest = hash('sha512', $salted, true);
for ($i=1; $i<5000; $i++) {
$digest = hash('sha512', $digest.$salted, true);
}
$encodedPassword = base64_encode($digest);
}
taking from this post How do I generate a SALT in Java for Salted-Hash?
since am not familiar with java hash libraries can anyone help me how to translated this code into Java !
The solution is to use a Java API that encode the password like the MessageDigestPasswordEncoder:
Generate a salt (lenght=43):
private static String generateSalt() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_SIZE];
random.nextBytes(salt);
String saltBase64_encoded=BaseEncoding.base64().encode(salt);
String saltPlusDot= saltBase64_encoded.replace("+",".");
return saltPlusDot.substring(0,saltPlusDot.length()-1);
}
BaseEncoding.base64() is a class in commons-codec api
concat: password + { + salt + }:
private static String mergePasswordAndSalt(String pass, String salt) {
if (salt == null) {
return salt;
}
String cg="{";String cd="}";
return pass+cg+salt+cd;
}
For each additional iteration: hash the concat of previous digest +
salt:
private static byte[] encodePassword(String password,String salt)
throws NoSuchAlgorithmException,UnsupportedEncodingException {
String mergedPasswordAndSalt =mergePasswordAndSalt(password, salt);
MessageDigest digester = MessageDigest.getInstance(ALGORITHM);
byte[] hash = digester.digest(mergedPasswordAndSalt .getBytes("UTF-8"));
for (int i = 1; i < ITERATIONS; ++i) {
hash = digester.digest(Bytes.concat(hash, mergedPasswordAndSalt.getBytes("UTF-8")));
}
return hash;
}
Bytes.concat(bytes ...) is a method in guava 19.0 api
This is the API in github FOSJcrypt
Symfony default setting for password encryption is Bcrypt this code mentioned in your security.yml config file
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 15
in my case i used a trick since all my password start with 13 am assuming that the salt equals to 13
so i tried translating it into java by using the java BCrypt library
public boolean checkPassword(String passwordText, String DbHash) {
boolean password_verified = false;
if (null == DbHash || !DbHash.startsWith("$2a$")) {
throw new java.lang.IllegalArgumentException("Invalid hash provided for comparison");
}
password_verified = BCrypt.checkpw(passwordText, DbHash);
return (password_verified);
}
passwordText you actual password , DbHash stored hash
This code check a password hash if password match or not
there's a trick symfony hashed password start with $2y$ so to make this work you need to need change $2y$ to $2a$
for exemple i have password with a hash value that is stored in my database
String passwordText = "admin";
String DbHash = "$2y$13$VVmaKXzaS2QWgU1S4I8h5eJgC/DduF2fXmnhvcynro004GCUAQfr2";
change this :
String DbHash = "$2y$13$VVmaKXzaS2QWgU1S4I8h5eJgC/DduF2fXmnhvcynro004GCUAQfr2";
to this :
String DbHash = "$2a$13$VVmaKXzaS2QWgU1S4I8h5eJgC/DduF2fXmnhvcynro004GCUAQfr2";

Read Encrypted Password in Java

I have the following code in javascript / nodejs that encrypt passwords. I need to read these passwords in java:
encryptPassword: function(password, salt) {
var salt = new Buffer(salt, 'base64');
return crypto.pbkdf2Sync(password, salt, 10000, 64).toString('base64');
}
I Used this method to create encrypted password for testing. this is the result (as java variables):
static String password = "123456";
static String salt = "CPvFo+klD9Vh2iE07JEGXA==";
public final String encrypted = "LtStqkNQjrr+P4V8fGtnauNJNOIB7t35O5I4a4/I9lFUnMR3ckbZyT85g/wO0Da9318Wrql/y1bsY2XdpXqx+Q==";
I tried to tranalte the encryption code above to java, using this http://www.javacodegeeks.com/2012/05/secure-password-storage-donts-dos-and.html :
public static byte[] getEncryptedPassword(String password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
String algorithm = "PBKDF2WithHmacSHA1";
int derivedKeyLength = 64;
int iterations = 10000;
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
return f.generateSecret(spec).getEncoded();
}
Finally, I used apache codecs to set the 64 based string:
public static String getEncryptedPassword(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException
{
byte[] bytes = Base64.decodeBase64(salt);
byte[] encryptedPassword = getEncryptedPassword(password, bytes);
return Base64.encodeBase64String(encryptedPassword);
}
The tester is this:
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println(encrypted);
System.out.println(getEncryptedPassword(password, salt));
}
And the output is
LtStqkNQjrr+P4V8fGtnauNJNOIB7t35O5I4a4/I9lFUnMR3ckbZyT85g/wO0Da9318Wrql/y1bsY2XdpXqx+Q==
LtStqkNQjro=
As you can see, the java code produce something that is pretty much a prefix of the encryped password produced by the javascript.
I tested this on different complicated passwords, and got the same result: a string that is a prefix of the javascript encrypted password. Different passwords are not a prefix of each other.
Therefore, I think I am pretty much close. But I can't figure out what is missing.

Password encryption method never returns the same result for the same parameters

I have found code leveraging java.security.* in order to encrypt passwords. But when I use it, It's not working. Each time I call the encrypt method with the same parameters (which are displayed in the encrypt() method, and are really each time the same), I get a different result, which of course makes the code useless. Here my code:
public byte[] encrypt(String clearPassword, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println(clearPassword+" ********** "+salt);
String algorithm = "PBKDF2WithHmacSHA1";
int derivedKeyLength = 1600;
int iterations = 20000;
KeySpec spec = new PBEKeySpec(clearPassword.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
byte [] truc = f.generateSecret(spec).getEncoded();
System.out.println(truc);
return truc;
}
public byte[] generateSalt() throws NoSuchAlgorithmException {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[8];
random.nextBytes(salt);
return salt;
}
I think I introduced an error in the original code at some point, but I can't see where. Any idea?
It's because System.out.println(truc); does not do what you think it does. If you tried:
System.out.println(Arrays.toString(truc));
you would print the actual content of the array, which should be the same every time you call the method with the same parameters.
See for example: printing arrays

Categories