#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:
ljacqu 2015-12-26 23:59:32 +01:00
parent 2bb386c488
commit 90a0325194
23 changed files with 387 additions and 206 deletions

View File

@ -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;
}

View 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() + "'");
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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);

View File

@ -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(íù*
}
}