28
28
import org .bson .BsonString ;
29
29
30
30
import javax .crypto .Mac ;
31
+ import javax .crypto .SecretKeyFactory ;
32
+ import javax .crypto .spec .PBEKeySpec ;
31
33
import javax .crypto .spec .SecretKeySpec ;
32
34
import javax .security .sasl .SaslClient ;
33
35
import javax .security .sasl .SaslException ;
36
38
import java .security .MessageDigest ;
37
39
import java .security .NoSuchAlgorithmException ;
38
40
import java .security .SecureRandom ;
41
+ import java .security .spec .InvalidKeySpecException ;
39
42
import java .util .Base64 ;
40
43
import java .util .HashMap ;
41
44
import java .util .Random ;
@@ -55,7 +58,6 @@ class ScramShaAuthenticator extends SaslAuthenticator {
55
58
private static final int MINIMUM_ITERATION_COUNT = 4096 ;
56
59
private static final String GS2_HEADER = "n,," ;
57
60
private static final int RANDOM_LENGTH = 24 ;
58
- private static final byte [] INT_1 = {0 , 0 , 0 , 1 };
59
61
60
62
ScramShaAuthenticator (final MongoCredentialWithCache credential , final ClusterConnectionMode clusterConnectionMode ,
61
63
@ Nullable final ServerApi serverApi ) {
@@ -65,8 +67,8 @@ class ScramShaAuthenticator extends SaslAuthenticator {
65
67
}
66
68
67
69
ScramShaAuthenticator (final MongoCredentialWithCache credential , final RandomStringGenerator randomStringGenerator ,
68
- final AuthenticationHashGenerator authenticationHashGenerator , final ClusterConnectionMode clusterConnectionMode ,
69
- @ Nullable final ServerApi serverApi ) {
70
+ final AuthenticationHashGenerator authenticationHashGenerator , final ClusterConnectionMode clusterConnectionMode ,
71
+ @ Nullable final ServerApi serverApi ) {
70
72
super (credential , clusterConnectionMode , serverApi );
71
73
this .randomStringGenerator = randomStringGenerator ;
72
74
this .authenticationHashGenerator = authenticationHashGenerator ;
@@ -127,6 +129,8 @@ class ScramShaSaslClient extends SaslClientImpl {
127
129
private final AuthenticationHashGenerator authenticationHashGenerator ;
128
130
private final String hAlgorithm ;
129
131
private final String hmacAlgorithm ;
132
+ private final String pbeAlgorithm ;
133
+ private final int keyLength ;
130
134
131
135
private String clientFirstMessageBare ;
132
136
private String clientNonce ;
@@ -137,16 +141,20 @@ class ScramShaSaslClient extends SaslClientImpl {
137
141
ScramShaSaslClient (
138
142
final MongoCredential credential ,
139
143
final RandomStringGenerator randomStringGenerator ,
140
- final AuthenticationHashGenerator authenticationHashGenerator ) {
144
+ final AuthenticationHashGenerator authenticationHashGenerator ) {
141
145
super (credential );
142
146
this .randomStringGenerator = randomStringGenerator ;
143
147
this .authenticationHashGenerator = authenticationHashGenerator ;
144
148
if (assertNotNull (credential .getAuthenticationMechanism ()).equals (SCRAM_SHA_1 )) {
145
149
hAlgorithm = "SHA-1" ;
146
150
hmacAlgorithm = "HmacSHA1" ;
151
+ pbeAlgorithm = "PBKDF2WithHmacSHA1" ;
152
+ keyLength = 160 ;
147
153
} else {
148
154
hAlgorithm = "SHA-256" ;
149
155
hmacAlgorithm = "HmacSHA256" ;
156
+ pbeAlgorithm = "PBKDF2WithHmacSHA256" ;
157
+ keyLength = 256 ;
150
158
}
151
159
}
152
160
@@ -224,7 +232,7 @@ String getClientProof(final String password, final String salt, final int iterat
224
232
CacheKey cacheKey = new CacheKey (hashedPasswordAndSalt , salt , iterationCount );
225
233
CacheValue cachedKeys = getMongoCredentialWithCache ().getFromCache (cacheKey , CacheValue .class );
226
234
if (cachedKeys == null ) {
227
- byte [] saltedPassword = hi (password . getBytes ( StandardCharsets . UTF_8 ) , Base64 .getDecoder ().decode (salt ), iterationCount );
235
+ byte [] saltedPassword = hi (password , Base64 .getDecoder ().decode (salt ), iterationCount );
228
236
byte [] clientKey = hmac (saltedPassword , "Client Key" );
229
237
byte [] serverKey = hmac (saltedPassword , "Server Key" );
230
238
cachedKeys = new CacheValue (clientKey , serverKey );
@@ -246,25 +254,15 @@ private byte[] h(final byte[] data) throws SaslException {
246
254
}
247
255
}
248
256
249
- private byte [] hi (final byte [] password , final byte [] salt , final int iterations ) throws SaslException {
257
+ private byte [] hi (final String password , final byte [] salt , final int iterations ) throws SaslException {
250
258
try {
251
- SecretKeySpec key = new SecretKeySpec (password , hmacAlgorithm );
252
- Mac mac = Mac .getInstance (hmacAlgorithm );
253
- mac .init (key );
254
- mac .update (salt );
255
- mac .update (INT_1 );
256
- byte [] result = mac .doFinal ();
257
- byte [] previous = null ;
258
- for (int i = 1 ; i < iterations ; i ++) {
259
- mac .update (previous != null ? previous : result );
260
- previous = mac .doFinal ();
261
- xorInPlace (result , previous );
262
- }
263
- return result ;
259
+ SecretKeyFactory secretKeyFactory = SecretKeyFactory .getInstance (pbeAlgorithm );
260
+ PBEKeySpec spec = new PBEKeySpec (password .toCharArray (), salt , iterations , keyLength );
261
+ return secretKeyFactory .generateSecret (spec ).getEncoded ();
264
262
} catch (NoSuchAlgorithmException e ) {
265
- throw new SaslException (format ("Algorithm for '%s' could not be found." , hmacAlgorithm ), e );
266
- } catch (InvalidKeyException e ) {
267
- throw new SaslException (format ("Invalid key for %s " , hmacAlgorithm ), e );
263
+ throw new SaslException (format ("Algorithm for '%s' could not be found." , pbeAlgorithm ), e );
264
+ } catch (InvalidKeySpecException e ) {
265
+ throw new SaslException (format ("Invalid key specification for '%s' " , pbeAlgorithm ), e );
268
266
}
269
267
}
270
268
0 commit comments