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.PemUtils;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.component.ComponentValidationException;
|
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.jose.jws.JWSBuilder;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.rule.CryptoInitRule;
|
import org.keycloak.rule.CryptoInitRule;
|
||||||
|
@ -63,8 +66,12 @@ public class CryptoPerfTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void perfTest(Runnable runnable, String testName) {
|
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();
|
long start = Time.currentTimeMillis();
|
||||||
for (int i=0 ; i<COUNT_ITERATIONS ; i++) {
|
for (int i=0 ; i<count ; i++) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
}
|
}
|
||||||
long took = Time.currentTimeMillis() - start;
|
long took = Time.currentTimeMillis() - start;
|
||||||
|
@ -102,6 +109,39 @@ public class CryptoPerfTest {
|
||||||
perfTest(() -> testTokenSignAndVerify(keyPair), "testSignAndVerifyTokens2048");
|
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) {
|
private KeyPair generateKeys(int size) {
|
||||||
KeyPair keyPair;
|
KeyPair keyPair;
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class Pbkdf2Sha256PasswordHashProviderFactory extends AbstractPbkdf2Passw
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PasswordHashProvider create(KeycloakSession session) {
|
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
|
@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 {
|
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();
|
byte[] key = SecretKeyFactory.getInstance(algorithm).generateSecret(spec).getEncoded();
|
||||||
if (expectedSuccess) {
|
if (expectedSuccess) {
|
||||||
assertEquals(Base64.encodeBytes(key), credential.getPasswordSecretData().getValue());
|
assertEquals(Base64.encodeBytes(key), credential.getPasswordSecretData().getValue());
|
||||||
|
|
Loading…
Reference in a new issue