mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-12-30 12:37:34 +01:00
#364 Create first EncryptionMethod tests
This commit is contained in:
parent
4f6c7d579c
commit
bf7a0c5a49
@ -1,6 +1,6 @@
|
|||||||
package fr.xephi.authme.security;
|
package fr.xephi.authme.security;
|
||||||
|
|
||||||
import org.apache.commons.lang.ObjectUtils.Null;
|
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@ -33,21 +33,21 @@ public enum HashAlgorithm {
|
|||||||
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class),
|
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class),
|
||||||
BCRYPT2Y(fr.xephi.authme.security.crypts.BCRYPT2Y.class),
|
BCRYPT2Y(fr.xephi.authme.security.crypts.BCRYPT2Y.class),
|
||||||
SALTEDSHA512(fr.xephi.authme.security.crypts.SALTEDSHA512.class),
|
SALTEDSHA512(fr.xephi.authme.security.crypts.SALTEDSHA512.class),
|
||||||
CUSTOM(Null.class);
|
CUSTOM(null);
|
||||||
|
|
||||||
final Class<?> classe;
|
final Class<? extends EncryptionMethod> clazz;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for HashAlgorithm.
|
* Constructor for HashAlgorithm.
|
||||||
*
|
*
|
||||||
* @param classe The class of the hash implementation.
|
* @param clazz The class of the hash implementation.
|
||||||
*/
|
*/
|
||||||
HashAlgorithm(Class<?> classe) {
|
HashAlgorithm(Class<? extends EncryptionMethod> clazz) {
|
||||||
this.classe = classe;
|
this.clazz = clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?> getclasse() {
|
public Class<? extends EncryptionMethod> getClazz() {
|
||||||
return classe;
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public class PasswordSecurity {
|
|||||||
EncryptionMethod method;
|
EncryptionMethod method;
|
||||||
try {
|
try {
|
||||||
if (alg != HashAlgorithm.CUSTOM)
|
if (alg != HashAlgorithm.CUSTOM)
|
||||||
method = (EncryptionMethod) alg.getclasse().newInstance();
|
method = alg.getClazz().newInstance();
|
||||||
else method = null;
|
else method = null;
|
||||||
} catch (InstantiationException | IllegalAccessException e) {
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
throw new NoSuchAlgorithmException("Problem with hash algorithm '" + alg + "'", e);
|
throw new NoSuchAlgorithmException("Problem with hash algorithm '" + alg + "'", e);
|
||||||
@ -131,10 +131,11 @@ public class PasswordSecurity {
|
|||||||
HashAlgorithm algorithm = Settings.getPasswordHash;
|
HashAlgorithm algorithm = Settings.getPasswordHash;
|
||||||
EncryptionMethod method;
|
EncryptionMethod method;
|
||||||
try {
|
try {
|
||||||
if (algorithm != HashAlgorithm.CUSTOM)
|
if (algorithm != HashAlgorithm.CUSTOM) {
|
||||||
method = (EncryptionMethod) algorithm.getclasse().newInstance();
|
method = algorithm.getClazz().newInstance();
|
||||||
else
|
} else {
|
||||||
method = null;
|
method = null;
|
||||||
|
}
|
||||||
|
|
||||||
PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName);
|
PasswordEncryptionEvent event = new PasswordEncryptionEvent(method, playerName);
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
@ -161,7 +162,7 @@ public class PasswordSecurity {
|
|||||||
for (HashAlgorithm algo : HashAlgorithm.values()) {
|
for (HashAlgorithm algo : HashAlgorithm.values()) {
|
||||||
if (algo != HashAlgorithm.CUSTOM) {
|
if (algo != HashAlgorithm.CUSTOM) {
|
||||||
try {
|
try {
|
||||||
EncryptionMethod method = (EncryptionMethod) algo.getclasse().newInstance();
|
EncryptionMethod method = algo.getClazz().newInstance();
|
||||||
if (method.comparePassword(hash, password, playerName)) {
|
if (method.comparePassword(hash, password, playerName)) {
|
||||||
PlayerAuth nAuth = AuthMe.getInstance().database.getAuth(playerName);
|
PlayerAuth nAuth = AuthMe.getInstance().database.getAuth(playerName);
|
||||||
if (nAuth != null) {
|
if (nAuth != null) {
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
package fr.xephi.authme.security;
|
package fr.xephi.authme.security;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Xephi59
|
|
||||||
*/
|
|
||||||
public class RandomString {
|
public class RandomString {
|
||||||
|
|
||||||
private static final char[] chars = new char[36];
|
private static final char[] chars = new char[36];
|
||||||
|
private static final Random RANDOM = new SecureRandom();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
for (int idx = 0; idx < 10; ++idx)
|
for (int idx = 0; idx < 10; ++idx) {
|
||||||
chars[idx] = (char) ('0' + idx);
|
chars[idx] = (char) ('0' + idx);
|
||||||
for (int idx = 10; idx < 36; ++idx)
|
}
|
||||||
|
for (int idx = 10; idx < 36; ++idx) {
|
||||||
chars[idx] = (char) ('a' + idx - 10);
|
chars[idx] = (char) ('a' + idx - 10);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
|
||||||
@ -34,4 +35,15 @@ public class RandomString {
|
|||||||
return new String(buf);
|
return new String(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String generate(int length) {
|
||||||
|
if (length < 0) {
|
||||||
|
throw new IllegalArgumentException("Length must be positive but was " + length);
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder(length);
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
sb.append(chars[RANDOM.nextInt(chars.length)]);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,8 @@ public class BCRYPT implements EncryptionMethod {
|
|||||||
* @param s the string to decode
|
* @param s the string to decode
|
||||||
* @param maxolen the maximum number of bytes to decode
|
* @param maxolen the maximum number of bytes to decode
|
||||||
*
|
*
|
||||||
* @return an array containing the decoded bytes * @throws IllegalArgumentException if maxolen is invalid * @throws IllegalArgumentException
|
* @return an array containing the decoded bytes
|
||||||
|
* @throws IllegalArgumentException if maxolen is invalid
|
||||||
*/
|
*/
|
||||||
private static byte[] decode_base64(String s, int maxolen)
|
private static byte[] decode_base64(String s, int maxolen)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for implementations of {@link EncryptionMethod}.
|
||||||
|
*/
|
||||||
|
// TODO #358: Remove NoSuchAlgorithm try-catch-es when no longer necessary
|
||||||
|
public abstract class AbstractEncryptionMethodTest {
|
||||||
|
|
||||||
|
public static final String USERNAME = "Test_Player00";
|
||||||
|
public static final String[] GIVEN_PASSWORDS = {"password", "PassWord1", "&^%te$t?Pw@_", "âË_3(íù*"};
|
||||||
|
private static final String[] INTERNAL_PASSWORDS = {"test1234", "Ab_C73", "(!#&$~`_-Aa0", "Ûïé1&?+A"};
|
||||||
|
|
||||||
|
private EncryptionMethod method;
|
||||||
|
private Map<String, String> hashes;
|
||||||
|
|
||||||
|
public AbstractEncryptionMethodTest(EncryptionMethod method, String hash0, String hash1,
|
||||||
|
String hash2, String hash3) {
|
||||||
|
this.method = method;
|
||||||
|
hashes = new HashMap<>();
|
||||||
|
hashes.put(GIVEN_PASSWORDS[0], hash0);
|
||||||
|
hashes.put(GIVEN_PASSWORDS[1], hash1);
|
||||||
|
hashes.put(GIVEN_PASSWORDS[2], hash2);
|
||||||
|
hashes.put(GIVEN_PASSWORDS[3], hash3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGivenPasswords() {
|
||||||
|
for (String password : GIVEN_PASSWORDS) {
|
||||||
|
try {
|
||||||
|
assertTrue("Hash for password '" + password + "' should match",
|
||||||
|
method.comparePassword(hashes.get(password), password, USERNAME));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new IllegalStateException("EncryptionMethod '" + method + "' threw exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPasswordEquality() {
|
||||||
|
for (String password : INTERNAL_PASSWORDS) {
|
||||||
|
try {
|
||||||
|
String hash = method.getHash(password, getSalt(method), USERNAME);
|
||||||
|
assertTrue("Generated hash for '" + password + "' should match password (hash = '" + hash + "')",
|
||||||
|
method.comparePassword(hash, password, USERNAME));
|
||||||
|
if (!password.equals(password.toLowerCase())) {
|
||||||
|
assertFalse("Lower-case of '" + password + "' should not match generated hash '" + hash + "'",
|
||||||
|
method.comparePassword(hash, password.toLowerCase(), USERNAME));
|
||||||
|
}
|
||||||
|
if (!password.equals(password.toUpperCase())) {
|
||||||
|
assertFalse("Upper-case of '" + password + "' should not match generated hash '" + hash + "'",
|
||||||
|
method.comparePassword(hash, password.toUpperCase(), USERNAME));
|
||||||
|
}
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new IllegalStateException("EncryptionMethod '" + method + "' threw exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generateHashes(EncryptionMethod method) {
|
||||||
|
System.out.println("AbstractEncryptionMethodTest.testGivenPasswords(method,");
|
||||||
|
for (String password : GIVEN_PASSWORDS) {
|
||||||
|
try {
|
||||||
|
System.out.println("\t\"" + method.getHash(password, getSalt(method), "USERNAME")
|
||||||
|
+ "\", // " + password);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException("Could not generate hash", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println(");");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO #358: Remove this method and use the new salt method on the interface
|
||||||
|
private static String getSalt(EncryptionMethod method) {
|
||||||
|
try {
|
||||||
|
if (method instanceof BCRYPT) {
|
||||||
|
return BCRYPT.gensalt();
|
||||||
|
} else if (method instanceof MD5) {
|
||||||
|
return "";
|
||||||
|
} else if (method instanceof JOOMLA) {
|
||||||
|
return PasswordSecurity.createSalt(32);
|
||||||
|
} else if (method instanceof SHA256) {
|
||||||
|
return PasswordSecurity.createSalt(16);
|
||||||
|
}
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Unknown EncryptionMethod for salt generation");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link BCRYPT}.
|
||||||
|
*/
|
||||||
|
public class BcryptTest extends AbstractEncryptionMethodTest {
|
||||||
|
|
||||||
|
public BcryptTest() {
|
||||||
|
super(new BCRYPT(),
|
||||||
|
"$2a$10$6iATmYgwJVc3YONhVcZFve3Cfb5GnwvKhJ20r.hMjmcNkIT9.Uh9K", // password
|
||||||
|
"$2a$10$LOhUxhEcS0vgDPv/jkXvCurNb7LjP9xUlEolJGk.Uhgikqc6FtIOi", // PassWord1
|
||||||
|
"$2a$10$j9da7SGiaakWhzIms9BtwemLUeIhSEphGUQ3XSlvYgpYsGnGCKRBa", // &^%te$t?Pw@_
|
||||||
|
"$2a$10$mkmO3SNzQT/SA5fG/8P8PePz/DI/kKpIH8vd1Owf/fQfFu6F0QyWO" // âË_3(íù*
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link JOOMLA}.
|
||||||
|
*/
|
||||||
|
public class JoomlaTest extends AbstractEncryptionMethodTest {
|
||||||
|
|
||||||
|
public JoomlaTest() {
|
||||||
|
super(new JOOMLA(),
|
||||||
|
"b18c99813cd96df3a706652f47177490:377c4aaf92c5ed57711306909e6065ca", // password
|
||||||
|
"c5af71da91a8841d95937ba24a5b7fdb:07068e5850930b794526a614438cafc7", // PassWord1
|
||||||
|
"f5fccd5166af7080833d7c7a6a531295:7cb6eeabcfac67ffe1341ec43375a9e6", // &^%te$t?Pw@_
|
||||||
|
"dce946c6864d2223caeed9d80f356bcc:0c55fa3eca8c42557a989700ac1c4b8e" // âË_3(íù*
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
src/test/java/fr/xephi/authme/security/crypts/Md5Test.java
Normal file
17
src/test/java/fr/xephi/authme/security/crypts/Md5Test.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link MD5}.
|
||||||
|
*/
|
||||||
|
public class Md5Test extends AbstractEncryptionMethodTest {
|
||||||
|
|
||||||
|
public Md5Test() {
|
||||||
|
super(new MD5(),
|
||||||
|
"5f4dcc3b5aa765d61d8327deb882cf99", // password
|
||||||
|
"f2126d405f46ed603ff5b2950f062c96", // PassWord1
|
||||||
|
"0833dcd2bc741f90c46bbac5498fd08f", // &^%te$t?Pw@_
|
||||||
|
"d1accd961cb7b688c87278191c1dfed3" // âË_3(íù*
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link SHA256}.
|
||||||
|
*/
|
||||||
|
public class Sha256Test extends AbstractEncryptionMethodTest {
|
||||||
|
|
||||||
|
public Sha256Test() {
|
||||||
|
super(new SHA256(),
|
||||||
|
"$SHA$11aa0706173d7272$dbba96681c2ae4e0bfdf226d70fbbc5e4ee3d8071faa613bc533fe8a64817d10", // password
|
||||||
|
"$SHA$3c72a18a29b08d40$8e50a7a4f69a80f4893dc921eac84bd74b3f9ebfa22908302c9965eac3aa45e5", // PassWord1
|
||||||
|
"$SHA$584cea1cfab90030$adc006330e73d81e463fe02a4fe9b17bdbbcc05955bff72fb27cf2089f0b3859", // &^%te$t?Pw@_
|
||||||
|
"$SHA$0b503d90dd9949d4$ba70c330242e0daa9a154ec9f4cce7f01dd05aff489d37c653e36a507c74d84f" // âË_3(íù*
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user