2

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

10
  • 1
    You need at least salt, otherwise vunerable to See rainbow tables and How to securely hash passwords? Commented Dec 18, 2018 at 13:09
  • 1
    No. SHA 256 is not a cryptographically secure hash function. You should also salt the passwords. Commented Dec 18, 2018 at 13:09
  • Okay thank you, I will look at salting now, what about the second part of my question, visa vi preventing code being decompiled and changed to bypass security features?? Commented Dec 18, 2018 at 13:11
  • @Michael SHA-256 is a standard. the way you use can make it insecure. Commented Dec 18, 2018 at 13:11
  • @kelalaka correct me if I am wrong, but looking at the ways hashes are decrypted is using the same hash function on multiple variables. the comparison of which can be used to decrypt. so would using hash for only one variable make it secure? Commented Dec 18, 2018 at 13:18

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, can you explain the my secret password section? does it require a password to hash a password, or is that the entered password that needs to be verified?
"my-secret-password" is the original password. You run this code once (on your machine) to generate the salt and hash, then store those in the application (not the original password). Then in the application you take the stored salt and the user-provided password and invoke the code again. The resulting hash will then either match the stored hash, meaning the user-provided password matches the original one, or not meaning the entered password is wrong.
1

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.

2 Comments

I'm going to sound stupid here, but if I wanted to package my project into an application i.e. a .exe, would this effect that process?
Java is not meant to be made to an .exe . Generally you would create a .jar file. This is not effected (despite the fact that the size will most likely be reduced) by the process as long as the Main-class is not renamed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.