JEP draft: Argon2 Password Hashing Algorithm
| Owner | Artur Barashev |
| Type | Feature |
| Scope | SE |
| Status | Submitted |
| Component | security-libs / javax.crypto |
| Effort | M |
| Duration | M |
| Relates to | JEP 510: Key Derivation Function API |
| Reviewed by | Sean Mullan |
| Created | 2026/02/03 15:26 |
| Updated | 2026/03/16 19:07 |
| Issue | 8377081 |
Summary
Enhance the security of Java applications by providing an implementation of the Argon2 password hashing algorithm. Argon2 provides additional protection against brute-force password guessing attacks and was the winner of the 2015 Password Hashing Competition.
Goals
- Provide a javax.crypto.KDF implementation of the Argon2id variant of Argon2, as specified in RFC 9106.
Non-Goals
- It is not a goal to implement the Argon2d or Argon2i variants of Argon2.
Motivation
The Java Platform should offer better support for password hashing algorithms beyond PBKDF2. PBKDF2 is compute-bound and low-memory, which maps well to massively parallel hardware and makes it susceptible to offline cracking with graphics processing units (GPUs) or application-specific integrated circuits (ASICs).
Argon2 is a memory-hard algorithm. Memory-hardness increases the cost of large-scale password guessing by limiting the degree to which attackers can exploit specialized hardware. For example, if each guess requires 64 MiB of memory, then a device with 8 GiB of available memory can execute only about 128 guesses in parallel, rather than thousands or millions.
The Java Platform should provide a standard memory-hard password hashing algorithm. Other cryptographic libraries such as OpenSSL and BouncyCastle already support Argon2.
Description
Argon2 defines three variants:
- Argon2d uses data-dependent memory access and provides better protection against time-memory trade-off (TMTO) attacks.
- Argon2i uses data-independent memory access and provides better protection against side-channel attacks.
- Argon2id is a hybrid design and works as Argon2i for the first half of the first pass over the memory and as Argon2d for the rest. Per RFC 9106 "Argon2id MUST be supported by any implementation of this document".
This JEP proposes to implement Argon2id, thus offering a balance between side-channel resistance and TMTO protection. The algorithm will be implemented as a KDF service of the SunJCE provider, adhering to the API introduced in JEP 510.
Argon2id has several input parameters which can be used to configure the algorithm. These parameters can be tailored based on the security requirements of your application and the system it is running on. The memory (m, in KiB), iterations (t) and parallelism (p, number of execution threads) parameters allow applications to tune computational and memory cost according to their deployment requirements. The salt (typically 16 bytes), and optional secret (k) parameters are commonly used in password hashing algorithms to make password guessing attacks harder. Other parameters include optional associated data (x), the algorithm version (defaults to V13), and the tag length (tagLen, typically 32 bytes) which is the length of the resulting hash.
Integration with the KDF API
Argon2id is exposed as a standard KDF algorithm named "Argon2id". Applications obtain an instance using:
KDF.getInstance("Argon2id");
Argon2ParameterSpec class
The javax.crypto.spec.Argon2ParameterSpec class specifies parameters for the Argon2 algorithm:
public final class Argon2ParameterSpec implements AlgorithmParameterSpec {
// input parameters
int memoryKiB();
int iterations();
int parallelism();
int tagLen();
byte[] secret();
byte[] associatedData();
Argon2ParameterSpec.Version version();
// password and salt
byte[] password();
byte[] salt();
// builder
static Argon2ParameterSpec.Builder newBuilder();
}
Argon2ParameterSpec.Builder class
The inner javax.crypto.spec.Argon2ParameterSpec.Builder class builds Argon2 inputs:
public static final class Builder {
Builder memoryKiB(int m);
Builder memoryPowerOfTwo(int mPower);
Builder iterations(int t);
Builder parallelism(int p);
Builder tagLen(int tagLen);
Builder secret(byte[] k);
Builder associatedData(byte[] x);
Builder version(Argon2ParameterSpec.Version ver);
Argon2ParameterSpec build(byte[] salt, byte[] password);
Argon2ParameterSpec build(byte[] salt, char[] password, Charset cs);
};
Argon2ParameterSpec.Version class
The inner javax.crypto.spec.Argon2ParameterSpec.Version class encapsulates Argon2 versions:
public enum Version {
V10(0x10), // version 1.0, not supported by SunJCE provider
V13(0x13); // RFC 9106 version, supported by SunJCE provider
};
Code Example
This example is based on the uniformly safe option №2 specified in section 4 of RFC 9106.
First, we create an Argon2ParameterSpec.Builder with 64 MiB of RAM, 3 iterations, 4 parallelly processed lanes and 256-bit tag length. Note: the memoryPowerOfTwo method sets the memory parameter to 2ⁿ KiB, where n is the value passed to the method; so in this example, 2¹⁶ = 65536 KiB or 64 MiB.
Argon2ParameterSpec.Builder builder = Argon2ParameterSpec.newBuilder()
.memoryPowerOfTwo(16).iterations(3).parallelism(4).tagLen(32);
Next we call the build method and specify a random 128-bit salt and password we want to hash:
Argon2ParameterSpec param = builder.build(randomSalt128, password);
Then we obtain an Argon2id KDF instance and generate a password hash as a byte array:
KDF k = KDF.getInstance("Argon2id");
byte[] passwordHash = k.deriveData(param);
And we can also generate output as a SecretKey:
SecretKey key = k.deriveKey("Generic", param);
Migration from PBKDF2
PBKDF2 is implemented via javax.crypto.SecretKeyFactory while this JEP proposes to implement Argon2id via javax.crypto.KDF API. Java applications wishing to migrate from PBKDF2 to Argon2id will need to make code modifications to adopt KDF API.
While adopting Argon2id requires code changes, migrating stored credentials requires a data- and rollout-strategy as well, since PBKDF2 and Argon2id outputs are not interchangeable. Recommended strategies include:
- Opportunistic migration during user authentication.
- Rehashing existing PBKDF2 hash values with Argon2id (double hashing).
Alternatives
The OWASP Password Storage Cheat Sheet lists three modern hashing algorithms that should be considered when selecting a password hashing algorithm: Argon2id, scrypt, and bcrypt. Of those 3, it recommends Argon2id as the preferred option. Here is some additional rationale as to why we chose Argon2id over scrypt and bcrypt:
- bcrypt is widely deployed but not memory-hard by modern standards and is generally weaker against modern GPU cracking than Argon2id.
- scrypt is memory-hard but permits more efficient TMTO attacks than Argon2id.
Testing
- Unit tests will confirm that the implementations comply with the specifications of the KDF APIs, including edge cases such as invalid input parameters, boundary values, and unsupported operations; verification against RFC 9106 known-answer test vectors will be also included.
- Interoperation tests with implementations from other vendors, including but not limited to BouncyCastle, will confirm that our Argon2 implementation works well with others.
Risks and Assumptions
- Argon2's memory-hardness relies on the JVM's ability to allocate requested memory, otherwise Argon2 password hashing fails.
- Runtime effects (e.g., GC activity) may introduce timing variability; callers should not treat execution time as constant.
- The strength is not fixed. It depends entirely on the algorithm's parameters. If weak parameters are used, Argon2 becomes weak. As the memory (m) decreases, the iterations (t) must increase to maintain security levels.