mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-23 02:35:11 +01:00
#685 Allow to configure number of rounds for PBKDF2
This commit is contained in:
parent
86db805c15
commit
79a3858b29
@ -1,8 +1,6 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||
import fr.xephi.authme.security.crypts.Pbkdf2;
|
||||
import fr.xephi.authme.security.crypts.Pbkdf2Django;
|
||||
|
||||
/**
|
||||
* Hash algorithms supported by AuthMe.
|
||||
@ -19,8 +17,8 @@ public enum HashAlgorithm {
|
||||
MD5(fr.xephi.authme.security.crypts.MD5.class),
|
||||
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
|
||||
MYBB(fr.xephi.authme.security.crypts.MYBB.class),
|
||||
PBKDF2(Pbkdf2.class),
|
||||
PBKDF2DJANGO(Pbkdf2Django.class),
|
||||
PBKDF2(fr.xephi.authme.security.crypts.Pbkdf2.class),
|
||||
PBKDF2DJANGO(fr.xephi.authme.security.crypts.Pbkdf2Django.class),
|
||||
PHPBB(fr.xephi.authme.security.crypts.PHPBB.class),
|
||||
PHPFUSION(fr.xephi.authme.security.crypts.PHPFUSION.class),
|
||||
@Deprecated
|
||||
|
@ -3,18 +3,30 @@ package fr.xephi.authme.security.crypts;
|
||||
import de.rtner.misc.BinTools;
|
||||
import de.rtner.security.auth.spi.PBKDF2Engine;
|
||||
import de.rtner.security.auth.spi.PBKDF2Parameters;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
public class Pbkdf2 extends HexSaltedMethod {
|
||||
|
||||
private static final int NUMBER_OF_ITERATIONS = 10_000;
|
||||
private static final int DEFAULT_ROUNDS = 10_000;
|
||||
private int numberOfRounds;
|
||||
|
||||
@Inject
|
||||
Pbkdf2(Settings settings) {
|
||||
int configuredRounds = settings.getProperty(SecuritySettings.PBKDF2_NUMBER_OF_ROUNDS);
|
||||
this.numberOfRounds = configuredRounds > 0 ? configuredRounds : DEFAULT_ROUNDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String result = "pbkdf2_sha256$" + NUMBER_OF_ITERATIONS + "$" + salt + "$";
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), NUMBER_OF_ITERATIONS);
|
||||
String result = "pbkdf2_sha256$" + numberOfRounds + "$" + salt + "$";
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), numberOfRounds);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
|
||||
return result + BinTools.bin2hex(engine.deriveKey(password, 64));
|
||||
@ -26,9 +38,16 @@ public class Pbkdf2 extends HexSaltedMethod {
|
||||
if (line.length != 4) {
|
||||
return false;
|
||||
}
|
||||
int iterations;
|
||||
try {
|
||||
iterations = Integer.parseInt(line[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
ConsoleLogger.logException("Cannot read number of rounds for Pbkdf2", e);
|
||||
return false;
|
||||
}
|
||||
String salt = line[2];
|
||||
byte[] derivedKey = BinTools.hex2bin(line[3]);
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), 10000, derivedKey);
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "UTF-8", salt.getBytes(), iterations, derivedKey);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
return engine.verifyKey(password);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import de.rtner.security.auth.spi.PBKDF2Engine;
|
||||
import de.rtner.security.auth.spi.PBKDF2Parameters;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.security.crypts.description.AsciiRestricted;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
@ -32,8 +31,7 @@ public class Pbkdf2Django extends HexSaltedMethod {
|
||||
try {
|
||||
iterations = Integer.parseInt(line[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
ConsoleLogger.warning("Could not read number of rounds for Pbkdf2Django:"
|
||||
+ StringUtils.formatException(e));
|
||||
ConsoleLogger.logException("Could not read number of rounds for Pbkdf2Django:", e);
|
||||
return false;
|
||||
}
|
||||
String salt = line[2];
|
||||
|
@ -86,6 +86,10 @@ public class SecuritySettings implements SettingsHolder {
|
||||
public static final Property<List<String>> LEGACY_HASHES =
|
||||
new EnumSetProperty<>(HashAlgorithm.class, "settings.security.legacyHashes");
|
||||
|
||||
@Comment("Number of rounds to use if passwordHash is set to PBKDF2. Default is 10000")
|
||||
public static final Property<Integer> PBKDF2_NUMBER_OF_ROUNDS =
|
||||
newProperty("settings.security.pbkdf2Rounds", 10000);
|
||||
|
||||
@Comment({"Prevent unsafe passwords from being used; put them in lowercase!",
|
||||
"You should always set 'help' as unsafePassword due to possible conflicts.",
|
||||
"unsafePasswords:",
|
||||
|
@ -32,6 +32,7 @@ public class HashAlgorithmIntegrationTest {
|
||||
Settings settings = mock(Settings.class);
|
||||
given(settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND)).willReturn(8);
|
||||
given(settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH)).willReturn(16);
|
||||
given(settings.getProperty(SecuritySettings.PBKDF2_NUMBER_OF_ROUNDS)).willReturn(10_000);
|
||||
injector = new InjectorBuilder().addDefaultHandlers("fr.xephi.authme").create();
|
||||
injector.register(Settings.class, settings);
|
||||
}
|
||||
|
@ -1,16 +1,44 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Test for {@link Pbkdf2}.
|
||||
*/
|
||||
public class Pbkdf2Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public Pbkdf2Test() {
|
||||
super(new Pbkdf2(),
|
||||
super(new Pbkdf2(mockSettings()),
|
||||
"pbkdf2_sha256$10000$b25801311edf$093E38B16DFF13FCE5CD64D5D888EE6E0376A3E572FE5DA6749515EA0F384413223A21C464B0BE899E64084D1FFEFD44F2AC768453C87F41B42CC6954C416900", // password
|
||||
"pbkdf2_sha256$10000$fe705da06c57$A41527BD58FED9C9E6F452FC1BA8B0C4C4224ECC63E37F71EB1A0865D2AB81BBFEBCA9B7B6A6E8AEF4717B43F8EB6FB4EDEFFBB399D9D991EF7E23013595BAF0", // PassWord1
|
||||
"pbkdf2_sha256$10000$05603593cdda$1D30D1D90D826C866755969F06C312E21CC3E8DA0B777E2C764700E4E1FD890B731FAF44753D68F3FC025D3EAA709E800FBF2AF61DB23464311FCE7D35353A30", // &^%te$t?Pw@_
|
||||
"pbkdf2_sha256$10000$fb944d66d754$F7E3BF8CB07CE3B3C8C5C534F803252F7B4FD58832E33BA62BA46CA06F23BAE12BE03A9CB5874BCFD4469E42972406F920E59F002247B23C22A8CF3D0E7BFFE0"); // âË_3(íù*
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectMatchForHashWithOtherRoundNumber() {
|
||||
// given
|
||||
Pbkdf2 pbkdf2 = new Pbkdf2(mockSettings());
|
||||
String hash = "pbkdf2_sha256$4128$3469b0d48b702046$DC8A54351008C6054E12FB19E0BF8A4EA6D4165E0EDC97A1ECD15231037C382DE5BF85D07D5BC9D1ADF9BBFE4CE257C6059FB1B9FF65DB69D8B205F064BE0DA9";
|
||||
String clearText = "PassWord1";
|
||||
|
||||
// when
|
||||
boolean isMatch = pbkdf2.comparePassword(clearText, new HashedPassword(hash), "");
|
||||
|
||||
// then
|
||||
assertThat(isMatch, equalTo(true));
|
||||
}
|
||||
|
||||
private static Settings mockSettings() {
|
||||
Settings settings = mock(Settings.class);
|
||||
given(settings.getProperty(SecuritySettings.PBKDF2_NUMBER_OF_ROUNDS)).willReturn(4128);
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user