Skip to content

Commit 2ea62d0

Browse files
committed
Update default configuration for Argon2PasswordEncoder
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 gh-10506
1 parent 8d09655 commit 2ea62d0

File tree

4 files changed

+66
-11
lines changed

4 files changed

+66
-11
lines changed

crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2PasswordEncoder.java

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,9 +52,9 @@ public class Argon2PasswordEncoder implements PasswordEncoder {
5252

5353
private static final int DEFAULT_PARALLELISM = 1;
5454

55-
private static final int DEFAULT_MEMORY = 1 << 12;
55+
private static final int DEFAULT_MEMORY = 1 << 14;
5656

57-
private static final int DEFAULT_ITERATIONS = 3;
57+
private static final int DEFAULT_ITERATIONS = 2;
5858

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

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

6969
private final BytesKeyGenerator saltGenerator;
7070

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

81+
/**
82+
* Constructs an Argon2 password encoder with the provided parameters.
83+
* @param saltLength the salt length (in bytes)
84+
* @param hashLength the hash length (in bytes)
85+
* @param parallelism the parallelism
86+
* @param memory the memory cost
87+
* @param iterations the number of iterations
88+
*/
7589
public Argon2PasswordEncoder(int saltLength, int hashLength, int parallelism, int memory, int iterations) {
7690
this.hashLength = hashLength;
7791
this.parallelism = parallelism;
@@ -80,6 +94,29 @@ public Argon2PasswordEncoder(int saltLength, int hashLength, int parallelism, in
8094
this.saltGenerator = KeyGenerators.secureRandom(saltLength);
8195
}
8296

97+
/**
98+
* Constructs an Argon2 password encoder with a salt length of 16 bytes, a hash length
99+
* of 32 bytes, parallelism of 1, memory cost of 1 << 12 and 3 iterations.
100+
* @return the {@link Argon2PasswordEncoder}
101+
* @since 5.8
102+
* @deprecated Use {@link #defaultsForSpringSecurity_v5_8()} instead
103+
*/
104+
@Deprecated
105+
public static Argon2PasswordEncoder defaultsForSpringSecurity_v5_2() {
106+
return new Argon2PasswordEncoder(16, 32, 1, 1 << 12, 3);
107+
}
108+
109+
/**
110+
* Constructs an Argon2 password encoder with a salt length of 16 bytes, a hash length
111+
* of 32 bytes, parallelism of 1, memory cost of 1 << 14 and 2 iterations.
112+
* @return the {@link Argon2PasswordEncoder}
113+
* @since 5.8
114+
*/
115+
public static Argon2PasswordEncoder defaultsForSpringSecurity_v5_8() {
116+
return new Argon2PasswordEncoder(DEFAULT_SALT_LENGTH, DEFAULT_HASH_LENGTH, DEFAULT_PARALLELISM, DEFAULT_MEMORY,
117+
DEFAULT_ITERATIONS);
118+
}
119+
83120
@Override
84121
public String encode(CharSequence rawPassword) {
85122
byte[] salt = this.saltGenerator.generateKey();

crypto/src/main/java/org/springframework/security/crypto/factory/PasswordEncoderFactories.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -58,7 +58,9 @@ private PasswordEncoderFactories() {
5858
* <li>SHA-256 - {@code new MessageDigestPasswordEncoder("SHA-256")}</li>
5959
* <li>sha256 -
6060
* {@link org.springframework.security.crypto.password.StandardPasswordEncoder}</li>
61-
* <li>argon2 - {@link Argon2PasswordEncoder}</li>
61+
* <li>argon2 - {@link Argon2PasswordEncoder#defaultsForSpringSecurity_v5_2()}</li>
62+
* <li>argon2@SpringSecurity_v5_8 -
63+
* {@link Argon2PasswordEncoder#defaultsForSpringSecurity_v5_8()}</li>
6264
* </ul>
6365
* @return the {@link PasswordEncoder} to use
6466
*/
@@ -77,7 +79,8 @@ public static PasswordEncoder createDelegatingPasswordEncoder() {
7779
encoders.put("SHA-256",
7880
new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
7981
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
80-
encoders.put("argon2", new Argon2PasswordEncoder());
82+
encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
83+
encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
8184
return new DelegatingPasswordEncoder(encodingId, encoders);
8285
}
8386

crypto/src/test/java/org/springframework/security/crypto/argon2/Argon2PasswordEncoderTests.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ public class Argon2PasswordEncoderTests {
3939
@Mock
4040
private BytesKeyGenerator keyGeneratorMock;
4141

42-
private Argon2PasswordEncoder encoder = new Argon2PasswordEncoder();
42+
private Argon2PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2();
4343

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

130+
@Test
131+
public void encodeWhenUsingPredictableSaltWithDefaultsForSpringSecurity_v5_8ThenEqualTestHash() throws Exception {
132+
this.encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
133+
injectPredictableSaltGen();
134+
String hash = this.encoder.encode("sometestpassword");
135+
assertThat(hash).isEqualTo(
136+
"$argon2id$v=19$m=16384,t=2,p=1$QUFBQUFBQUFBQUFBQUFBQQ$zGt5MiNPSUOo4/7jBcJMayCPfcsLJ4c0WUxhwGDIYPw");
137+
}
138+
130139
@Test
131140
public void upgradeEncodingWhenSameEncodingThenFalse() {
132141
String hash = this.encoder.encode("password");
@@ -135,7 +144,7 @@ public void upgradeEncodingWhenSameEncodingThenFalse() {
135144

136145
@Test
137146
public void upgradeEncodingWhenSameStandardParamsThenFalse() {
138-
Argon2PasswordEncoder newEncoder = new Argon2PasswordEncoder();
147+
Argon2PasswordEncoder newEncoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2();
139148
String hash = this.encoder.encode("password");
140149
assertThat(newEncoder.upgradeEncoding(hash)).isFalse();
141150
}

crypto/src/test/java/org/springframework/security/crypto/factory/PasswordEncoderFactoriesTests.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -105,4 +105,10 @@ public void matchesWhenArgon2ThenWorks() {
105105
assertThat(this.encoder.matches(this.rawPassword, encodedPassword)).isTrue();
106106
}
107107

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

0 commit comments

Comments
 (0)