11/*
2- * Copyright 2002-2020 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.
3636 * <li>a configurable random salt value length (default is {@value #DEFAULT_SALT_LENGTH}
3737 * bytes)</li>
3838 * <li>a configurable number of iterations (default is {@value #DEFAULT_ITERATIONS})</li>
39- * <li>a configurable output hash width (default is {@value #DEFAULT_HASH_WIDTH}
40- * bits)</li>
4139 * <li>a configurable key derivation function (see {@link SecretKeyFactoryAlgorithm})</li>
4240 * <li>a configurable secret appended to the random salt (default is empty)</li>
4341 * </ul>
5048 */
5149public class Pbkdf2PasswordEncoder implements PasswordEncoder {
5250
53- private static final int DEFAULT_SALT_LENGTH = 8 ;
51+ private static final int DEFAULT_SALT_LENGTH = 16 ;
5452
55- private static final int DEFAULT_HASH_WIDTH = 256 ;
53+ private static final SecretKeyFactoryAlgorithm DEFAULT_ALGORITHM = SecretKeyFactoryAlgorithm . PBKDF2WithHmacSHA256 ;
5654
57- private static final int DEFAULT_ITERATIONS = 185000 ;
55+ private static final int DEFAULT_HASH_WIDTH = 256 ; // SHA-256
56+
57+ private static final int DEFAULT_ITERATIONS = 310000 ;
5858
5959 private final BytesKeyGenerator saltGenerator ;
6060
6161 private final byte [] secret ;
6262
63- private final int hashWidth ;
64-
6563 private final int iterations ;
6664
67- private String algorithm = SecretKeyFactoryAlgorithm .PBKDF2WithHmacSHA1 .name ();
65+ private String algorithm = DEFAULT_ALGORITHM .name ();
66+
67+ private int hashWidth = DEFAULT_HASH_WIDTH ;
68+
69+ // @formatter:off
70+ /*
71+ The length of the hash should be derived from the hashing algorithm.
72+
73+ For example:
74+ SHA-1 - 160 bits (20 bytes)
75+ SHA-256 - 256 bits (32 bytes)
76+ SHA-512 - 512 bits (64 bytes)
77+
78+ However, the original configuration for PBKDF2 was hashWidth=256 and algorithm=SHA-1, which is incorrect.
79+ The default configuration has been updated to hashWidth=256 and algorithm=SHA-256 (see gh-10506).
80+ In order to preserve backwards compatibility, the variable 'overrideHashWidth' has been introduced
81+ to indicate usage of the deprecated constructor that honors the hashWidth parameter.
82+ */
83+ // @formatter:on
84+ private boolean overrideHashWidth = true ;
6885
6986 private boolean encodeHashAsBase64 ;
7087
7188 /**
7289 * Constructs a PBKDF2 password encoder with no additional secret value. There will be
73- * a salt length of {@value #DEFAULT_SALT_LENGTH} bytes, {@value #DEFAULT_ITERATIONS}
74- * iterations and a hash width of {@value #DEFAULT_HASH_WIDTH} bits. The default is
75- * based upon aiming for .5 seconds to validate the password when this class was
76- * added. Users should tune password verification to their own systems.
90+ * a salt length of 8 bytes, 185,000 iterations, SHA-1 algorithm and a hash length of
91+ * 256 bits. The default is based upon aiming for .5 seconds to validate the password
92+ * when this class was added. Users should tune password verification to their own
93+ * systems.
94+ * @deprecated Use {@link #defaultsForSpringSecurity_v5_5()} instead
7795 */
96+ @ Deprecated
7897 public Pbkdf2PasswordEncoder () {
7998 this ("" );
8099 }
81100
82101 /**
83- * Constructs a standard password encoder with a secret value which is also included
84- * in the password hash. There will be a salt length of {@value #DEFAULT_SALT_LENGTH}
85- * bytes, {@value #DEFAULT_ITERATIONS} iterations and a hash width of
86- * {@value #DEFAULT_HASH_WIDTH} bits.
102+ * Constructs a PBKDF2 password encoder with a secret value which is also included in
103+ * the password hash. There will be a salt length of 8 bytes, 185,000 iterations,
104+ * SHA-1 algorithm and a hash length of 256 bits.
87105 * @param secret the secret key used in the encoding process (should not be shared)
106+ * @deprecated Use {@link #Pbkdf2PasswordEncoder(CharSequence, int, int, int)} instead
88107 */
108+ @ Deprecated
89109 public Pbkdf2PasswordEncoder (CharSequence secret ) {
90- this (secret , DEFAULT_SALT_LENGTH , DEFAULT_ITERATIONS , DEFAULT_HASH_WIDTH );
110+ this (secret , 8 );
91111 }
92112
93113 /**
94- * Constructs a standard password encoder with a secret value as well as salt length.
95- * There will be {@value #DEFAULT_ITERATIONS} iterations and a hash width of
96- * {@value #DEFAULT_HASH_WIDTH} bits.
114+ * Constructs a PBKDF2 password encoder with a secret value as well as salt length.
115+ * There will be 185,000 iterations, SHA-1 algorithm and a hash length of 256 bits.
97116 * @param secret the secret
98117 * @param saltLength the salt length (in bytes)
99118 * @since 5.5
119+ * @deprecated Use {@link #Pbkdf2PasswordEncoder(CharSequence, int, int, int)} instead
100120 */
121+ @ Deprecated
101122 public Pbkdf2PasswordEncoder (CharSequence secret , int saltLength ) {
102- this (secret , saltLength , DEFAULT_ITERATIONS , DEFAULT_HASH_WIDTH );
123+ this (secret , saltLength , 185000 , 256 );
103124 }
104125
105126 /**
106- * Constructs a standard password encoder with a secret value as well as iterations
107- * and hash width. The salt length will be of {@value #DEFAULT_SALT_LENGTH} bytes.
127+ * Constructs a PBKDF2 password encoder with a secret value as well as iterations and
128+ * hash width. The salt length will be 8 bytes.
108129 * @param secret the secret
109130 * @param iterations the number of iterations. Users should aim for taking about .5
110131 * seconds on their own system.
111132 * @param hashWidth the size of the hash (in bits)
133+ * @deprecated Use {@link #Pbkdf2PasswordEncoder(CharSequence, int, int, int)} instead
112134 */
135+ @ Deprecated
113136 public Pbkdf2PasswordEncoder (CharSequence secret , int iterations , int hashWidth ) {
114- this (secret , DEFAULT_SALT_LENGTH , iterations , hashWidth );
137+ this (secret , 8 , iterations , hashWidth );
115138 }
116139
117140 /**
118- * Constructs a standard password encoder with a secret value as well as salt length,
141+ * Constructs a PBKDF2 password encoder with a secret value as well as salt length,
119142 * iterations and hash width.
120143 * @param secret the secret
121144 * @param saltLength the salt length (in bytes)
122145 * @param iterations the number of iterations. Users should aim for taking about .5
123146 * seconds on their own system.
124147 * @param hashWidth the size of the hash (in bits)
125148 * @since 5.5
149+ * @deprecated Use
150+ * {@link #Pbkdf2PasswordEncoder(CharSequence, int, int, SecretKeyFactoryAlgorithm)}
151+ * instead
126152 */
153+ @ Deprecated
127154 public Pbkdf2PasswordEncoder (CharSequence secret , int saltLength , int iterations , int hashWidth ) {
128155 this .secret = Utf8 .encode (secret );
129156 this .saltGenerator = KeyGenerators .secureRandom (saltLength );
130157 this .iterations = iterations ;
131158 this .hashWidth = hashWidth ;
159+ this .algorithm = SecretKeyFactoryAlgorithm .PBKDF2WithHmacSHA1 .name ();
160+ this .overrideHashWidth = false ; // Honor 'hashWidth' to preserve backwards
161+ // compatibility
162+ }
163+
164+ /**
165+ * Constructs a PBKDF2 password encoder with a secret value as well as salt length,
166+ * iterations and algorithm.
167+ * @param secret the secret
168+ * @param saltLength the salt length (in bytes)
169+ * @param iterations the number of iterations. Users should aim for taking about .5
170+ * seconds on their own system.
171+ * @param secretKeyFactoryAlgorithm the algorithm to use
172+ * @since 5.8
173+ */
174+ public Pbkdf2PasswordEncoder (CharSequence secret , int saltLength , int iterations ,
175+ SecretKeyFactoryAlgorithm secretKeyFactoryAlgorithm ) {
176+ this .secret = Utf8 .encode (secret );
177+ this .saltGenerator = KeyGenerators .secureRandom (saltLength );
178+ this .iterations = iterations ;
179+ setAlgorithm (secretKeyFactoryAlgorithm );
180+ }
181+
182+ /**
183+ * Constructs a PBKDF2 password encoder with no additional secret value. There will be
184+ * a salt length of 8 bytes, 185,000 iterations, SHA-1 algorithm and a hash length of
185+ * 256 bits. The default is based upon aiming for .5 seconds to validate the password
186+ * when this class was added. Users should tune password verification to their own
187+ * systems.
188+ * @return the {@link Pbkdf2PasswordEncoder}
189+ * @since 5.8
190+ * @deprecated Use {@link #defaultsForSpringSecurity_v5_8()} instead
191+ */
192+ @ Deprecated
193+ public static Pbkdf2PasswordEncoder defaultsForSpringSecurity_v5_5 () {
194+ return new Pbkdf2PasswordEncoder ("" , 8 , 185000 , 256 );
195+ }
196+
197+ /**
198+ * Constructs a PBKDF2 password encoder with no additional secret value. There will be
199+ * a salt length of 16 bytes, 310,000 iterations, SHA-256 algorithm and a hash length
200+ * of 256 bits. The default is based upon aiming for .5 seconds to validate the
201+ * password when this class was added. Users should tune password verification to
202+ * their own systems.
203+ * @return the {@link Pbkdf2PasswordEncoder}
204+ * @since 5.8
205+ */
206+ public static Pbkdf2PasswordEncoder defaultsForSpringSecurity_v5_8 () {
207+ return new Pbkdf2PasswordEncoder ("" , DEFAULT_SALT_LENGTH , DEFAULT_ITERATIONS , DEFAULT_ALGORITHM );
132208 }
133209
134210 /**
@@ -153,6 +229,10 @@ public void setAlgorithm(SecretKeyFactoryAlgorithm secretKeyFactoryAlgorithm) {
153229 catch (NoSuchAlgorithmException ex ) {
154230 throw new IllegalArgumentException ("Invalid algorithm '" + algorithmName + "'." , ex );
155231 }
232+ if (this .overrideHashWidth ) {
233+ this .hashWidth = SecretKeyFactoryAlgorithm .PBKDF2WithHmacSHA1 .equals (secretKeyFactoryAlgorithm ) ? 160
234+ : SecretKeyFactoryAlgorithm .PBKDF2WithHmacSHA256 .equals (secretKeyFactoryAlgorithm ) ? 256 : 512 ;
235+ }
156236 }
157237
158238 /**
0 commit comments