DevTools Hub

Search tools

Search for a developer tool

How to Hash Passwords in Java

Part of the Hashing Toolkit
Pattern
Argon2Factory.create(Argon2Factory.Argon2Types.ARGON2id)

argon2-jvm — the default create() call with no arguments returns Argon2i, not Argon2id

Explanation

argon2-jvm (de.mkammerer:argon2-jvm-nolibs on Maven/Gradle) wraps the real, native Argon2 reference implementation for the JVM. The one thing worth knowing before anything else:

Argon2 argon2 = Argon2Factory.create(); // defaults to Argon2i, NOT Argon2id

Calling Argon2Factory.create() with no arguments gives you Argon2i — side-channel-resistant, but not the variant OWASP recommends for password storage. Getting Argon2id requires passing the type explicitly:

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

char[] password = "correct horse battery staple".toCharArray();
try {
    String hash = argon2.hash(2, 19456, 1, password); // iterations, memory (KiB), parallelism
    boolean ok = argon2.verify(hash, password);
} finally {
    argon2.wipeArray(password);
}

Two details specific to the JVM here, not present in the Node.js or Python versions of this same code: passwords are passed as char[], not String — Java string literals can live in memory (and in the string pool) longer than you control, while a char[] can be explicitly overwritten once you're done with it. argon2.wipeArray(password) does exactly that, and belongs in a finally block so it runs even if hashing throws.

For what the iteration count, memory, and parallelism arguments actually control internally, see Argon2 Explained.

Valid examples

  • Argon2 argon2 = Argon2Factory.create(Argon2Factory.Argon2Types.ARGON2id); String hash = argon2.hash(2, 19456, 1, password);

    Explicitly requests Argon2id with OWASP-baseline parameters (iterations, memory in KiB, parallelism).

  • boolean ok = argon2.verify(hash, password); // password is a char[]

    Reads the algorithm, version, and parameters back out of the hash string itself.

  • try { ... } finally { argon2.wipeArray(password); }

    Overwrites the char[] password in memory once hashing/verification is done, in a finally block so it runs even on exception.

Invalid examples

  • Argon2 argon2 = Argon2Factory.create(); // Argon2i, not Argon2id

    The no-argument factory method defaults to Argon2i — side-channel resistant, but not OWASP's recommended variant for password storage.

  • MessageDigest.getInstance("SHA-256").digest(password.getBytes())

    A raw SHA-256 digest — no salt, no cost factor. See Why SHA-256 Should Not Be Used for Passwords.

  • String password = "..."; // instead of char[]

    String is immutable in Java — it can't be explicitly wiped from memory the way a char[] can, so it may persist longer than intended, including in the string pool.

Try it now