#358 Update EncryptionMethod to new interface
- Add new methods to the EncryptionMethod interface - Delete temporary interface (NewEncrMethod) - Remove temporary checks and casts to NewEncrMethod
This commit is contained in:
parent
9b73475b9a
commit
47f4275225
@ -7,7 +7,6 @@ import fr.xephi.authme.events.PasswordEncryptionEvent;
|
|||||||
import fr.xephi.authme.security.crypts.BCRYPT;
|
import fr.xephi.authme.security.crypts.BCRYPT;
|
||||||
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||||
import fr.xephi.authme.security.crypts.HashResult;
|
import fr.xephi.authme.security.crypts.HashResult;
|
||||||
import fr.xephi.authme.security.crypts.NewEncrMethod;
|
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
@ -145,7 +144,18 @@ public class PasswordSecurity {
|
|||||||
if (method == null)
|
if (method == null)
|
||||||
throw new NoSuchAlgorithmException("Unknown hash algorithm");
|
throw new NoSuchAlgorithmException("Unknown hash algorithm");
|
||||||
|
|
||||||
if (method.comparePassword(hash, password, playerName))
|
String salt = null;
|
||||||
|
if (method.hasSeparateSalt()) {
|
||||||
|
PlayerAuth auth = AuthMe.getInstance().getDataSource().getAuth(playerName);
|
||||||
|
if (auth == null) {
|
||||||
|
// User is not in data source, so the result will invariably be wrong because an encryption
|
||||||
|
// method with hasSeparateSalt() == true NEEDS the salt to evaluate the password
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
salt = auth.getSalt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.comparePassword(hash, password, salt, playerName))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Settings.supportOldPassword) {
|
if (Settings.supportOldPassword) {
|
||||||
@ -159,32 +169,21 @@ public class PasswordSecurity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public HashResult computeHash(HashAlgorithm algorithm, String password, String playerName) {
|
public HashResult computeHash(HashAlgorithm algorithm, String password, String playerName) {
|
||||||
EncryptionMethod method1 = initializeEncryptionMethod(algorithm, playerName);
|
EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName);
|
||||||
// TODO #358: Remove this check:
|
|
||||||
NewEncrMethod method;
|
|
||||||
if (method1 instanceof NewEncrMethod) {
|
|
||||||
method = (NewEncrMethod) method1;
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("TODO #358: Class not yet extended with NewEncrMethod methods");
|
|
||||||
}
|
|
||||||
|
|
||||||
return method.computeHash(password, playerName);
|
return method.computeHash(password, playerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean comparePassword(HashAlgorithm algorithm, String hash, String password, String playerName) {
|
public boolean comparePassword(HashAlgorithm algorithm, String hash, String password, String playerName) {
|
||||||
EncryptionMethod method1 = initializeEncryptionMethod(algorithm, playerName);
|
EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName);
|
||||||
// TODO #358: Remove this check:
|
|
||||||
NewEncrMethod method;
|
|
||||||
if (method1 instanceof NewEncrMethod) {
|
|
||||||
method = (NewEncrMethod) method1;
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("TODO #358: Class not yet extended with NewEncrMethod methods");
|
|
||||||
}
|
|
||||||
|
|
||||||
String salt = null;
|
String salt = null;
|
||||||
if (method.hasSeparateSalt()) {
|
if (method.hasSeparateSalt()) {
|
||||||
PlayerAuth auth = dataSource.getAuth(playerName);
|
PlayerAuth auth = dataSource.getAuth(playerName);
|
||||||
salt = (auth != null) ? auth.getSalt() : null;
|
if (auth == null) {
|
||||||
|
// User is not in data source, so the result will invariably be wrong because an encryption
|
||||||
|
// method with hasSeparateSalt() == true NEEDS the salt to evaluate the password
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
salt = auth.getSalt();
|
||||||
}
|
}
|
||||||
return method.comparePassword(hash, password, salt, playerName);
|
return method.comparePassword(hash, password, salt, playerName);
|
||||||
// TODO #358: Add logic for Settings.supportOldPassword
|
// TODO #358: Add logic for Settings.supportOldPassword
|
||||||
@ -209,11 +208,19 @@ public class PasswordSecurity {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
private static boolean compareWithAllEncryptionMethod(String password,
|
private static boolean compareWithAllEncryptionMethod(String password,
|
||||||
String hash, String playerName) {
|
String hash, String playerName) {
|
||||||
|
String salt;
|
||||||
|
PlayerAuth auth = AuthMe.getInstance().getDataSource().getAuth(playerName);
|
||||||
|
if (auth == null) {
|
||||||
|
salt = null;
|
||||||
|
} else {
|
||||||
|
salt = auth.getSalt();
|
||||||
|
}
|
||||||
|
|
||||||
for (HashAlgorithm algo : HashAlgorithm.values()) {
|
for (HashAlgorithm algo : HashAlgorithm.values()) {
|
||||||
if (algo != HashAlgorithm.CUSTOM) {
|
if (algo != HashAlgorithm.CUSTOM) {
|
||||||
try {
|
try {
|
||||||
EncryptionMethod method = algo.getClazz().newInstance();
|
EncryptionMethod method = algo.getClazz().newInstance();
|
||||||
if (method.comparePassword(hash, password, playerName)) {
|
if (method.comparePassword(hash, password, salt, playerName)) {
|
||||||
PlayerAuth nAuth = AuthMe.getInstance().database.getAuth(playerName);
|
PlayerAuth nAuth = AuthMe.getInstance().database.getAuth(playerName);
|
||||||
if (nAuth != null) {
|
if (nAuth != null) {
|
||||||
nAuth.setHash(getHash(Settings.getPasswordHash, password, playerName));
|
nAuth.setHash(getHash(Settings.getPasswordHash, password, playerName));
|
||||||
|
|||||||
@ -66,7 +66,7 @@ import java.security.SecureRandom;
|
|||||||
*/
|
*/
|
||||||
@Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8
|
@Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8
|
||||||
@HasSalt(value = SaltType.TEXT) // length depends on Settings.bCryptLog2Rounds
|
@HasSalt(value = SaltType.TEXT) // length depends on Settings.bCryptLog2Rounds
|
||||||
public class BCRYPT implements NewEncrMethod {
|
public class BCRYPT implements EncryptionMethod {
|
||||||
|
|
||||||
// BCrypt parameters
|
// BCrypt parameters
|
||||||
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
|
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
|
||||||
@ -525,14 +525,9 @@ public class BCRYPT implements NewEncrMethod {
|
|||||||
return new HashResult(hashpw(password, salt), salt);
|
return new HashResult(hashpw(password, salt), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
|
||||||
return checkpw(password, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String hash, String password, String salt, String name) {
|
public boolean comparePassword(String hash, String password, String salt, String name) {
|
||||||
return comparePassword(hash, password, name);
|
return checkpw(password, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -5,11 +5,10 @@ import fr.xephi.authme.security.crypts.description.Usage;
|
|||||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
|
import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
|
||||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
|
import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@Recommendation(Usage.DOES_NOT_WORK)
|
@Recommendation(Usage.DOES_NOT_WORK)
|
||||||
public class CryptPBKDF2 implements EncryptionMethod {
|
public class CryptPBKDF2 extends HexSaltedMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -21,7 +20,7 @@ public class CryptPBKDF2 implements EncryptionMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) {
|
||||||
String[] line = hash.split("\\$");
|
String[] line = hash.split("\\$");
|
||||||
String salt = line[2];
|
String salt = line[2];
|
||||||
String derivedKey = line[3];
|
String derivedKey = line[3];
|
||||||
@ -30,4 +29,9 @@ public class CryptPBKDF2 implements EncryptionMethod {
|
|||||||
return engine.verifyKey(password);
|
return engine.verifyKey(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSaltLength() {
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,28 +5,56 @@ package fr.xephi.authme.security.crypts;
|
|||||||
*/
|
*/
|
||||||
public interface EncryptionMethod {
|
public interface EncryptionMethod {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash the given password for the given player name.
|
||||||
|
*
|
||||||
|
* @param password The password to hash
|
||||||
|
* @param name The name of the player (sometimes required to generate a salt with)
|
||||||
|
*
|
||||||
|
* @return The hash result for the password.
|
||||||
|
* @see HashResult
|
||||||
|
*/
|
||||||
|
HashResult computeHash(String password, String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash the given password with the given salt for the given player.
|
* Hash the given password with the given salt for the given player.
|
||||||
*
|
*
|
||||||
* @param password The clear-text password to hash
|
* @param password The password to hash
|
||||||
* @param salt The salt to add to the hash
|
* @param salt The salt to add to the hash
|
||||||
* @param name The player's name (sometimes required for storing the salt separately in the database)
|
* @param name The player's name (sometimes required to generate a salt with)
|
||||||
*
|
*
|
||||||
* @return The hashed password
|
* @return The hashed password
|
||||||
|
* @see #hasSeparateSalt()
|
||||||
*/
|
*/
|
||||||
String computeHash(String password, String salt, String name);
|
String computeHash(String password, String salt, String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether a given hash matches the clear-text password.
|
* Check whether the given hash matches the clear-text password.
|
||||||
*
|
*
|
||||||
* @param hash The hash to verify
|
* @param hash The hash to verify
|
||||||
* @param password The clear-text password to verify the hash against
|
* @param password The clear-text password to verify the hash against
|
||||||
* @param playerName The player name to do the check for (sometimes required for retrieving
|
* @param salt The salt if it is stored separately (null otherwise)
|
||||||
* the salt from the database)
|
* @param name The player name to do the check for (sometimes required for generating the salt)
|
||||||
*
|
*
|
||||||
* @return True if the password matches, false otherwise
|
* @return True if the password matches, false otherwise
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
boolean comparePassword(String hash, String password, String salt, String name);
|
||||||
boolean comparePassword(String hash, String password, String playerName);
|
|
||||||
|
/**
|
||||||
|
* Generate a new salt to hash a password with.
|
||||||
|
*
|
||||||
|
* @return The generated salt, null if the method does not use a random text-based salt
|
||||||
|
*/
|
||||||
|
String generateSalt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the encryption method requires the salt to be stored separately and
|
||||||
|
* passed again to {@link #comparePassword(String, String, String, String)}. Note that
|
||||||
|
* an encryption method returning {@code false} does not imply that it uses no salt; it
|
||||||
|
* may be embedded into the hash or it may use the username as salt.
|
||||||
|
*
|
||||||
|
* @return True if the salt has to be stored and retrieved separately, false otherwise
|
||||||
|
*/
|
||||||
|
boolean hasSeparateSalt();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,38 @@
|
|||||||
package fr.xephi.authme.security.crypts;
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The result of a hash computation.
|
* The result of a hash computation. See {@link #salt} for details.
|
||||||
*/
|
*/
|
||||||
public class HashResult {
|
public class HashResult {
|
||||||
|
|
||||||
/** The generated hash. */
|
/** The generated hash. */
|
||||||
private final String hash;
|
private final String hash;
|
||||||
/** The generated salt; may be null if no salt is used or if the salt is included in the hash output. */
|
/**
|
||||||
|
* The generated salt; may be null if no salt is used or if the salt is included
|
||||||
|
* in the hash output. The salt is only not null if {@link EncryptionMethod#hasSeparateSalt()}
|
||||||
|
* returns true for the associated encryption method.
|
||||||
|
* <p>
|
||||||
|
* When the field is not null, it must be stored into the salt column of the data source
|
||||||
|
* and retrieved again to compare a password with the hash.
|
||||||
|
*/
|
||||||
private final String salt;
|
private final String salt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param hash The computed hash
|
||||||
|
* @param salt The generated salt
|
||||||
|
*/
|
||||||
public HashResult(String hash, String salt) {
|
public HashResult(String hash, String salt) {
|
||||||
this.hash = hash;
|
this.hash = hash;
|
||||||
this.salt = salt;
|
this.salt = salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a hash with no separate salt.
|
||||||
|
*
|
||||||
|
* @param hash The computed hash
|
||||||
|
*/
|
||||||
public HashResult(String hash) {
|
public HashResult(String hash) {
|
||||||
this(hash, null);
|
this(hash, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import fr.xephi.authme.security.crypts.description.Usage;
|
|||||||
*/
|
*/
|
||||||
@Recommendation(Usage.ACCEPTABLE)
|
@Recommendation(Usage.ACCEPTABLE)
|
||||||
@HasSalt(SaltType.TEXT) // See saltLength() for length
|
@HasSalt(SaltType.TEXT) // See saltLength() for length
|
||||||
public abstract class HexSaltedMethod implements NewEncrMethod {
|
public abstract class HexSaltedMethod implements EncryptionMethod {
|
||||||
|
|
||||||
public abstract int getSaltLength();
|
public abstract int getSaltLength();
|
||||||
|
|
||||||
@ -28,12 +28,6 @@ public abstract class HexSaltedMethod implements NewEncrMethod {
|
|||||||
@Override
|
@Override
|
||||||
public abstract boolean comparePassword(String hash, String password, String salt, String name);
|
public abstract boolean comparePassword(String hash, String password, String salt, String name);
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String generateSalt() {
|
public String generateSalt() {
|
||||||
return RandomString.generateHex(getSaltLength());
|
return RandomString.generateHex(getSaltLength());
|
||||||
|
|||||||
@ -1,22 +1,16 @@
|
|||||||
package fr.xephi.authme.security.crypts;
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.security.HashUtils;
|
|
||||||
import fr.xephi.authme.security.RandomString;
|
import fr.xephi.authme.security.RandomString;
|
||||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||||
import fr.xephi.authme.security.crypts.description.Usage;
|
import fr.xephi.authme.security.crypts.description.Usage;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.security.HashUtils.md5;
|
import static fr.xephi.authme.security.HashUtils.md5;
|
||||||
|
|
||||||
@Recommendation(Usage.DO_NOT_USE)
|
@Recommendation(Usage.DO_NOT_USE)
|
||||||
@HasSalt(value = SaltType.TEXT, length = 5)
|
@HasSalt(value = SaltType.TEXT, length = 5)
|
||||||
public class IPB3 implements NewEncrMethod {
|
public class IPB3 implements EncryptionMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -29,12 +23,6 @@ public class IPB3 implements NewEncrMethod {
|
|||||||
return new HashResult(computeHash(password, salt, name), salt);
|
return new HashResult(computeHash(password, salt, name), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
|
||||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
|
||||||
return hash.equals(computeHash(password, salt, playerName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String hash, String password, String salt, String name) {
|
public boolean comparePassword(String hash, String password, String salt, String name) {
|
||||||
return hash.equals(computeHash(password, salt, name));
|
return hash.equals(computeHash(password, salt, name));
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
package fr.xephi.authme.security.crypts;
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.security.HashUtils;
|
|
||||||
import fr.xephi.authme.security.RandomString;
|
import fr.xephi.authme.security.RandomString;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
import static fr.xephi.authme.security.HashUtils.md5;
|
import static fr.xephi.authme.security.HashUtils.md5;
|
||||||
|
|
||||||
public class MYBB implements NewEncrMethod {
|
public class MYBB implements EncryptionMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -23,12 +17,6 @@ public class MYBB implements NewEncrMethod {
|
|||||||
return new HashResult(computeHash(password, salt, name), salt);
|
return new HashResult(computeHash(password, salt, name), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
|
||||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
|
||||||
return hash.equals(computeHash(password, salt, playerName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String hash, String password, String salt, String name) {
|
public boolean comparePassword(String hash, String password, String salt, String name) {
|
||||||
return hash.equals(computeHash(password, salt, name));
|
return hash.equals(computeHash(password, salt, name));
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
package fr.xephi.authme.security.crypts;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Temporary interface for additional methods that will be added to {@link EncryptionMethod}.
|
|
||||||
* TODO #358: Move methods to EncryptionMethod interface and delete this.
|
|
||||||
*/
|
|
||||||
public interface NewEncrMethod extends EncryptionMethod {
|
|
||||||
|
|
||||||
HashResult computeHash(String password, String name);
|
|
||||||
|
|
||||||
String generateSalt();
|
|
||||||
|
|
||||||
boolean hasSeparateSalt();
|
|
||||||
|
|
||||||
boolean comparePassword(String hash, String password, String salt, String name);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package fr.xephi.authme.security.crypts;
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
import fr.xephi.authme.security.HashUtils;
|
import fr.xephi.authme.security.HashUtils;
|
||||||
import fr.xephi.authme.security.RandomString;
|
import fr.xephi.authme.security.RandomString;
|
||||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||||
@ -9,13 +8,11 @@ import fr.xephi.authme.security.crypts.description.Usage;
|
|||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
@Recommendation(Usage.DO_NOT_USE)
|
@Recommendation(Usage.DO_NOT_USE)
|
||||||
public class PHPFUSION implements NewEncrMethod {
|
public class PHPFUSION implements EncryptionMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -46,13 +43,6 @@ public class PHPFUSION implements NewEncrMethod {
|
|||||||
return new HashResult(computeHash(password, salt, name), salt);
|
return new HashResult(computeHash(password, salt, name), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean comparePassword(String hash, String password,
|
|
||||||
String playerName) {
|
|
||||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
|
||||||
return hash.equals(computeHash(password, salt, ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String hash, String password, String salt, String name) {
|
public boolean comparePassword(String hash, String password, String salt, String name) {
|
||||||
return hash.equals(computeHash(password, salt, name));
|
return hash.equals(computeHash(password, salt, name));
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package fr.xephi.authme.security.crypts;
|
|||||||
/**
|
/**
|
||||||
* Common supertype for encryption methods which store their salt separately from the hash.
|
* Common supertype for encryption methods which store their salt separately from the hash.
|
||||||
*/
|
*/
|
||||||
public abstract class SeparateSaltMethod implements NewEncrMethod {
|
public abstract class SeparateSaltMethod implements EncryptionMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract String computeHash(String password, String salt, String name);
|
public abstract String computeHash(String password, String salt, String name);
|
||||||
@ -27,9 +27,4 @@ public abstract class SeparateSaltMethod implements NewEncrMethod {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import fr.xephi.authme.security.crypts.description.Usage;
|
|||||||
*/
|
*/
|
||||||
@Recommendation(Usage.DO_NOT_USE)
|
@Recommendation(Usage.DO_NOT_USE)
|
||||||
@HasSalt(SaltType.NONE)
|
@HasSalt(SaltType.NONE)
|
||||||
public abstract class UnsaltedMethod implements NewEncrMethod {
|
public abstract class UnsaltedMethod implements EncryptionMethod {
|
||||||
|
|
||||||
public abstract String computeHash(String password);
|
public abstract String computeHash(String password);
|
||||||
|
|
||||||
@ -24,12 +24,6 @@ public abstract class UnsaltedMethod implements NewEncrMethod {
|
|||||||
return computeHash(password);
|
return computeHash(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String hash, String password, String salt, String name) {
|
public boolean comparePassword(String hash, String password, String salt, String name) {
|
||||||
return hash.equals(computeHash(password));
|
return hash.equals(computeHash(password));
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import fr.xephi.authme.security.crypts.description.Usage;
|
|||||||
*/
|
*/
|
||||||
@Recommendation(Usage.DO_NOT_USE)
|
@Recommendation(Usage.DO_NOT_USE)
|
||||||
@HasSalt(SaltType.USERNAME)
|
@HasSalt(SaltType.USERNAME)
|
||||||
public abstract class UsernameSaltMethod implements NewEncrMethod {
|
public abstract class UsernameSaltMethod implements EncryptionMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract HashResult computeHash(String password, String name);
|
public abstract HashResult computeHash(String password, String name);
|
||||||
@ -21,12 +21,6 @@ public abstract class UsernameSaltMethod implements NewEncrMethod {
|
|||||||
return hash.equals(computeHash(password, name).getHash());
|
return hash.equals(computeHash(password, name).getHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
return computeHash(password, name).getHash();
|
return computeHash(password, name).getHash();
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
package fr.xephi.authme.security.crypts;
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||||
|
import fr.xephi.authme.security.crypts.description.Usage;
|
||||||
|
|
||||||
/**
|
@Recommendation(Usage.DOES_NOT_WORK)
|
||||||
*/
|
public class WBB4 extends HexSaltedMethod {
|
||||||
public class WBB4 implements EncryptionMethod {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -12,8 +12,23 @@ public class WBB4 implements EncryptionMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
public boolean comparePassword(String hash, String password, String salt, String playerName) {
|
||||||
return BCRYPT.checkpw(password, hash, 2);
|
return BCRYPT.checkpw(password, hash, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateSalt() {
|
||||||
|
return BCRYPT.gensalt(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that {@link #generateSalt()} is overridden for this class.
|
||||||
|
*
|
||||||
|
* @return The salt length
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getSaltLength() {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
package fr.xephi.authme.security.crypts;
|
package fr.xephi.authme.security.crypts;
|
||||||
|
|
||||||
import fr.xephi.authme.AuthMe;
|
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -11,7 +9,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public class XF implements NewEncrMethod {
|
public class XF implements EncryptionMethod {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String computeHash(String password, String salt, String name) {
|
public String computeHash(String password, String salt, String name) {
|
||||||
@ -24,12 +22,6 @@ public class XF implements NewEncrMethod {
|
|||||||
return new HashResult(computeHash(password, salt, null), salt);
|
return new HashResult(computeHash(password, salt, null), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean comparePassword(String hash, String password, String playerName) {
|
|
||||||
String salt = AuthMe.getInstance().database.getAuth(playerName).getSalt();
|
|
||||||
return hash.equals(regmatch("\"hash\";.:..:\"(.*)\";.:.:\"salt\"", salt));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean comparePassword(String hash, String password, String salt, String name) {
|
public boolean comparePassword(String hash, String password, String salt, String name) {
|
||||||
return hash.equals(regmatch("\"hash\";.:..:\"(.*)\";.:.:\"salt\"", salt));
|
return hash.equals(regmatch("\"hash\";.:..:\"(.*)\";.:.:\"salt\"", salt));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import static org.hamcrest.Matchers.equalTo;
|
|||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for implementations of {@link EncryptionMethod}.
|
* Test for implementations of {@link EncryptionMethod}.
|
||||||
@ -98,45 +97,30 @@ public abstract class AbstractEncryptionMethodTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPasswordEquality() {
|
public void testPasswordEquality() {
|
||||||
// TODO #358: Remove instanceof and use this code always
|
for (String password : INTERNAL_PASSWORDS) {
|
||||||
if (method instanceof NewEncrMethod) {
|
final String salt = method.generateSalt();
|
||||||
NewEncrMethod method1 = (NewEncrMethod) method;
|
final String hash = method.computeHash(password, salt, USERNAME);
|
||||||
for (String password : INTERNAL_PASSWORDS) {
|
|
||||||
final String salt = method1.generateSalt();
|
|
||||||
final String hash = method1.computeHash(password, salt, USERNAME);
|
|
||||||
|
|
||||||
// Check that the computeHash(password, salt, name) method has the same output for the returned salt
|
// Check that the computeHash(password, salt, name) method has the same output for the returned salt
|
||||||
assertThat(hash, equalTo(method1.computeHash(password, salt, USERNAME)));
|
assertThat(hash, equalTo(method.computeHash(password, salt, USERNAME)));
|
||||||
|
|
||||||
assertTrue("Generated hash for '" + password + "' should match password (hash = '" + hash + "')",
|
assertTrue("Generated hash for '" + password + "' should match password (hash = '" + hash + "')",
|
||||||
method1.comparePassword(hash, password, salt, USERNAME));
|
method.comparePassword(hash, password, salt, USERNAME));
|
||||||
if (!password.equals(password.toLowerCase())) {
|
if (!password.equals(password.toLowerCase())) {
|
||||||
assertFalse("Lower-case of '" + password + "' should not match generated hash '" + hash + "'",
|
assertFalse("Lower-case of '" + password + "' should not match generated hash '" + hash + "'",
|
||||||
method1.comparePassword(hash, password.toLowerCase(), salt, USERNAME));
|
method.comparePassword(hash, password.toLowerCase(), salt, USERNAME));
|
||||||
}
|
}
|
||||||
if (!password.equals(password.toUpperCase())) {
|
if (!password.equals(password.toUpperCase())) {
|
||||||
assertFalse("Upper-case of '" + password + "' should not match generated hash '" + hash + "'",
|
assertFalse("Upper-case of '" + password + "' should not match generated hash '" + hash + "'",
|
||||||
method1.comparePassword(hash, password.toUpperCase(), salt, USERNAME));
|
method.comparePassword(hash, password.toUpperCase(), salt, USERNAME));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fail("No longer supporting old EncryptionMethod implementations");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doesGivenHashMatch(String password, EncryptionMethod method) {
|
private boolean doesGivenHashMatch(String password, EncryptionMethod method) {
|
||||||
// TODO #358: Remove casting checks and remove old code below
|
String hash = hashes.get(password);
|
||||||
if (method instanceof NewEncrMethod) {
|
String salt = salts.get(password);
|
||||||
NewEncrMethod method1 = (NewEncrMethod) method;
|
return method.comparePassword(hash, password, salt, USERNAME);
|
||||||
String hash = hashes.get(password);
|
|
||||||
String salt = salts.get(password);
|
|
||||||
return method1.comparePassword(hash, password, salt, USERNAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO #358: Remove line below
|
|
||||||
return method.comparePassword(hashes.get(password), password, USERNAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @org.junit.Test public void a() { AbstractEncryptionMethodTest.generateTest(); }
|
// @org.junit.Test public void a() { AbstractEncryptionMethodTest.generateTest(); }
|
||||||
@ -148,28 +132,18 @@ public abstract class AbstractEncryptionMethodTest {
|
|||||||
System.out.println("\n\tpublic " + className + "Test() {");
|
System.out.println("\n\tpublic " + className + "Test() {");
|
||||||
System.out.println("\t\tsuper(new " + className + "(),");
|
System.out.println("\t\tsuper(new " + className + "(),");
|
||||||
|
|
||||||
NewEncrMethod method1 = null;
|
|
||||||
if (method instanceof NewEncrMethod) {
|
|
||||||
method1 = (NewEncrMethod) method;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
String delim = ", ";
|
String delim = ", ";
|
||||||
for (String password : GIVEN_PASSWORDS) {
|
for (String password : GIVEN_PASSWORDS) {
|
||||||
if (password.equals(GIVEN_PASSWORDS[GIVEN_PASSWORDS.length - 1])) {
|
if (password.equals(GIVEN_PASSWORDS[GIVEN_PASSWORDS.length - 1])) {
|
||||||
delim = "); ";
|
delim = "); ";
|
||||||
}
|
}
|
||||||
if (method1 != null) {
|
|
||||||
if (method1.hasSeparateSalt()) {
|
if (method.hasSeparateSalt()) {
|
||||||
HashResult hashResult = method1.computeHash(password, USERNAME);
|
HashResult hashResult = method.computeHash(password, USERNAME);
|
||||||
System.out.println(String.format("\t\tnew HashResult(\"%s\", \"%s\")%s// %s",
|
System.out.println(String.format("\t\tnew HashResult(\"%s\", \"%s\")%s// %s",
|
||||||
hashResult.getHash(), hashResult.getSalt(), delim, password));
|
hashResult.getHash(), hashResult.getSalt(), delim, password));
|
||||||
} else {
|
|
||||||
System.out.println("\t\t\"" + method1.computeHash(password, USERNAME).getHash()
|
|
||||||
+ "\"" + delim + "// " + password);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
System.out.println("\t\t\"" + method.computeHash(password, null, USERNAME)
|
System.out.println("\t\t\"" + method.computeHash(password, USERNAME).getHash()
|
||||||
+ "\"" + delim + "// " + password);
|
+ "\"" + delim + "// " + password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user