Make sure PBKDF2 providers are using the expect size for derived keys (#16798)
Closes #16797
This commit is contained in:
parent
f8f112d8d2
commit
d97b9c48c4
3 changed files with 49 additions and 3 deletions
|
@ -35,6 +35,9 @@ import org.keycloak.common.util.KeyUtils;
|
|||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.component.ComponentValidationException;
|
||||
import org.keycloak.credential.hash.Pbkdf2PasswordHashProvider;
|
||||
import org.keycloak.credential.hash.Pbkdf2Sha256PasswordHashProviderFactory;
|
||||
import org.keycloak.credential.hash.Pbkdf2Sha512PasswordHashProviderFactory;
|
||||
import org.keycloak.jose.jws.JWSBuilder;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.rule.CryptoInitRule;
|
||||
|
@ -63,8 +66,12 @@ public class CryptoPerfTest {
|
|||
}
|
||||
|
||||
private void perfTest(Runnable runnable, String testName) {
|
||||
perfTest(runnable, testName, COUNT_ITERATIONS);
|
||||
}
|
||||
|
||||
private void perfTest(Runnable runnable, String testName, int count) {
|
||||
long start = Time.currentTimeMillis();
|
||||
for (int i=0 ; i<COUNT_ITERATIONS ; i++) {
|
||||
for (int i=0 ; i<count ; i++) {
|
||||
runnable.run();
|
||||
}
|
||||
long took = Time.currentTimeMillis() - start;
|
||||
|
@ -102,6 +109,39 @@ public class CryptoPerfTest {
|
|||
perfTest(() -> testTokenSignAndVerify(keyPair), "testSignAndVerifyTokens2048");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPbkdf256() {
|
||||
int iterations = 600 * 1000;
|
||||
int derivedKeySize = 256;
|
||||
String providerId = Pbkdf2Sha256PasswordHashProviderFactory.ID;
|
||||
String algorithm = Pbkdf2Sha256PasswordHashProviderFactory.PBKDF2_ALGORITHM;
|
||||
perfTestPasswordHashins(iterations, derivedKeySize, providerId, algorithm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPbkdf512() {
|
||||
int iterations = 210 * 1000;
|
||||
int derivedKeySize = 512;
|
||||
String providerId = Pbkdf2Sha512PasswordHashProviderFactory.ID;
|
||||
String algorithm = Pbkdf2Sha512PasswordHashProviderFactory.PBKDF2_ALGORITHM;
|
||||
perfTestPasswordHashins(iterations, derivedKeySize, providerId, algorithm);
|
||||
}
|
||||
|
||||
private void perfTestPasswordHashins(int iterations, int derivedKeySize, String providerId, String algorithm) {
|
||||
Pbkdf2PasswordHashProvider provider = new Pbkdf2PasswordHashProvider(
|
||||
providerId,
|
||||
algorithm,
|
||||
iterations,
|
||||
0,
|
||||
derivedKeySize);
|
||||
|
||||
perfTest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
provider.encode("password", -1);
|
||||
}
|
||||
}, "testPbkdf512", 1);
|
||||
}
|
||||
|
||||
private KeyPair generateKeys(int size) {
|
||||
KeyPair keyPair;
|
||||
|
|
|
@ -17,7 +17,7 @@ public class Pbkdf2Sha256PasswordHashProviderFactory extends AbstractPbkdf2Passw
|
|||
|
||||
@Override
|
||||
public PasswordHashProvider create(KeycloakSession session) {
|
||||
return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM, DEFAULT_ITERATIONS, getMaxPaddingLength());
|
||||
return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM, DEFAULT_ITERATIONS, getMaxPaddingLength(), 256);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -278,7 +278,13 @@ public class PasswordHashingTest extends AbstractTestRealmKeycloakTest {
|
|||
}
|
||||
|
||||
private void assertEncoded(PasswordCredentialModel credential, String password, byte[] salt, String algorithm, int iterations, boolean expectedSuccess) throws Exception {
|
||||
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, 512);
|
||||
int keyLength = 512;
|
||||
|
||||
if (Pbkdf2Sha256PasswordHashProviderFactory.ID.equals(credential.getPasswordCredentialData().getAlgorithm())) {
|
||||
keyLength = 256;
|
||||
}
|
||||
|
||||
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, keyLength);
|
||||
byte[] key = SecretKeyFactory.getInstance(algorithm).generateSecret(spec).getEncoded();
|
||||
if (expectedSuccess) {
|
||||
assertEquals(Base64.encodeBytes(key), credential.getPasswordSecretData().getValue());
|
||||
|
|
Loading…
Reference in a new issue