How to Use Argon2 for Password Hashing in Java

In previous posts, we’ve learned about the importance of using a password hashing function like Argon2id to create hashes of passwords that can be safely stored in a database. I have shown you how to use two popular libraries to perform this operation in C#. In this post, I’m going to show you how to do the same thing in Java.

For Java, I recommend either using argon2-jvm. As an alternative, you can utilize one of the many wrappers around Libsodium, but there simply aren’t any great options, and all of them appear to require you to manage the Libsodium binaries yourself. Fail.

For background information, I recommend the following posts:

Using argon2-jvm

The Argon2 documentation refers to two libraries that implement the specification. Argon2-jvm is the most popular.

The library is stupid simple to use. However, there are no reasonable defaults provided, so you are either left at guessing, using Libsodium’s recommended values, or using a tool such as the one that I have provided to calculate them for you.

Argon2-jvm generates a secure salt for you on the fly and embeds it in the encoded password hash. Thus, when you go to verify a password, you simply need to verify the encoded hash that you have previously stored with the password supplied by the user.

A Simple Example

Let’s take a look at an example. First, add a dependency to your Maven’s pom.xml file to include argon2-jvm:

<dependency>
    <groupId>de.mkammerer</groupId>
    <artifactId>argon2-jvm</artifactId>
    <version>2.5</version>
</dependency>

Next, in the .java file for which you would like to utilize the Argon2 algorithm, add the following import statements to the top. I’m also including Instant and Duration for diagnostics, but this is optional.

import java.time.Duration;
import java.time.Instant;
import de.mkammerer.argon2.Argon2;
import de.mkammerer.argon2.Argon2Factory;
import de.mkammerer.argon2.Argon2Types;

In order to hash a password, you will need to create an instance of the Argon2 interface using the Argon2Factory class. By default, the Argon2Factory will attempt to utilize the Argon2i algorithm, which is not recommended. We’ll force it to use Argon2id.

Argon2 argon2 = Argon2Factory.create(Argon2Types.ARGON2id);

Now, we can use our Argon2 instance to hash a password. The hash() function will return the encoded password hash with the salt embedded.

String hash = argon2.hash(4, 1024 * 1024, 8, password);

In this example, we are using 4 iterations, 1 GB of memory, and 8 degrees of parallelism (for 4 CPU cores). Note that I’m not concerning myself with cleaning the password from memory. This is a good practice, but the additional steps get a bit in the way of our simple example.

Next, we’ll use our Argon2 instance to verify the hash. Note again that the verify() function will strip the salt encoded in the password hash and supply it to the Argon2 algorithm. It will return a Boolean value denoting success or failure.

boolean success = argon2.verify(hash, password);

Putting It All Together

Finally, we can piece together all of the above function calls to both calculate and verify the password hash:

private void run() {
    String password = "Hello World!";
    Instant beginHash = Instant.now();

    Argon2 argon2 = Argon2Factory.create(Argon2Types.ARGON2id);
    System.out.println(String.format("Creating hash for password '%s'.", password));

    String hash = argon2.hash(4, 1024 * 1024, 8, password);
    System.out.println(String.format("Encoded hash is '%s'.", hash));

    Instant endHash = Instant.now();
    System.out.println(String.format(
        "Process took %f s",
        Duration.between(beginHash, endHash).toMillis() / 1024.0
        ));

    Instant beginVerify = Instant.now();
    System.out.println("Verifying hash...");

    boolean success = argon2.verify(hash, password);
    System.out.println(success ? "Success!" : "Failure!");

    Instant endVerify = Instant.now();
    System.out.println(String.format(
        "Process took %f s",
        Duration.between(beginVerify, endVerify).toMillis() / 1024.0
        ));
}

Like I said in my previous post, you don’t want to log a password or its hash, unless you want to make it easier for the bad guys. Here are the results:

Creating hash for password 'Hello World!'.
Encoded hash is '$argon2id$v=19$m=1048576,t=4,p=8$9m35jyZUsdtJ8ON2K6xAjg$dMIdvc17guXazUEo2/DWyih10h7AoK3m+KuHan40yI8'.
Process took 1.705078 s
Verifying hash...
Success!
Process took 1.110352 s

Conclusion

Argon2-jvm makes calculating password hashes in Java easy. And, since the salt, memory usage, iterations, and degree of parallelism are all encoded in the generated password hash, it makes storage of Argon2’s parameters a breeze. If you need to calculate password hashes in Java, I highly recommend giving this library a shot.

 

Photo by Ylanite Koppens from Pexels.

Leave a Reply