36
36
* <li>a configurable random salt value length (default is {@value #DEFAULT_SALT_LENGTH}
37
37
* bytes)</li>
38
38
* <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>
41
39
* <li>a configurable key derivation function (see {@link SecretKeyFactoryAlgorithm})</li>
42
40
* <li>a configurable secret appended to the random salt (default is empty)</li>
43
41
* </ul>
@@ -52,28 +50,43 @@ public class Pbkdf2PasswordEncoder implements PasswordEncoder {
52
50
53
51
private static final int DEFAULT_SALT_LENGTH = 16 ;
54
52
55
- private static final int DEFAULT_HASH_WIDTH = 256 ;
56
-
57
53
private static final int DEFAULT_ITERATIONS = 310000 ;
58
54
59
55
private final BytesKeyGenerator saltGenerator ;
60
56
61
57
private final byte [] secret ;
62
58
63
- private final int hashWidth ;
64
-
65
59
private final int iterations ;
66
60
67
61
private String algorithm = SecretKeyFactoryAlgorithm .PBKDF2WithHmacSHA256 .name ();
68
62
63
+ private int hashWidth = 256 ; // SHA-256
64
+
65
+ // @formatter:off
66
+ /*
67
+ The length of the hash should be derived from the hashing algorithm.
68
+
69
+ For example:
70
+ SHA-1 - 160 bits (20 bytes)
71
+ SHA-256 - 256 bits (32 bytes)
72
+ SHA-512 - 512 bits (64 bytes)
73
+
74
+ However, the original configuration for PBKDF2 was hashWidth=256 and algorithm=SHA-1, which is incorrect.
75
+ The default configuration has been updated to hashWidth=256 and algorithm=SHA-256 (see gh-10506).
76
+ In order to preserve backwards compatibility, the variable 'overrideHashWidth' has been introduced
77
+ to indicate usage of the deprecated constructors that allow (and honor) a hashWidth parameter.
78
+ */
79
+ // @formatter:on
80
+ private boolean overrideHashWidth = true ;
81
+
69
82
private boolean encodeHashAsBase64 ;
70
83
71
84
/**
72
85
* Constructs a PBKDF2 password encoder with no additional secret value. There will be
73
86
* 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.
87
+ * iterations and SHA-256 algorithm. The default is based upon aiming for .5 seconds
88
+ * to validate the password when this class was added. Users should tune password
89
+ * verification to their own systems.
77
90
*/
78
91
public Pbkdf2PasswordEncoder () {
79
92
this ("" );
@@ -82,24 +95,22 @@ public Pbkdf2PasswordEncoder() {
82
95
/**
83
96
* Constructs a standard password encoder with a secret value which is also included
84
97
* 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.
98
+ * bytes, {@value #DEFAULT_ITERATIONS} iterations and SHA-256 algorithm.
87
99
* @param secret the secret key used in the encoding process (should not be shared)
88
100
*/
89
101
public Pbkdf2PasswordEncoder (CharSequence secret ) {
90
- this (secret , DEFAULT_SALT_LENGTH , DEFAULT_ITERATIONS , DEFAULT_HASH_WIDTH );
102
+ this (secret , DEFAULT_SALT_LENGTH );
91
103
}
92
104
93
105
/**
94
106
* 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.
107
+ * There will be {@value #DEFAULT_ITERATIONS} iterations and SHA-256 algorithm.
97
108
* @param secret the secret
98
109
* @param saltLength the salt length (in bytes)
99
110
* @since 5.5
100
111
*/
101
112
public Pbkdf2PasswordEncoder (CharSequence secret , int saltLength ) {
102
- this (secret , saltLength , DEFAULT_ITERATIONS , DEFAULT_HASH_WIDTH );
113
+ this (secret , saltLength , DEFAULT_ITERATIONS , SecretKeyFactoryAlgorithm . PBKDF2WithHmacSHA256 );
103
114
}
104
115
105
116
/**
@@ -109,7 +120,11 @@ public Pbkdf2PasswordEncoder(CharSequence secret, int saltLength) {
109
120
* @param iterations the number of iterations. Users should aim for taking about .5
110
121
* seconds on their own system.
111
122
* @param hashWidth the size of the hash (in bits)
123
+ * @deprecated Use
124
+ * {@link #Pbkdf2PasswordEncoder(CharSequence, int, int, SecretKeyFactoryAlgorithm)}
125
+ * instead
112
126
*/
127
+ @ Deprecated
113
128
public Pbkdf2PasswordEncoder (CharSequence secret , int iterations , int hashWidth ) {
114
129
this (secret , DEFAULT_SALT_LENGTH , iterations , hashWidth );
115
130
}
@@ -123,12 +138,36 @@ public Pbkdf2PasswordEncoder(CharSequence secret, int iterations, int hashWidth)
123
138
* seconds on their own system.
124
139
* @param hashWidth the size of the hash (in bits)
125
140
* @since 5.5
141
+ * @deprecated Use
142
+ * {@link #Pbkdf2PasswordEncoder(CharSequence, int, int, SecretKeyFactoryAlgorithm)}
143
+ * instead
126
144
*/
145
+ @ Deprecated
127
146
public Pbkdf2PasswordEncoder (CharSequence secret , int saltLength , int iterations , int hashWidth ) {
128
147
this .secret = Utf8 .encode (secret );
129
148
this .saltGenerator = KeyGenerators .secureRandom (saltLength );
130
149
this .iterations = iterations ;
131
150
this .hashWidth = hashWidth ;
151
+ this .overrideHashWidth = false ; // Honor 'hashWidth' to preserve backwards
152
+ // compatibility
153
+ }
154
+
155
+ /**
156
+ * Constructs a standard password encoder with a secret value as well as salt length,
157
+ * iterations and algorithm.
158
+ * @param secret the secret
159
+ * @param saltLength the salt length (in bytes)
160
+ * @param iterations the number of iterations. Users should aim for taking about .5
161
+ * seconds on their own system.
162
+ * @param secretKeyFactoryAlgorithm the algorithm to use
163
+ * @since 6.0
164
+ */
165
+ public Pbkdf2PasswordEncoder (CharSequence secret , int saltLength , int iterations ,
166
+ SecretKeyFactoryAlgorithm secretKeyFactoryAlgorithm ) {
167
+ this .secret = Utf8 .encode (secret );
168
+ this .saltGenerator = KeyGenerators .secureRandom (saltLength );
169
+ this .iterations = iterations ;
170
+ setAlgorithm (secretKeyFactoryAlgorithm );
132
171
}
133
172
134
173
/**
@@ -153,6 +192,10 @@ public void setAlgorithm(SecretKeyFactoryAlgorithm secretKeyFactoryAlgorithm) {
153
192
catch (NoSuchAlgorithmException ex ) {
154
193
throw new IllegalArgumentException ("Invalid algorithm '" + algorithmName + "'." , ex );
155
194
}
195
+ if (this .overrideHashWidth ) {
196
+ this .hashWidth = SecretKeyFactoryAlgorithm .PBKDF2WithHmacSHA1 .equals (secretKeyFactoryAlgorithm ) ? 160
197
+ : SecretKeyFactoryAlgorithm .PBKDF2WithHmacSHA256 .equals (secretKeyFactoryAlgorithm ) ? 256 : 512 ;
198
+ }
156
199
}
157
200
158
201
/**
0 commit comments