Skip to content

Commit 7d80cef

Browse files
authored
Use JCA provider for implementation of PBKDF2 (#1448)
Previously the driver implemented the PBKDF2 (Password-based-Key-Derivative-Function) function itself. With this change it instead looks up an implementation of either PBKDF2WithHmacSHA1 or PBKDF2WithHmacSHA256 from the JCA provider via SecretKeyFactory#getInstance. JAVA-5507
1 parent 96540ca commit 7d80cef

File tree

1 file changed

+20
-22
lines changed

1 file changed

+20
-22
lines changed

driver-core/src/main/com/mongodb/internal/connection/ScramShaAuthenticator.java

+20-22
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.bson.BsonString;
2929

3030
import javax.crypto.Mac;
31+
import javax.crypto.SecretKeyFactory;
32+
import javax.crypto.spec.PBEKeySpec;
3133
import javax.crypto.spec.SecretKeySpec;
3234
import javax.security.sasl.SaslClient;
3335
import javax.security.sasl.SaslException;
@@ -36,6 +38,7 @@
3638
import java.security.MessageDigest;
3739
import java.security.NoSuchAlgorithmException;
3840
import java.security.SecureRandom;
41+
import java.security.spec.InvalidKeySpecException;
3942
import java.util.Base64;
4043
import java.util.HashMap;
4144
import java.util.Random;
@@ -55,7 +58,6 @@ class ScramShaAuthenticator extends SaslAuthenticator {
5558
private static final int MINIMUM_ITERATION_COUNT = 4096;
5659
private static final String GS2_HEADER = "n,,";
5760
private static final int RANDOM_LENGTH = 24;
58-
private static final byte[] INT_1 = {0, 0, 0, 1};
5961

6062
ScramShaAuthenticator(final MongoCredentialWithCache credential, final ClusterConnectionMode clusterConnectionMode,
6163
@Nullable final ServerApi serverApi) {
@@ -65,8 +67,8 @@ class ScramShaAuthenticator extends SaslAuthenticator {
6567
}
6668

6769
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) {
7072
super(credential, clusterConnectionMode, serverApi);
7173
this.randomStringGenerator = randomStringGenerator;
7274
this.authenticationHashGenerator = authenticationHashGenerator;
@@ -127,6 +129,8 @@ class ScramShaSaslClient extends SaslClientImpl {
127129
private final AuthenticationHashGenerator authenticationHashGenerator;
128130
private final String hAlgorithm;
129131
private final String hmacAlgorithm;
132+
private final String pbeAlgorithm;
133+
private final int keyLength;
130134

131135
private String clientFirstMessageBare;
132136
private String clientNonce;
@@ -137,16 +141,20 @@ class ScramShaSaslClient extends SaslClientImpl {
137141
ScramShaSaslClient(
138142
final MongoCredential credential,
139143
final RandomStringGenerator randomStringGenerator,
140-
final AuthenticationHashGenerator authenticationHashGenerator) {
144+
final AuthenticationHashGenerator authenticationHashGenerator) {
141145
super(credential);
142146
this.randomStringGenerator = randomStringGenerator;
143147
this.authenticationHashGenerator = authenticationHashGenerator;
144148
if (assertNotNull(credential.getAuthenticationMechanism()).equals(SCRAM_SHA_1)) {
145149
hAlgorithm = "SHA-1";
146150
hmacAlgorithm = "HmacSHA1";
151+
pbeAlgorithm = "PBKDF2WithHmacSHA1";
152+
keyLength = 160;
147153
} else {
148154
hAlgorithm = "SHA-256";
149155
hmacAlgorithm = "HmacSHA256";
156+
pbeAlgorithm = "PBKDF2WithHmacSHA256";
157+
keyLength = 256;
150158
}
151159
}
152160

@@ -224,7 +232,7 @@ String getClientProof(final String password, final String salt, final int iterat
224232
CacheKey cacheKey = new CacheKey(hashedPasswordAndSalt, salt, iterationCount);
225233
CacheValue cachedKeys = getMongoCredentialWithCache().getFromCache(cacheKey, CacheValue.class);
226234
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);
228236
byte[] clientKey = hmac(saltedPassword, "Client Key");
229237
byte[] serverKey = hmac(saltedPassword, "Server Key");
230238
cachedKeys = new CacheValue(clientKey, serverKey);
@@ -246,25 +254,15 @@ private byte[] h(final byte[] data) throws SaslException {
246254
}
247255
}
248256

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 {
250258
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();
264262
} 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);
268266
}
269267
}
270268

0 commit comments

Comments
 (0)