mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2025-02-25 16:22:01 +01:00
#358 Add future interface methods, remove exception throwing
- Create Utils class for a common implementation of md5/sha1 - Create "foolproof" way of getting the MessageDigest for md5 etc. (MessageDigestAlgorithm enum) - Create description annotations to annotate algorithms with usage recommendation and salt type
This commit is contained in:
parent
2bb386c488
commit
90a0325194
@ -5,14 +5,10 @@ import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This event is called when we need to compare or get an hash password, for set
|
||||
* a custom EncryptionMethod
|
||||
* </p>
|
||||
*
|
||||
* @author Xephi59
|
||||
* @version $Revision: 1.0 $
|
||||
* @see fr.xephi.authme.security.crypts.EncryptionMethod
|
||||
*/
|
||||
public class PasswordEncryptionEvent extends Event {
|
||||
|
||||
@ -20,60 +16,29 @@ public class PasswordEncryptionEvent extends Event {
|
||||
private EncryptionMethod method = null;
|
||||
private String playerName = "";
|
||||
|
||||
/**
|
||||
* Constructor for PasswordEncryptionEvent.
|
||||
*
|
||||
* @param method EncryptionMethod
|
||||
* @param playerName String
|
||||
*/
|
||||
public PasswordEncryptionEvent(EncryptionMethod method, String playerName) {
|
||||
super(false);
|
||||
this.method = method;
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getHandlerList.
|
||||
*
|
||||
* @return HandlerList
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getHandlers.
|
||||
*
|
||||
* @return HandlerList
|
||||
*/
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getMethod.
|
||||
*
|
||||
* @return EncryptionMethod
|
||||
*/
|
||||
public EncryptionMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setMethod.
|
||||
*
|
||||
* @param method EncryptionMethod
|
||||
*/
|
||||
public void setMethod(EncryptionMethod method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getPlayerName.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
53
src/main/java/fr/xephi/authme/security/HashUtils.java
Normal file
53
src/main/java/fr/xephi/authme/security/HashUtils.java
Normal file
@ -0,0 +1,53 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
|
||||
public final class HashUtils {
|
||||
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
|
||||
private HashUtils() {
|
||||
}
|
||||
|
||||
public static String hash(String message, MessageDigestAlgorithm algorithm) {
|
||||
MessageDigest md = getDigest(algorithm);
|
||||
md.reset();
|
||||
md.update(message.getBytes());
|
||||
byte[] digest = md.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
}
|
||||
|
||||
public static String sha1(String message) {
|
||||
return hash(message, MessageDigestAlgorithm.SHA1);
|
||||
}
|
||||
|
||||
public static String md5(String message) {
|
||||
return hash(message, MessageDigestAlgorithm.MD5);
|
||||
}
|
||||
|
||||
// Only works for length up to 40!
|
||||
public static String generateSalt(int length) {
|
||||
byte[] msg = new byte[40];
|
||||
RANDOM.nextBytes(msg);
|
||||
MessageDigest sha1 = getDigest(MessageDigestAlgorithm.SHA1);
|
||||
sha1.reset();
|
||||
byte[] digest = sha1.digest(msg);
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest)).substring(0, length);
|
||||
}
|
||||
|
||||
public static MessageDigest getDigest(MessageDigestAlgorithm algorithm) {
|
||||
try {
|
||||
return MessageDigest.getInstance(algorithm.getKey());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new UnsupportedOperationException("Your system seems not to support the hash algorithm '"
|
||||
+ algorithm.getKey() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package fr.xephi.authme.security;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* The Java-supported names to get a {@link MessageDigest} instance with.
|
||||
*
|
||||
* @see <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/security/CryptoSpec.html#AppA">
|
||||
* Crypto Spec Appendix A: Standard Names</a>
|
||||
*/
|
||||
public enum MessageDigestAlgorithm {
|
||||
|
||||
MD5("MD5"),
|
||||
|
||||
SHA1("SHA-1"),
|
||||
|
||||
SHA256("SHA-256"),
|
||||
|
||||
SHA512("SHA-512");
|
||||
|
||||
private final String key;
|
||||
|
||||
MessageDigestAlgorithm(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
@ -13,8 +13,12 @@
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
@ -59,11 +63,13 @@ import java.security.SecureRandom;
|
||||
* @author Damien Miller
|
||||
* @version 0.2
|
||||
*/
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
@HasSalt(value = SaltType.TEXT, length = BCRYPT.BCRYPT_SALT_LEN)
|
||||
public class BCRYPT implements EncryptionMethod {
|
||||
|
||||
// BCrypt parameters
|
||||
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
|
||||
private static final int BCRYPT_SALT_LEN = 16;
|
||||
protected static final int BCRYPT_SALT_LEN = 16;
|
||||
|
||||
// Blowfish parameters
|
||||
private static final int BLOWFISH_NUM_ROUNDS = 16;
|
||||
@ -508,14 +514,20 @@ public class BCRYPT implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return hashpw(password, salt);
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return hashpw(password, generateSalt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
return checkpw(password, hash);
|
||||
}
|
||||
|
||||
public String generateSalt() {
|
||||
return BCRYPT.gensalt();
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,22 @@
|
||||
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 BCRYPT2Y implements EncryptionMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
if (salt.length() == 22)
|
||||
salt = "$2y$10$" + salt;
|
||||
return (BCRYPT.hashpw(password, salt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
String ok = hash.substring(0, 29);
|
||||
if (ok.length() != 29)
|
||||
return false;
|
||||
return hash.equals(computeHash(password, ok, playerName));
|
||||
return ok.length() == 29 && hash.equals(computeHash(password, ok, playerName));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,24 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.MessageDigestAlgorithm;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(SaltType.USERNAME)
|
||||
public class CRAZYCRYPT1 implements EncryptionMethod {
|
||||
|
||||
private static final char[] CRYPTCHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
protected final Charset charset = Charset.forName("UTF-8");
|
||||
private static final char[] CRYPTCHARS =
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
private final Charset charset = Charset.forName("UTF-8");
|
||||
|
||||
|
||||
public static String byteArrayToHexString(final byte... args) {
|
||||
private static String byteArrayToHexString(final byte... args) {
|
||||
final char[] chars = new char[args.length * 2];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
chars[i * 2] = CRYPTCHARS[(args[i] >> 4) & 0xF];
|
||||
@ -22,21 +28,23 @@ public class CRAZYCRYPT1 implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return computeHash(password, name);
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
final String text = "ÜÄaeut//&/=I " + password + "7421€547" + name + "__+IÄIH§%NK " + password;
|
||||
try {
|
||||
final MessageDigest md = MessageDigest.getInstance("SHA-512");
|
||||
md.update(text.getBytes(charset), 0, text.length());
|
||||
return byteArrayToHexString(md.digest());
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
final MessageDigest md = HashUtils.getDigest(MessageDigestAlgorithm.SHA512);
|
||||
md.update(text.getBytes(charset), 0, text.length());
|
||||
return byteArrayToHexString(md.digest());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, null, playerName));
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
return hash.equals(computeHash(password, playerName));
|
||||
}
|
||||
|
||||
public String generateSalt() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.DOES_NOT_WORK)
|
||||
public class CryptPBKDF2 implements EncryptionMethod {
|
||||
|
||||
@Override
|
||||
|
@ -1,18 +1,21 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Engine;
|
||||
import fr.xephi.authme.security.pbkdf2.PBKDF2Parameters;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.OK)
|
||||
@HasSalt(value = SaltType.TEXT, length = 12)
|
||||
public class CryptPBKDF2Django implements EncryptionMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String result = "pbkdf2_sha256$15000$" + salt + "$";
|
||||
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000);
|
||||
PBKDF2Engine engine = new PBKDF2Engine(params);
|
||||
@ -20,9 +23,12 @@ public class CryptPBKDF2Django implements EncryptionMethod {
|
||||
return result + String.valueOf(DatatypeConverter.printBase64Binary(engine.deriveKey(password, 32)));
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return computeHash(password, generateSalt(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
String[] line = hash.split("\\$");
|
||||
String salt = line[2];
|
||||
byte[] derivedKey = DatatypeConverter.parseBase64Binary(line[3]);
|
||||
@ -31,4 +37,8 @@ public class CryptPBKDF2Django implements EncryptionMethod {
|
||||
return engine.verifyKey(password);
|
||||
}
|
||||
|
||||
public String generateSalt() {
|
||||
return HashUtils.generateSalt(12);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,32 +1,31 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(SaltType.NONE)
|
||||
public class DOUBLEMD5 implements EncryptionMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return computeHash(password, null);
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return HashUtils.md5(HashUtils.md5(password));
|
||||
}
|
||||
|
||||
public String generateSalt() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(getMD5(password));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
return hash.equals(computeHash(password, null, null));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,4 +32,8 @@ public interface EncryptionMethod {
|
||||
boolean comparePassword(String hash, String password, String playerName)
|
||||
throws NoSuchAlgorithmException;
|
||||
|
||||
// String generateSalt();
|
||||
|
||||
// String computeHash(String password, String name);
|
||||
|
||||
}
|
||||
|
@ -1,32 +1,35 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.OK)
|
||||
@HasSalt(value = SaltType.TEXT, length = 32)
|
||||
public class JOOMLA implements EncryptionMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return HashUtils.md5(password + salt) + ":" + salt;
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return computeHash(password, generateSalt(), null);
|
||||
}
|
||||
|
||||
public String generateSalt() {
|
||||
return HashUtils.generateSalt(32);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(password + salt) + ":" + salt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
String salt = hash.split(":")[1];
|
||||
return hash.equals(getMD5(password + salt) + ":" + salt);
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
String[] hashParts = hash.split(":");
|
||||
if (hashParts.length != 2) {
|
||||
return false;
|
||||
}
|
||||
String salt = hashParts[1];
|
||||
return hash.equals(computeHash(password, salt, null));
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,26 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(SaltType.NONE)
|
||||
public class MD5 implements EncryptionMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return computeHash(password, null);
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return HashUtils.md5(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getMD5(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
return hash.equals(computeHash(password, null));
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,34 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
import static fr.xephi.authme.security.HashUtils.md5;
|
||||
|
||||
@Recommendation(Usage.OK)
|
||||
@HasSalt(value = SaltType.TEXT, length = 16)
|
||||
public class MD5VB implements EncryptionMethod {
|
||||
|
||||
private static String getMD5(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
md5.reset();
|
||||
md5.update(message.getBytes());
|
||||
byte[] digest = md5.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return "$MD5vb$" + salt + "$" + md5(md5(password) + salt);
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return computeHash(password, generateSalt(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return "$MD5vb$" + salt + "$" + getMD5(getMD5(password) + salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
String[] line = hash.split("\\$");
|
||||
return hash.equals(computeHash(password, line[2], ""));
|
||||
return line.length == 4 && hash.equals(computeHash(password, line[2], ""));
|
||||
}
|
||||
|
||||
public String generateSalt() {
|
||||
return HashUtils.generateSalt(16);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,32 +1,31 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(SaltType.NONE)
|
||||
public class SHA1 implements EncryptionMethod {
|
||||
|
||||
private static String getSHA1(String message)
|
||||
throws NoSuchAlgorithmException {
|
||||
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
|
||||
sha1.reset();
|
||||
sha1.update(message.getBytes());
|
||||
byte[] digest = sha1.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return computeHash(password, null);
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return HashUtils.sha1(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
return getSHA1(password);
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
return hash.equals(computeHash(password, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
public String generateSalt() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -59,11 +59,15 @@ package fr.xephi.authme.security.crypts;
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.DO_NOT_USE)
|
||||
@HasSalt(SaltType.NONE)
|
||||
public class WHIRLPOOL implements EncryptionMethod {
|
||||
|
||||
/**
|
||||
@ -383,8 +387,11 @@ public class WHIRLPOOL implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
return computeHash(password, null);
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
byte[] digest = new byte[DIGESTBYTES];
|
||||
NESSIEinit();
|
||||
NESSIEadd(password);
|
||||
@ -393,8 +400,8 @@ public class WHIRLPOOL implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
return hash.equals(computeHash(password, "", ""));
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
return hash.equals(computeHash(password, null, null));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,18 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.OK)
|
||||
@HasSalt(value = SaltType.TEXT, length = 9)
|
||||
public class WORDPRESS implements EncryptionMethod {
|
||||
|
||||
private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
@ -102,18 +107,25 @@ public class WORDPRESS implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
byte random[] = new byte[6];
|
||||
this.randomGen.nextBytes(random);
|
||||
randomGen.nextBytes(random);
|
||||
return crypt(password, gensaltPrivate(stringToUtf8(new String(random))));
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return computeHash(password, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
String comparedHash = crypt(password, hash);
|
||||
return comparedHash.equals(hash);
|
||||
}
|
||||
|
||||
public String generateSalt() {
|
||||
// This hash uses a salt, but it is not exposed to the outside
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.crypts.description.HasSalt;
|
||||
import fr.xephi.authme.security.crypts.description.Recommendation;
|
||||
import fr.xephi.authme.security.crypts.description.SaltType;
|
||||
import fr.xephi.authme.security.crypts.description.Usage;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Recommendation(Usage.RECOMMENDED)
|
||||
@HasSalt(value = SaltType.TEXT, length = 12)
|
||||
public class XAUTH implements EncryptionMethod {
|
||||
|
||||
public static String getWhirlpool(String message) {
|
||||
@ -16,19 +20,25 @@ public class XAUTH implements EncryptionMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeHash(String password, String salt, String name)
|
||||
throws NoSuchAlgorithmException {
|
||||
public String computeHash(String password, String salt, String name) {
|
||||
String hash = getWhirlpool(salt + password).toLowerCase();
|
||||
int saltPos = (password.length() >= hash.length() ? hash.length() - 1 : password.length());
|
||||
return hash.substring(0, saltPos) + salt + hash.substring(saltPos);
|
||||
}
|
||||
|
||||
public String computeHash(String password, String name) {
|
||||
return computeHash(password, generateSalt(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean comparePassword(String hash, String password,
|
||||
String playerName) throws NoSuchAlgorithmException {
|
||||
public boolean comparePassword(String hash, String password, String playerName) {
|
||||
int saltPos = (password.length() >= hash.length() ? hash.length() - 1 : password.length());
|
||||
String salt = hash.substring(saltPos, saltPos + 12);
|
||||
return hash.equals(computeHash(password, salt, ""));
|
||||
}
|
||||
|
||||
public String generateSalt() {
|
||||
return HashUtils.generateSalt(12);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
/**
|
||||
* Describes the type of salt the encryption algorithm uses. This is purely for documentation
|
||||
* purposes and is ignored by the code.
|
||||
*/
|
||||
public @interface HasSalt {
|
||||
|
||||
SaltType value();
|
||||
|
||||
int length() default 0;
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
/**
|
||||
* Annotation to mark a hash algorithm with the usage recommendation, see {@link Usage}.
|
||||
*/
|
||||
public @interface Recommendation {
|
||||
|
||||
Usage value();
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
/**
|
||||
* The type of salt used by an encryption algorithms.
|
||||
*/
|
||||
public enum SaltType {
|
||||
|
||||
/** Random, newly generated text. */
|
||||
TEXT,
|
||||
|
||||
/** The username, including variations or repetitions. */
|
||||
USERNAME,
|
||||
|
||||
/** No salt. */
|
||||
NONE
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package fr.xephi.authme.security.crypts.description;
|
||||
|
||||
/**
|
||||
* Usage recommendation that can be provided for a hash algorithm.
|
||||
*/
|
||||
public enum Usage {
|
||||
|
||||
/** The hash algorithm appears to be cryptographically secure and is one of the algorithms recommended by AuthMe. */
|
||||
RECOMMENDED,
|
||||
|
||||
/** There are safer algorithms that can be chosen but using the algorithm is generally OK. */
|
||||
OK,
|
||||
|
||||
/** Hash algorithm is not recommended to be used. Use only if required by another system. */
|
||||
DO_NOT_USE,
|
||||
|
||||
/** The algorithm does not work properly; do not use. */
|
||||
DOES_NOT_WORK
|
||||
|
||||
}
|
@ -134,7 +134,7 @@ public abstract class AbstractEncryptionMethodTest {
|
||||
return BCRYPT.gensalt();
|
||||
} else if (method instanceof MD5 || method instanceof WORDPRESS || method instanceof SMF
|
||||
|| method instanceof SHA512 || method instanceof SHA1 || method instanceof ROYALAUTH
|
||||
|| method instanceof DOUBLEMD5) {
|
||||
|| method instanceof DOUBLEMD5 || method instanceof CRAZYCRYPT1) {
|
||||
return "";
|
||||
} else if (method instanceof JOOMLA || method instanceof SALTEDSHA512) {
|
||||
return PasswordSecurity.createSalt(32);
|
||||
|
@ -0,0 +1,16 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
/**
|
||||
* Test for {@link CRAZYCRYPT1}.
|
||||
*/
|
||||
public class CRAZYCRYPT1Test extends AbstractEncryptionMethodTest {
|
||||
|
||||
public CRAZYCRYPT1Test() {
|
||||
super(new CRAZYCRYPT1(),
|
||||
"d5c76eb36417d4e97ec62609619e40a9e549a2598d0dab5a7194fd997a9305af78de2b93f958e150d19dd1e7f821043379ddf5f9c7f352bf27df91ae4913f3e8", // password
|
||||
"49c63f827c88196871e344e589bd46cc4fa6db3c27801bbad5374c0d216381977627c1d76f2114667d5dd117e046f7493eb06e4f461f4f848aa08f6f40a3e934", // PassWord1
|
||||
"6fefb0233bab6e6efb9c16f82cb0d8f569488905e2dae0e7c9dde700e7363da67213d37c44bc15f4a05854c9c21e5688389d416413c7309398aa96cb1f341d08", // &^%te$t?Pw@_
|
||||
"46f51cde7657fdec9848bad0fd8e7fb97783cf5335f94dbb5260899ab0b04022a52d651b1c45345328850178e7165308c8c213040b0864de66018a0b769d37cb"); // âË_3(íù*
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user