-
Notifications
You must be signed in to change notification settings - Fork 27
Argon2
Argon2 is a key derivation function that was selected as the winner of the Password Hashing Competition in July 2015.
Argon2 accepts 6 parameters: the memory required for computation, the number of iterations , the number of threads, the desired key length, the type (i
, d
, or id
) and the version of the algorithm.
Name | Default value | Properties | Description |
---|---|---|---|
Memory | 15 | hash.argon2.memory |
Defines amount of memory (in kibibytes) to use. |
Iterations | 2 | hash.argon2.iterations |
Defines number of iterations to perform. |
Parallelisation | 1 | hash.argon2.parallelism |
Defines the degree of parallelism (number of threads). |
Output length | 32 | hash.argon2.length |
Defines the desired length of the final derived key. |
Type | Argon2id | hash.argon2.type |
Defines the desired type of the algorithm. |
Version | 19 | hash.argon2.version |
The current version is 0x13 (19 decimal). |
The suggested version of the algorithm is 19, the latest one. The other versions should be used only for backward compatibility reasons and we recommend to update your hashes as soon as possible.
Type | Description |
---|---|
Argon2d | It maximizes resistance to GPU cracking attacks. It accesses the memory array in a password dependent order, which reduces the possibility of time–memory trade-off (TMTO) attacks, but introduces possible side-channel attacks. |
Argon2i | It is optimized to resist side-channel attacks. It accesses the memory array in a password independent order. |
Argon2id | It is a hybrid version. It follows the Argon2i approach for the first half pass over memory and the Argon2d approach for subsequent passes. The Internet draft recommends using Argon2id except when there are reasons to prefer one of the other two modes. |
You can define a singleton custom scrypt function by calling Argon2Function.getInstance(int, int, int, int, int, int)
or Argon2Function.getInstance(int, int, int, int, int)
Argon2Function argon2 = Argon2Function.getInstance(1024, 3, 2, 32, Argon2.d, 19);
In this case you have created a singleton instance which requires 1024 kibibytes of memory, performs 3 iterations, spawns 2 threads, produces a derived key of 32 bytes, uses Argon2d with the latest version (19).
Alternatively if you have defined the parameters in the psw4j.properties
file
Argon2Function argon2 = AlgorithmFinder.getArgon2Instance();
Additionally you can create a Argon2Function
singleton instance from the hash, since all the parameters required are stored into it.
String hashed = "$argon2id$v=19$m=1024,t=3,p=12$MzMzMzMzMzM$DXUE5N4lm4plldg9nGMq+tYsbGhko8HWpPaADujpgFQ";
Argon2Function argon2 = Argon2Function.getInstanceFromHash(hashed);
Hashing passwords with Argon2 can be done quite easily.
Hash hash = Password.hash(plainTextPassword).withArgon2();
hash.getResult(); // $argon2id$v=19$m=1024,t=3,p=12$MTExMTExMTE$0PUE8wVEaK0qdjms3b4pTZOs0+00S/+9j28WZ3gMUno
This approach takes the parameters from psw4j.properties
file (like AlgorithmFinder.getArgon2Instance()
).
However it's possible to use user-defined parameters as we saw previously
Argon2Function myArgon2 = Argon2Function.getInstance(1024, 3, 2, 32, Argon2.d, 19);
Password.hash(plainTextPassword).with(myArgon2);
You have two way to define the cryptographic salt.
Method addSalt(String)
make you define the intended salt.
Hash hash = Password.hash(plainTextPassword).addSalt("a1b2c3d4").withArgon2();
For security reasons, the salt must never be the same.
Method addRandomSalt(int)
adds a random generated salt with a defined length (in bytes)
Hash hash = Password.hash(plainTextPassword).addRandomSalt(42).withArgon2();
Alternatively, you can use addRandomSalt()
(no arguments) to define a random salt of 64 bytes
Hash hash = Password.hash(plainTextPassword).addRandomSalt().withArgon2();
Method addPepper(CharSequence)
make you define the intended pepper.
Hash hash = Password.hash(plainTextPassword).addPepper("AlicePepper").withArgon2();
Alternatively you can define the pepper in the psw4j.properties
file at the property global.pepper
Hash hash = Password.hash(plainTextPassword).addPepper().withArgon2();
The pepper is used as Argon2's secret
parameter (it's not appended/prepended to the plain text password).
Ideally the hash is retrieved from the database. Once retrieved you can check the user-provided passwords against the hash from your database. The salt is always encoded within the hash.
String hashFromDB = getHashFromDatabase(user);
boolean verified = Password.check(userProvidedPassword, hashFromDB).withArgon2();
The parameters used are taken from your psw4j.properties
file.
Alternatively you can define your own parameters
String hashFromDB = getHashFromDatabase(user);
Argon2Function myArgon2 = Argon2Function.getInstance(1024, 3, 2, 32, Argon2.d, 19);
boolean verified = Password.check(userProvidedPassword, hashFromDB).with(myArgon2);
If you want to migrate your cryptographic hashes from the original configuration to a more secure one, you can refresh them during the first user login.
String hashFromDB = getHashFromDatabase(user);
Argon2Function myArgon2 = Argon2Function.getInstance(1024, 3, 2, 32, Argon2.d, 19);
HashUpdate update = Password.check(userProvidedPassword, hashFromDB)
.andUpdate()
.addNewRandomSalt().with(myScrypt);
if(update.isVerified())
{
Hash newHash = update.getHash();
storeNewHash(user, newHash.getHash());
}
You can switch to any other hashing function offered by Password4j (for example scrypt)
Argon2Function oldFunction = AlgorithmFinder.getArgon2Function();
ScryptFunction newFunction = AlgorithmFinder.getScryptFunction();
HashUpdate update = Password.check(userProvidedPassword, hashFromDB)
.andUpdate()
.addNewRandomSalt().with(oldFunction, newFunction);