Skip to content

Commit

Permalink
Update default configuration for Argon2PasswordEncoder
Browse files Browse the repository at this point in the history
The recommended minimums for Argon2, as per OWASP Cheat Sheet Series (https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html), are:
Use Argon2id with a minimum configuration of 15 MiB of memory, an iteration count of 2, and 1 degree of parallelism.

Previous default configuration:
memory=4, iterations=3, parallelism=1

New default configuration:
memory=16, iterations=2, parallelism=1

Issue spring-projectsgh-10506
  • Loading branch information
jgrandja committed Oct 11, 2022
1 parent 8d09655 commit 2ea62d0
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -52,9 +52,9 @@ public class Argon2PasswordEncoder implements PasswordEncoder {

private static final int DEFAULT_PARALLELISM = 1;

private static final int DEFAULT_MEMORY = 1 << 12;
private static final int DEFAULT_MEMORY = 1 << 14;

private static final int DEFAULT_ITERATIONS = 3;
private static final int DEFAULT_ITERATIONS = 2;

private final Log logger = LogFactory.getLog(getClass());

Expand All @@ -68,10 +68,24 @@ public class Argon2PasswordEncoder implements PasswordEncoder {

private final BytesKeyGenerator saltGenerator;

/**
* Constructs an Argon2 password encoder with a salt length of 16 bytes, a hash length
* of 32 bytes, parallelism of 1, memory cost of 1 << 12 and 3 iterations.
* @deprecated Use {@link #defaultsForSpringSecurity_v5_2()} instead
*/
@Deprecated
public Argon2PasswordEncoder() {
this(DEFAULT_SALT_LENGTH, DEFAULT_HASH_LENGTH, DEFAULT_PARALLELISM, DEFAULT_MEMORY, DEFAULT_ITERATIONS);
this(16, 32, 1, 1 << 12, 3);
}

/**
* Constructs an Argon2 password encoder with the provided parameters.
* @param saltLength the salt length (in bytes)
* @param hashLength the hash length (in bytes)
* @param parallelism the parallelism
* @param memory the memory cost
* @param iterations the number of iterations
*/
public Argon2PasswordEncoder(int saltLength, int hashLength, int parallelism, int memory, int iterations) {
this.hashLength = hashLength;
this.parallelism = parallelism;
Expand All @@ -80,6 +94,29 @@ public Argon2PasswordEncoder(int saltLength, int hashLength, int parallelism, in
this.saltGenerator = KeyGenerators.secureRandom(saltLength);
}

/**
* Constructs an Argon2 password encoder with a salt length of 16 bytes, a hash length
* of 32 bytes, parallelism of 1, memory cost of 1 << 12 and 3 iterations.
* @return the {@link Argon2PasswordEncoder}
* @since 5.8
* @deprecated Use {@link #defaultsForSpringSecurity_v5_8()} instead
*/
@Deprecated
public static Argon2PasswordEncoder defaultsForSpringSecurity_v5_2() {
return new Argon2PasswordEncoder(16, 32, 1, 1 << 12, 3);
}

/**
* Constructs an Argon2 password encoder with a salt length of 16 bytes, a hash length
* of 32 bytes, parallelism of 1, memory cost of 1 << 14 and 2 iterations.
* @return the {@link Argon2PasswordEncoder}
* @since 5.8
*/
public static Argon2PasswordEncoder defaultsForSpringSecurity_v5_8() {
return new Argon2PasswordEncoder(DEFAULT_SALT_LENGTH, DEFAULT_HASH_LENGTH, DEFAULT_PARALLELISM, DEFAULT_MEMORY,
DEFAULT_ITERATIONS);
}

@Override
public String encode(CharSequence rawPassword) {
byte[] salt = this.saltGenerator.generateKey();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -58,7 +58,9 @@ private PasswordEncoderFactories() {
* <li>SHA-256 - {@code new MessageDigestPasswordEncoder("SHA-256")}</li>
* <li>sha256 -
* {@link org.springframework.security.crypto.password.StandardPasswordEncoder}</li>
* <li>argon2 - {@link Argon2PasswordEncoder}</li>
* <li>argon2 - {@link Argon2PasswordEncoder#defaultsForSpringSecurity_v5_2()}</li>
* <li>argon2@SpringSecurity_v5_8 -
* {@link Argon2PasswordEncoder#defaultsForSpringSecurity_v5_8()}</li>
* </ul>
* @return the {@link PasswordEncoder} to use
*/
Expand All @@ -77,7 +79,8 @@ public static PasswordEncoder createDelegatingPasswordEncoder() {
encoders.put("SHA-256",
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
return new DelegatingPasswordEncoder(encodingId, encoders);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,7 +39,7 @@ public class Argon2PasswordEncoderTests {
@Mock
private BytesKeyGenerator keyGeneratorMock;

private Argon2PasswordEncoder encoder = new Argon2PasswordEncoder();
private Argon2PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2();

@Test
public void encodeDoesNotEqualPassword() {
Expand Down Expand Up @@ -127,6 +127,15 @@ public void encodeWhenUsingPredictableSaltWithCustomParamsThenEqualTestHash() th
"$argon2id$v=19$m=512,t=5,p=4$QUFBQUFBQUFBQUFBQUFBQQ$PNv4C3K50bz3rmON+LtFpdisD7ePieLNq+l5iUHgc1k");
}

@Test
public void encodeWhenUsingPredictableSaltWithDefaultsForSpringSecurity_v5_8ThenEqualTestHash() throws Exception {
this.encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
injectPredictableSaltGen();
String hash = this.encoder.encode("sometestpassword");
assertThat(hash).isEqualTo(
"$argon2id$v=19$m=16384,t=2,p=1$QUFBQUFBQUFBQUFBQUFBQQ$zGt5MiNPSUOo4/7jBcJMayCPfcsLJ4c0WUxhwGDIYPw");
}

@Test
public void upgradeEncodingWhenSameEncodingThenFalse() {
String hash = this.encoder.encode("password");
Expand All @@ -135,7 +144,7 @@ public void upgradeEncodingWhenSameEncodingThenFalse() {

@Test
public void upgradeEncodingWhenSameStandardParamsThenFalse() {
Argon2PasswordEncoder newEncoder = new Argon2PasswordEncoder();
Argon2PasswordEncoder newEncoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2();
String hash = this.encoder.encode("password");
assertThat(newEncoder.upgradeEncoding(hash)).isFalse();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -105,4 +105,10 @@ public void matchesWhenArgon2ThenWorks() {
assertThat(this.encoder.matches(this.rawPassword, encodedPassword)).isTrue();
}

@Test
public void matchesWhenArgon2SpringSecurity_v5_8ThenWorks() {
String encodedPassword = "{argon2@SpringSecurity_v5_8}$argon2id$v=19$m=16384,t=2,p=1$v7fN5p91BQbdbA2HfdSPRg$MULpa02CO/6FKfqwuerCFvS7OhMxGFCKUOoWfzt86Rc";
assertThat(this.encoder.matches(this.rawPassword, encodedPassword)).isTrue();
}

}

0 comments on commit 2ea62d0

Please sign in to comment.