Java Password Hash

0 views
Skip to first unread message

Gladys Anick

unread,
Aug 5, 2024, 5:46:00 AM8/5/24
to fanloralo
LearnJava hashing algorithms in-depth for hashing passwords. A secure password hash is an encrypted sequence of characters obtained after applying specific algorithms and manipulations on user-provided passwords, which are generally very weak and easy to guess.

These blocks are processed by the MD5 algorithm, which operates in a 128-bit state, and the result will be a 128-bit hash value. After applying MD5, the generated hash is typically a 32-digit hexadecimal number.


The original intent of salting was primarily to defeat pre-computed rainbow table attacks that could otherwise be used to significantly improve the efficiency of cracking the hashed password database.


Please note that you must now store this salt value for every password you hash. Because when user login back into the system, we must use only the originally generated salt to create the hash again to match with the stored hash. If a different salt is used (we are generating random salt), the then generated hash will be different.


So far, we have learned about creating secure hashes for passwords and using salt to make it even more secure. But the problem today is that hardwares have become so fast than any brute force attack using dictionary and rainbow tables, a bad actor can crack any password in less or more time.


This feature is essentially implemented using some CPU-intensive algorithms such as PBKDF2, Bcrypt or Scrypt. These algorithms take a work factor (also known as security factor) or iteration count as an argument.


The concepts behind bcrypt is similar to the previous concept as in PBKDF2. It just happened to be that Java does not have any inbuilt support for bcrypt algorithm to make the attack slower but still, you can find one such implementation in the attached source code.


There are lots of hashing algorithms, but very few of them are good choices for passwords. Many types of hashing functions have specific use cases like checking the integrity of a file, for instance. These hashing algorithms are a poor choice for passwords.


The best algorithm to use at the moment (in 2022) is Argon2id. Argon2 is a key derivation function that was selected as the winner of the Password Hashing Competition. It has three different versions:


The Argon2id version is advised for passwords because of the balanced approach against both side-channel and GPU-based attacks. You can configure the Argon2id algorithm by supplying three parameters: memory size (m), iterations (t), and degree of parallelism (p).


Currently, the advice is to use Argon2id with at least 15 MiB of memory, an iteration count of 2, and 1 degree of parallelism. The algorithm already includes automatic salting for every individual user to prevent pre-computed attacks, so nothing special needs to be done here.


The easiest way to implement Arong2id in your Java application is to use the spring-security-crypto library. Although it is part of the Spring framework, you do not have to use the rest of the Spring framework.


The spring-security-crypto library has a Argon2PasswordEncoder that you can use. I personally believe the naming is a bit off, as this is technically not an encoder but a hasher. The Spring library uses bouncycastle as a dependency that holds a full Java-based implementation of the Argon2 algorithm. The spring-security-crypto library can be considered an intuitive interface on top of bouncycastle, making it easier to use. Next to bouncycastle, you also need a dependency to common-logging for, you might have guessed it, logging.


This hash contains all the information it needs, including the settings I supplied to the encoder and the salt information. This way you can easily check if the original password matches using encoder.matches(). This also works with another instance of the Argon2PasswordEncoder with different settings.


The Argon2 Binding for the JVM library is an alternative to the Spring library. This library was created by Moritz Halbritter and uses JNA to call a native C library. The advantage of this approach is that this uses the original implementation of the Argon2 authors and possibly includes a performance advantage. As a result, you need to have access to the underlying C library on your system.


You can choose to install this C library yourself using your package manager or depend on the library that contains a set of pre-compiled Argon2 libraries. The first one is recommended for the obvious reason that it is smaller.


According to the OWASP Password cheat sheet, you should use a minimum CPU/memory cost parameter (N), a minimum block size (r), and a parallelization parameter (p). The options below are considered the minimum you should use.


Please note that the above list of scrypt parameters will all result in equally strong password hashes. The options above are simply showcasing that by specifying different values for the N, r, and p parameters, you can have the scrypt algorithm use more CPU or memory resources, depending on preference. My recommendation below showcases the real-world usage of this that you can simply copy and paste for simplicity.


The spring-security-crypto library supports many algorithms including SCrypt. You can use the SCryptEncoder in the same way as we did with the Argon2Encoder.In the example below I used the middle suggestion to provide a good balance between CPU and memory allocation.


The higher you set the work factor, the stronger the hash will be, but it will also take more CPU resources (and time!) to finish running. On my local machine, setting running BCrypt with a workload of 10 costs me about 89ms on average. For a workload of 14, it is 1033ms on average. That is almost 12x as long. This is by no means an accurate benchmark, but it does show the impact of an increased work factor.


As computers get stronger and faster every year, password hashing algorithms (and their parameters) need to be adjusted! Modern password hashing algorithms are reliant upon you (as the developer) to specify how much resources they should use when computing a hash, and as time progresses, you will need to update these parameters. The only way to stay on top of things like this is by keeping up with the latest security news and trends. The Snyk blog, for example, is a great resource for security information and trends over time.


I had a discussion with a friend today about his password hash comparison. I argued that you can't return false on the first hash mismatch you have and I sent him a link to an article about a Java timing attack that happened in Java 6.


Which, for me, indicates there is a possible timing attack that could be done because you return false if there is a mismatch in the hash. He argued that this would not be a risk in the application and that the important thing is that the password is salted and hashed and that will probably will not affect the security of the application.


The first algorithm is sensitive to timing attacks, while the second looks better (but I don't know for sure if it's vulnerable or not). However, there is a bug with potential security implications in the second version: What happends if the two strings have different lengths?


Timing attacks are a real security issue that it is reasonable to be worried about, so you are right to bring the issue up. I could partly agree with your friend in that it is more important to use salt and a good hashing algorithm. This however does not mean that timing attacks are not important or should not be taken seriously. They should.


However, in this case, it is not obvious how an attacker could pull off a timing attack. Since the input (the password) is hashed with a salt, the attacker probably can't freely control what any of the compared hashes will be. That means it might not be possible to search your way to a matching hash. But all this depends on how the entire system is built, not just on the string comparison algorithm.


One good way to deal with all of this is to use a good library for the hashing. A well written library should take care of both salting and defense against timing attacks for you, without you having to go through the hassle to write all the code yourself.


Your coder is correct: given network travel times and other mitigating factors that you naturally put in (brute force detection, up lockout, etc...) it is very unlikely that an exploit is possible.


However, that isn't my main concern. This is a classic example of a timing vulnerability, AKA this is a pretty basic security vulnerability. Therefore I would assume that whoever wrote this code is not as experienced with managing passwords and hashes as they probably think they are. This leads to a very natural question: what else did they unknowingly get wrong?


Without a full code/system review from someone who is an expert in this area, you'll never know the answer to that question. As a result I suggest you take @Ander's advice: switch to a standard library.


You are correct. Because you wrote the code to check the hash character by character (why are you doing that?), it would be possible to use timing to work out the correct hash character by character. But that would be no different from trying random passwords. You just know which of your attempts resulted in a close hash. It doesn't inform your next guesses.


If the password is stored plainly clearly the first code can cause a remote timing attack. The second one only leaks about the number of if condition satisfied. Can this leak be used for remote timing? It is not clear without a real.


then it is a true constant time that eliminates the information of the number of equalities. The string length are always equal since the attacker cannot control the length. Coding is not enough and one also need to consider the compiler optimization. Therefore one either check the result or use in assembly. There is a great page about constant timing on BearSSL pages written by the Thomas Pornin.

3a8082e126
Reply all
Reply to author
Forward
0 new messages