#358 Handle hash + salt as one "unit"

- Rename HashResult to EncryptedPassword to reflect its broader use
- Use EncryptedPassword in methods that require the hash and the salt, instead of passing them as strings separately
- Store EncryptedPassword as field in PlayerAuth; updatePassword() thus processes the entire data in the EncryptedPassword object
This commit is contained in:
ljacqu 2015-12-30 17:56:22 +01:00
parent 9c4a578bec
commit a3402d573f
46 changed files with 328 additions and 564 deletions

View File

@ -43,7 +43,7 @@ import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.process.Management; import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.OtherAccounts;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.Spawn; import fr.xephi.authme.settings.Spawn;
@ -592,8 +592,9 @@ public class AuthMe extends JavaPlugin {
ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated; " + ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated; " +
"it will be changed and hashed now to the AuthMe default hashing method"); "it will be changed and hashed now to the AuthMe default hashing method");
for (PlayerAuth auth : database.getAllAuths()) { for (PlayerAuth auth : database.getAllAuths()) {
HashResult hashResult = passwordSecurity.computeHash(HashAlgorithm.SHA256, auth.getHash(), auth.getNickname()); EncryptedPassword encryptedPassword = passwordSecurity.computeHash(
auth.setHash(hashResult.getHash()); HashAlgorithm.SHA256, auth.getPassword().getHash(), auth.getNickname());
auth.setPassword(encryptedPassword);
database.updatePassword(auth); database.updatePassword(auth);
} }
Settings.setValue("settings.security.passwordHash", "SHA256"); Settings.setValue("settings.security.passwordHash", "SHA256");

View File

@ -4,8 +4,7 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -135,13 +134,13 @@ public class API {
@Deprecated @Deprecated
public static boolean registerPlayer(String playerName, String password) { public static boolean registerPlayer(String playerName, String password) {
String name = playerName.toLowerCase(); String name = playerName.toLowerCase();
HashResult hashResult = passwordSecurity.computeHash(Settings.getPasswordHash, password, name); EncryptedPassword encryptedPassword = passwordSecurity.computeHash(password, name);
if (isRegistered(name)) { if (isRegistered(name)) {
return false; return false;
} }
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(name) .name(name)
.hash(hashResult.getHash()) .hash(encryptedPassword)
.lastLogin(0) .lastLogin(0)
.realName(playerName) .realName(playerName)
.build(); .build();

View File

@ -3,7 +3,7 @@ package fr.xephi.authme.api;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -149,14 +149,13 @@ public class NewAPI {
*/ */
public boolean registerPlayer(String playerName, String password) { public boolean registerPlayer(String playerName, String password) {
String name = playerName.toLowerCase(); String name = playerName.toLowerCase();
HashResult result = plugin.getPasswordSecurity().computeHash(password, name); EncryptedPassword result = plugin.getPasswordSecurity().computeHash(password, name);
if (isRegistered(name)) { if (isRegistered(name)) {
return false; return false;
} }
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(name) .name(name)
.hash(result.getHash()) .hash(result)
.salt(result.getSalt())
.realName(playerName) .realName(playerName)
.build(); .build();
return plugin.getDataSource().saveAuth(auth); return plugin.getDataSource().saveAuth(auth);

View File

@ -1,11 +1,9 @@
package fr.xephi.authme.cache.auth; package fr.xephi.authme.cache.auth;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings;
import static com.google.common.base.Objects.firstNonNull; import static com.google.common.base.Objects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.nullToEmpty;
/** /**
@ -13,14 +11,13 @@ import static com.google.common.base.Strings.nullToEmpty;
public class PlayerAuth { public class PlayerAuth {
private String nickname; private String nickname;
private String hash; private EncryptedPassword password;
private String ip; private String ip;
private long lastLogin; private long lastLogin;
private double x; private double x;
private double y; private double y;
private double z; private double z;
private String world; private String world;
private String salt;
private int groupId; private int groupId;
private String email; private String email;
private String realName; private String realName;
@ -41,7 +38,7 @@ public class PlayerAuth {
* @param realName String * @param realName String
*/ */
public PlayerAuth(String nickname, String ip, long lastLogin, String realName) { public PlayerAuth(String nickname, String ip, long lastLogin, String realName) {
this(nickname, "", "", -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); this(nickname, new EncryptedPassword(""), -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName);
} }
/** /**
@ -55,7 +52,8 @@ public class PlayerAuth {
* @param realName String * @param realName String
*/ */
public PlayerAuth(String nickname, double x, double y, double z, String world, String realName) { public PlayerAuth(String nickname, double x, double y, double z, String world, String realName) {
this(nickname, "", "", -1, "127.0.0.1", System.currentTimeMillis(), x, y, z, world, "your@email.com", realName); this(nickname, new EncryptedPassword(""), -1, "127.0.0.1", System.currentTimeMillis(), x, y, z, world,
"your@email.com", realName);
} }
/** /**
@ -68,7 +66,7 @@ public class PlayerAuth {
* @param realName String * @param realName String
*/ */
public PlayerAuth(String nickname, String hash, String ip, long lastLogin, String realName) { public PlayerAuth(String nickname, String hash, String ip, long lastLogin, String realName) {
this(nickname, hash, "", -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); this(nickname, new EncryptedPassword(hash), -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName);
} }
/** /**
@ -82,7 +80,7 @@ public class PlayerAuth {
* @param realName String * @param realName String
*/ */
public PlayerAuth(String nickname, String hash, String ip, long lastLogin, String email, String realName) { public PlayerAuth(String nickname, String hash, String ip, long lastLogin, String email, String realName) {
this(nickname, hash, "", -1, ip, lastLogin, 0, 0, 0, "world", email, realName); this(nickname, new EncryptedPassword(hash), -1, ip, lastLogin, 0, 0, 0, "world", email, realName);
} }
/** /**
@ -96,7 +94,7 @@ public class PlayerAuth {
* @param realName String * @param realName String
*/ */
public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, String realName) { public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, String realName) {
this(nickname, hash, salt, -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName); this(nickname, new EncryptedPassword(hash, salt), -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName);
} }
/** /**
@ -113,8 +111,9 @@ public class PlayerAuth {
* @param email String * @param email String
* @param realName String * @param realName String
*/ */
public PlayerAuth(String nickname, String hash, String ip, long lastLogin, double x, double y, double z, String world, String email, String realName) { public PlayerAuth(String nickname, String hash, String ip, long lastLogin, double x, double y, double z,
this(nickname, hash, "", -1, ip, lastLogin, x, y, z, world, email, realName); String world, String email, String realName) {
this(nickname, new EncryptedPassword(hash), -1, ip, lastLogin, x, y, z, world, email, realName);
} }
/** /**
@ -132,8 +131,10 @@ public class PlayerAuth {
* @param email String * @param email String
* @param realName String * @param realName String
*/ */
public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, double x, double y, double z, String world, String email, String realName) { public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, double x, double y,
this(nickname, hash, salt, -1, ip, lastLogin, x, y, z, world, email, realName); double z, String world, String email, String realName) {
this(nickname, new EncryptedPassword(hash, salt), -1, ip, lastLogin,
x, y, z, world, email, realName);
} }
/** /**
@ -147,38 +148,37 @@ public class PlayerAuth {
* @param lastLogin long * @param lastLogin long
* @param realName String * @param realName String
*/ */
public PlayerAuth(String nickname, String hash, String salt, int groupId, String ip, long lastLogin, String realName) {
this(nickname, hash, salt, groupId, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName);
}
/**
* Constructor for PlayerAuth.
*
* @param nickname String
* @param hash String
* @param salt String
* @param groupId int
* @param ip String
* @param lastLogin long
* @param x double
* @param y double
* @param z double
* @param world String
* @param email String
* @param realName String
*/
public PlayerAuth(String nickname, String hash, String salt, int groupId, String ip, public PlayerAuth(String nickname, String hash, String salt, int groupId, String ip,
long lastLogin, double x, double y, double z, String world, String email, long lastLogin, String realName) {
String realName) { this(nickname, new EncryptedPassword(hash, salt), groupId, ip, lastLogin,
0, 0, 0, "world", "your@email.com", realName);
}
/**
* Constructor for PlayerAuth.
*
* @param nickname String
* @param password String
* @param groupId int
* @param ip String
* @param lastLogin long
* @param x double
* @param y double
* @param z double
* @param world String
* @param email String
* @param realName String
*/
public PlayerAuth(String nickname, EncryptedPassword password, int groupId, String ip, long lastLogin,
double x, double y, double z, String world, String email, String realName) {
this.nickname = nickname.toLowerCase(); this.nickname = nickname.toLowerCase();
this.hash = hash; this.password = password;
this.ip = ip; this.ip = ip;
this.lastLogin = lastLogin; this.lastLogin = lastLogin;
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
this.world = world; this.world = world;
this.salt = salt;
this.groupId = groupId; this.groupId = groupId;
this.email = email; this.email = email;
this.realName = realName; this.realName = realName;
@ -191,237 +191,108 @@ public class PlayerAuth {
*/ */
public void set(PlayerAuth auth) { public void set(PlayerAuth auth) {
this.setEmail(auth.getEmail()); this.setEmail(auth.getEmail());
this.setHash(auth.getHash()); this.setPassword(auth.getPassword());
this.setIp(auth.getIp()); this.setIp(auth.getIp());
this.setLastLogin(auth.getLastLogin()); this.setLastLogin(auth.getLastLogin());
this.setNickname(auth.getNickname()); this.setNickname(auth.getNickname());
this.setQuitLocX(auth.getQuitLocX()); this.setQuitLocX(auth.getQuitLocX());
this.setQuitLocY(auth.getQuitLocY()); this.setQuitLocY(auth.getQuitLocY());
this.setQuitLocZ(auth.getQuitLocZ()); this.setQuitLocZ(auth.getQuitLocZ());
this.setSalt(auth.getSalt());
this.setWorld(auth.getWorld()); this.setWorld(auth.getWorld());
this.setRealName(auth.getRealName()); this.setRealName(auth.getRealName());
} }
/**
* Method setNickname.
*
* @param nickname String
*/
public void setNickname(String nickname) { public void setNickname(String nickname) {
this.nickname = nickname.toLowerCase(); this.nickname = nickname.toLowerCase();
} }
/**
* Method getNickname.
*
* @return String
*/
public String getNickname() { public String getNickname() {
return nickname; return nickname;
} }
/**
* Method getRealName.
*
* @return String
*/
public String getRealName() { public String getRealName() {
return realName; return realName;
} }
/**
* Method setRealName.
*
* @param realName String
*/
public void setRealName(String realName) { public void setRealName(String realName) {
this.realName = realName; this.realName = realName;
} }
/**
* Method getGroupId.
*
* @return int
*/
public int getGroupId() { public int getGroupId() {
return groupId; return groupId;
} }
/**
* Method getQuitLocX.
*
* @return double
*/
public double getQuitLocX() { public double getQuitLocX() {
return x; return x;
} }
/**
* Method setQuitLocX.
*
* @param d double
*/
public void setQuitLocX(double d) { public void setQuitLocX(double d) {
this.x = d; this.x = d;
} }
/**
* Method getQuitLocY.
*
* @return double
*/
public double getQuitLocY() { public double getQuitLocY() {
return y; return y;
} }
/**
* Method setQuitLocY.
*
* @param d double
*/
public void setQuitLocY(double d) { public void setQuitLocY(double d) {
this.y = d; this.y = d;
} }
/**
* Method getQuitLocZ.
*
* @return double
*/
public double getQuitLocZ() { public double getQuitLocZ() {
return z; return z;
} }
/**
* Method setQuitLocZ.
*
* @param d double
*/
public void setQuitLocZ(double d) { public void setQuitLocZ(double d) {
this.z = d; this.z = d;
} }
/**
* Method getWorld.
*
* @return String
*/
public String getWorld() { public String getWorld() {
return world; return world;
} }
/**
* Method setWorld.
*
* @param world String
*/
public void setWorld(String world) { public void setWorld(String world) {
this.world = world; this.world = world;
} }
/**
* Method getIp.
*
* @return String
*/
public String getIp() { public String getIp() {
return ip; return ip;
} }
/**
* Method setIp.
*
* @param ip String
*/
public void setIp(String ip) { public void setIp(String ip) {
this.ip = ip; this.ip = ip;
} }
/**
* Method getLastLogin.
*
* @return long
*/
public long getLastLogin() { public long getLastLogin() {
return lastLogin; return lastLogin;
} }
/**
* Method setLastLogin.
*
* @param lastLogin long
*/
public void setLastLogin(long lastLogin) { public void setLastLogin(long lastLogin) {
this.lastLogin = lastLogin; this.lastLogin = lastLogin;
} }
/**
* Method getEmail.
*
* @return String
*/
public String getEmail() { public String getEmail() {
return email; return email;
} }
/**
* Method setEmail.
*
* @param email String
*/
public void setEmail(String email) { public void setEmail(String email) {
this.email = email; this.email = email;
} }
/** public EncryptedPassword getPassword() {
* Method getSalt. // TODO #358: Check whether this check is really necessary. It's been here since the first commit.
* /*if (Settings.getPasswordHash == HashAlgorithm.MD5VB) {
* @return String
*/
public String getSalt() {
return this.salt;
}
/**
* Method setSalt.
*
* @param salt String
*/
public void setSalt(String salt) {
this.salt = salt;
}
/**
* Method getHash.
*
* @return String
*/
public String getHash() {
if (Settings.getPasswordHash == HashAlgorithm.MD5VB) {
if (salt != null && !salt.isEmpty() && Settings.getPasswordHash == HashAlgorithm.MD5VB) { if (salt != null && !salt.isEmpty() && Settings.getPasswordHash == HashAlgorithm.MD5VB) {
return "$MD5vb$" + salt + "$" + hash; return "$MD5vb$" + salt + "$" + hash;
} }
} }*/
return hash; return password;
} }
/** public void setPassword(EncryptedPassword password) {
* Method setHash. this.password = password;
*
* @param hash String
*/
public void setHash(String hash) {
this.hash = hash;
} }
/**
* Method equals.
*
* @param obj Object
*
* @return boolean
*/
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (!(obj instanceof PlayerAuth)) { if (!(obj instanceof PlayerAuth)) {
@ -431,11 +302,6 @@ public class PlayerAuth {
return other.getIp().equals(this.ip) && other.getNickname().equals(this.nickname); return other.getIp().equals(this.ip) && other.getNickname().equals(this.nickname);
} }
/**
* Method hashCode.
*
* @return int
*/
@Override @Override
public int hashCode() { public int hashCode() {
int hashCode = 7; int hashCode = 7;
@ -444,20 +310,14 @@ public class PlayerAuth {
return hashCode; return hashCode;
} }
/**
* Method toString.
*
* @return String
*/
@Override @Override
public String toString() { public String toString() {
return ("Player : " + nickname + " | " + realName return "Player : " + nickname + " | " + realName
+ " ! IP : " + ip + " ! IP : " + ip
+ " ! LastLogin : " + lastLogin + " ! LastLogin : " + lastLogin
+ " ! LastPosition : " + x + "," + y + "," + z + "," + world + " ! LastPosition : " + x + "," + y + "," + z + "," + world
+ " ! Email : " + email + " ! Email : " + email
+ " ! Hash : " + hash + " ! Hash : {" + password.getHash() + ", " + password.getSalt() + "}";
+ " ! Salt : " + salt);
} }
/** /**
@ -472,8 +332,8 @@ public class PlayerAuth {
str.append(this.realName).append(d); str.append(this.realName).append(d);
str.append(this.ip).append(d); str.append(this.ip).append(d);
str.append(this.email).append(d); str.append(this.email).append(d);
str.append(this.hash).append(d); str.append(this.password.getHash()).append(d);
str.append(this.salt).append(d); str.append(this.password.getSalt()).append(d);
str.append(this.groupId).append(d); str.append(this.groupId).append(d);
str.append(this.lastLogin).append(d); str.append(this.lastLogin).append(d);
str.append(this.world).append(d); str.append(this.world).append(d);
@ -492,8 +352,7 @@ public class PlayerAuth {
this.realName = args[1]; this.realName = args[1];
this.ip = args[2]; this.ip = args[2];
this.email = args[3]; this.email = args[3];
this.hash = args[4]; this.password = new EncryptedPassword(args[4], args[5]);
this.salt = args[5];
this.groupId = Integer.parseInt(args[6]); this.groupId = Integer.parseInt(args[6]);
this.lastLogin = Long.parseLong(args[7]); this.lastLogin = Long.parseLong(args[7]);
this.world = args[8]; this.world = args[8];
@ -509,8 +368,7 @@ public class PlayerAuth {
public static final class Builder { public static final class Builder {
private String name; private String name;
private String realName; private String realName;
private String hash; private EncryptedPassword hash;
private String salt;
private String ip; private String ip;
private String world; private String world;
private String email; private String email;
@ -523,8 +381,7 @@ public class PlayerAuth {
public PlayerAuth build() { public PlayerAuth build() {
return new PlayerAuth( return new PlayerAuth(
checkNotNull(name), checkNotNull(name),
nullToEmpty(hash), firstNonNull(hash, new EncryptedPassword("")),
nullToEmpty(salt),
groupId, groupId,
firstNonNull(ip, "127.0.0.1"), firstNonNull(ip, "127.0.0.1"),
lastLogin, lastLogin,
@ -545,14 +402,13 @@ public class PlayerAuth {
return this; return this;
} }
public Builder hash(String hash) { public Builder hash(EncryptedPassword hash) {
this.hash = hash; this.hash = hash;
return this; return this;
} }
public Builder salt(String salt) { public Builder hash(String hash, String salt) {
this.salt = salt; return hash(new EncryptedPassword(hash, salt));
return this;
} }
public Builder ip(String ip) { public Builder ip(String ip) {

View File

@ -7,7 +7,7 @@ import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -68,11 +68,9 @@ public class ChangePasswordAdminCommand implements ExecutableCommand {
} }
// TODO #358: Do we always pass lowercase name?? In that case we need to do that in PasswordSecurity! // TODO #358: Do we always pass lowercase name?? In that case we need to do that in PasswordSecurity!
HashResult hashResult = commandService.getPasswordSecurity().computeHash(playerPass, playerNameLowerCase); EncryptedPassword encryptedPassword = commandService.getPasswordSecurity().computeHash(playerPass, playerNameLowerCase);
auth.setHash(hashResult.getHash()); auth.setPassword(encryptedPassword);
auth.setSalt(hashResult.getSalt());
// TODO #358: updatePassword(auth) needs to update the salt, too.
if (!dataSource.updatePassword(auth)) { if (!dataSource.updatePassword(auth)) {
commandService.send(sender, MessageKey.ERROR); commandService.send(sender, MessageKey.ERROR);
} else { } else {

View File

@ -5,7 +5,7 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -57,13 +57,12 @@ public class RegisterAdminCommand implements ExecutableCommand {
commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED); commandService.send(sender, MessageKey.NAME_ALREADY_REGISTERED);
return; return;
} }
HashResult hashResult = commandService.getPasswordSecurity() EncryptedPassword encryptedPassword = commandService.getPasswordSecurity()
.computeHash(playerPass, playerNameLowerCase); .computeHash(playerPass, playerNameLowerCase);
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(playerNameLowerCase) .name(playerNameLowerCase)
.realName(playerName) .realName(playerName)
.hash(hashResult.getHash()) .hash(encryptedPassword)
.salt(hashResult.getSalt())
.build(); .build();
if (!commandService.getDataSource().saveAuth(auth)) { if (!commandService.getDataSource().saveAuth(auth)) {

View File

@ -8,7 +8,7 @@ import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.RandomString; import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -37,7 +37,7 @@ public class RecoverEmailCommand extends PlayerCommand {
} }
String thePass = RandomString.generate(Settings.getRecoveryPassLength); String thePass = RandomString.generate(Settings.getRecoveryPassLength);
HashResult hashNew = commandService.getPasswordSecurity().computeHash(thePass, playerName); EncryptedPassword hashNew = commandService.getPasswordSecurity().computeHash(thePass, playerName);
PlayerAuth auth; PlayerAuth auth;
if (PlayerCache.getInstance().isAuthenticated(playerName)) { if (PlayerCache.getInstance().isAuthenticated(playerName)) {
auth = PlayerCache.getInstance().getAuth(playerName); auth = PlayerCache.getInstance().getAuth(playerName);
@ -57,8 +57,7 @@ public class RecoverEmailCommand extends PlayerCommand {
commandService.send(player, MessageKey.INVALID_EMAIL); commandService.send(player, MessageKey.INVALID_EMAIL);
return; return;
} }
auth.setHash(hashNew.getHash()); auth.setPassword(hashNew);
auth.setSalt(hashNew.getSalt());
dataSource.updatePassword(auth); dataSource.updatePassword(auth);
plugin.mail.main(auth, thePass); plugin.mail.main(auth, thePass);
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE); commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);

View File

@ -6,7 +6,7 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -42,7 +42,7 @@ public class RakamakConverter implements Converter {
File source = new File(Settings.PLUGIN_FOLDER, fileName); File source = new File(Settings.PLUGIN_FOLDER, fileName);
File ipfiles = new File(Settings.PLUGIN_FOLDER, ipFileName); File ipfiles = new File(Settings.PLUGIN_FOLDER, ipFileName);
HashMap<String, String> playerIP = new HashMap<>(); HashMap<String, String> playerIP = new HashMap<>();
HashMap<String, HashResult> playerPSW = new HashMap<>(); HashMap<String, EncryptedPassword> playerPSW = new HashMap<>();
try { try {
BufferedReader users; BufferedReader users;
BufferedReader ipFile; BufferedReader ipFile;
@ -64,22 +64,21 @@ public class RakamakConverter implements Converter {
while ((line = users.readLine()) != null) { while ((line = users.readLine()) != null) {
if (line.contains("=")) { if (line.contains("=")) {
String[] arguments = line.split("="); String[] arguments = line.split("=");
HashResult hashResult = passwordSecurity.computeHash(hash, arguments[1], arguments[0]); EncryptedPassword encryptedPassword = passwordSecurity.computeHash(hash, arguments[1], arguments[0]);
playerPSW.put(arguments[0], hashResult); playerPSW.put(arguments[0], encryptedPassword);
} }
} }
users.close(); users.close();
for (Entry<String, HashResult> m : playerPSW.entrySet()) { for (Entry<String, EncryptedPassword> m : playerPSW.entrySet()) {
String playerName = m.getKey(); String playerName = m.getKey();
HashResult psw = playerPSW.get(playerName); EncryptedPassword psw = playerPSW.get(playerName);
String ip = useIP ? playerIP.get(playerName) : "127.0.0.1"; String ip = useIP ? playerIP.get(playerName) : "127.0.0.1";
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(playerName) .name(playerName)
.realName(playerName) .realName(playerName)
.ip(ip) .ip(ip)
.hash(psw.getHash()) .hash(psw)
.salt(psw.getSalt())
.lastLogin(System.currentTimeMillis()) .lastLogin(System.currentTimeMillis())
.build(); .build();
database.saveAuth(auth); database.saveAuth(auth);

View File

@ -270,24 +270,6 @@ public class CacheDataSource implements DataSource {
return result; return result;
} }
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean
*
* @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth)
*/
@Override
public synchronized boolean updateSalt(final PlayerAuth auth) {
boolean result = source.updateSalt(auth);
if (result) {
cachedAuths.refresh(auth.getNickname());
}
return result;
}
/** /**
* Method getAllAuthsByName. * Method getAllAuthsByName.
* *

View File

@ -134,15 +134,6 @@ public interface DataSource {
*/ */
boolean updateEmail(PlayerAuth auth); boolean updateEmail(PlayerAuth auth);
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean
*/
boolean updateSalt(PlayerAuth auth);
void close(); void close();
void reload(); void reload();

View File

@ -102,7 +102,7 @@ public class FlatFile implements DataSource {
BufferedWriter bw = null; BufferedWriter bw = null;
try { try {
bw = new BufferedWriter(new FileWriter(source, true)); bw = new BufferedWriter(new FileWriter(source, true));
bw.write(auth.getNickname() + ":" + auth.getHash() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n"); bw.write(auth.getNickname() + ":" + auth.getPassword() + ":" + auth.getIp() + ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY() + ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
} catch (IOException ex) { } catch (IOException ex) {
ConsoleLogger.showError(ex.getMessage()); ConsoleLogger.showError(ex.getMessage());
return false; return false;
@ -137,25 +137,26 @@ public class FlatFile implements DataSource {
while ((line = br.readLine()) != null) { while ((line = br.readLine()) != null) {
String[] args = line.split(":"); String[] args = line.split(":");
if (args[0].equals(auth.getNickname())) { if (args[0].equals(auth.getNickname())) {
// Note ljacqu 20151230: This does not persist the salt; it is not supported in flat file.
switch (args.length) { switch (args.length) {
case 4: { case 4: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), 0, 0, 0, "world", "your@email.com", args[0]); newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), 0, 0, 0, "world", "your@email.com", args[0]);
break; break;
} }
case 7: { case 7: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), "world", "your@email.com", args[0]); newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), "world", "your@email.com", args[0]);
break; break;
} }
case 8: { case 8: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], "your@email.com", args[0]); newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], "your@email.com", args[0]);
break; break;
} }
case 9: { case 9: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], args[8], args[0]); newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], Long.parseLong(args[3]), Double.parseDouble(args[4]), Double.parseDouble(args[5]), Double.parseDouble(args[6]), args[7], args[8], args[0]);
break; break;
} }
default: { default: {
newAuth = new PlayerAuth(args[0], auth.getHash(), args[2], 0, 0, 0, 0, "world", "your@email.com", args[0]); newAuth = new PlayerAuth(args[0], auth.getPassword().getHash(), args[2], 0, 0, 0, 0, "world", "your@email.com", args[0]);
break; break;
} }
} }
@ -600,18 +601,6 @@ public class FlatFile implements DataSource {
return true; return true;
} }
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth)
*/
@Override
public boolean updateSalt(PlayerAuth auth) {
return false;
}
/** /**
* Method getAllAuthsByName. * Method getAllAuthsByName.
* *

View File

@ -6,7 +6,9 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import java.sql.*; import java.sql.*;
import java.util.ArrayList; import java.util.ArrayList;
@ -284,13 +286,14 @@ public class MySQL implements DataSource {
if (!rs.next()) { if (!rs.next()) {
return null; return null;
} }
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : ""; String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null;
int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; String hash = rs.getString(columnPassword);
int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
int id = rs.getInt(columnID); int id = rs.getInt(columnID);
pAuth = PlayerAuth.builder() pAuth = PlayerAuth.builder()
.name(rs.getString(columnName)) .name(rs.getString(columnName))
.realName(rs.getString(columnRealName)) .realName(rs.getString(columnRealName))
.hash(rs.getString(columnPassword)) .hash(new EncryptedPassword(hash, salt))
.lastLogin(rs.getLong(columnLastLogin)) .lastLogin(rs.getLong(columnLastLogin))
.ip(rs.getString(columnIp)) .ip(rs.getString(columnIp))
.locWorld(rs.getString(lastlocWorld)) .locWorld(rs.getString(lastlocWorld))
@ -298,7 +301,6 @@ public class MySQL implements DataSource {
.locY(rs.getDouble(lastlocY)) .locY(rs.getDouble(lastlocY))
.locZ(rs.getDouble(lastlocZ)) .locZ(rs.getDouble(lastlocZ))
.email(rs.getString(columnEmail)) .email(rs.getString(columnEmail))
.salt(salt)
.groupId(group) .groupId(group)
.build(); .build();
rs.close(); rs.close();
@ -328,7 +330,7 @@ public class MySQL implements DataSource {
ResultSet rs; ResultSet rs;
String sql; String sql;
boolean useSalt = !columnSalt.isEmpty() || !auth.getSalt().isEmpty(); boolean useSalt = !columnSalt.isEmpty() || !StringUtils.isEmpty(auth.getPassword().getSalt());
sql = "INSERT INTO " + tableName + "(" sql = "INSERT INTO " + tableName + "("
+ columnName + "," + columnPassword + "," + columnIp + "," + columnName + "," + columnPassword + "," + columnIp + ","
+ columnLastLogin + "," + columnRealName + columnLastLogin + "," + columnRealName
@ -336,12 +338,12 @@ public class MySQL implements DataSource {
+ ") VALUES (?,?,?,?,?" + (useSalt ? ",?" : "") + ");"; + ") VALUES (?,?,?,?,?" + (useSalt ? ",?" : "") + ");";
pst = con.prepareStatement(sql); pst = con.prepareStatement(sql);
pst.setString(1, auth.getNickname()); pst.setString(1, auth.getNickname());
pst.setString(2, auth.getHash()); pst.setString(2, auth.getPassword().getHash());
pst.setString(3, auth.getIp()); pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin()); pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getRealName()); pst.setString(5, auth.getRealName());
if (useSalt) { if (useSalt) {
pst.setString(6, auth.getSalt()); pst.setString(6, auth.getPassword().getSalt());
} }
pst.executeUpdate(); pst.executeUpdate();
pst.close(); pst.close();
@ -513,10 +515,22 @@ public class MySQL implements DataSource {
@Override @Override
public synchronized boolean updatePassword(PlayerAuth auth) { public synchronized boolean updatePassword(PlayerAuth auth) {
try (Connection con = getConnection()) { try (Connection con = getConnection()) {
String sql = "UPDATE " + tableName + " SET " + columnPassword + "=? WHERE " + columnName + "=?;"; boolean useSalt = !columnSalt.isEmpty();
PreparedStatement pst = con.prepareStatement(sql); PreparedStatement pst;
pst.setString(1, auth.getHash()); if (useSalt) {
pst.setString(2, auth.getNickname()); String sql = String.format("UPDATE %s SET %s = ?, %s = ? WHERE %s = ?;",
tableName, columnPassword, columnSalt, columnName);
pst = con.prepareStatement(sql);
pst.setString(1, auth.getPassword().getHash());
pst.setString(2, auth.getPassword().getSalt());
pst.setString(3, auth.getNickname());
} else {
String sql = String.format("UPDATE %s SET %s = ? WHERE %s = ?;",
tableName, columnPassword, columnName);
pst = con.prepareStatement(sql);
pst.setString(1, auth.getPassword().getHash());
pst.setString(2, auth.getNickname());
}
pst.executeUpdate(); pst.executeUpdate();
pst.close(); pst.close();
return true; return true;
@ -719,35 +733,6 @@ public class MySQL implements DataSource {
return false; return false;
} }
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean
*
* @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth)
*/
@Override
public synchronized boolean updateSalt(PlayerAuth auth) {
if (columnSalt.isEmpty()) {
return false;
}
try (Connection con = getConnection()) {
String sql = "UPDATE " + tableName + " SET " + columnSalt + " =? WHERE " + columnName + "=?;";
PreparedStatement pst = con.prepareStatement(sql);
pst.setString(1, auth.getSalt());
pst.setString(2, auth.getNickname());
pst.executeUpdate();
pst.close();
return true;
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
}
return false;
}
/** /**
* Method reload. * Method reload.
* *
@ -1045,12 +1030,12 @@ public class MySQL implements DataSource {
ResultSet rs = st.executeQuery("SELECT * FROM " + tableName); ResultSet rs = st.executeQuery("SELECT * FROM " + tableName);
PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;"); PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;");
while (rs.next()) { while (rs.next()) {
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : ""; String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null;
int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
PlayerAuth pAuth = PlayerAuth.builder() PlayerAuth pAuth = PlayerAuth.builder()
.name(rs.getString(columnName)) .name(rs.getString(columnName))
.realName(rs.getString(columnRealName)) .realName(rs.getString(columnRealName))
.hash(rs.getString(columnPassword)) .hash(new EncryptedPassword(rs.getString(columnPassword), salt))
.lastLogin(rs.getLong(columnLastLogin)) .lastLogin(rs.getLong(columnLastLogin))
.ip(rs.getString(columnIp)) .ip(rs.getString(columnIp))
.locWorld(rs.getString(lastlocWorld)) .locWorld(rs.getString(lastlocWorld))
@ -1058,7 +1043,6 @@ public class MySQL implements DataSource {
.locY(rs.getDouble(lastlocY)) .locY(rs.getDouble(lastlocY))
.locZ(rs.getDouble(lastlocZ)) .locZ(rs.getDouble(lastlocZ))
.email(rs.getString(columnEmail)) .email(rs.getString(columnEmail))
.salt(salt)
.groupId(group) .groupId(group)
.build(); .build();
@ -1089,12 +1073,12 @@ public class MySQL implements DataSource {
ResultSet rs = st.executeQuery("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); ResultSet rs = st.executeQuery("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;");
PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;"); PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + columnID + "=?;");
while (rs.next()) { while (rs.next()) {
String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : ""; String salt = !columnSalt.isEmpty() ? rs.getString(columnSalt) : null;
int group = !salt.isEmpty() && !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1; int group = !columnGroup.isEmpty() ? rs.getInt(columnGroup) : -1;
PlayerAuth pAuth = PlayerAuth.builder() PlayerAuth pAuth = PlayerAuth.builder()
.name(rs.getString(columnName)) .name(rs.getString(columnName))
.realName(rs.getString(columnRealName)) .realName(rs.getString(columnRealName))
.hash(rs.getString(columnPassword)) .hash(new EncryptedPassword(rs.getString(columnPassword), salt))
.lastLogin(rs.getLong(columnLastLogin)) .lastLogin(rs.getLong(columnLastLogin))
.ip(rs.getString(columnIp)) .ip(rs.getString(columnIp))
.locWorld(rs.getString(lastlocWorld)) .locWorld(rs.getString(lastlocWorld))
@ -1102,7 +1086,6 @@ public class MySQL implements DataSource {
.locY(rs.getDouble(lastlocY)) .locY(rs.getDouble(lastlocY))
.locZ(rs.getDouble(lastlocZ)) .locZ(rs.getDouble(lastlocZ))
.email(rs.getString(columnEmail)) .email(rs.getString(columnEmail))
.salt(salt)
.groupId(group) .groupId(group)
.build(); .build();

View File

@ -2,6 +2,7 @@ package fr.xephi.authme.datasource;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import java.sql.*; import java.sql.*;
@ -174,15 +175,7 @@ public class SQLite implements DataSource {
pst.setString(1, user); pst.setString(1, user);
rs = pst.executeQuery(); rs = pst.executeQuery();
if (rs.next()) { if (rs.next()) {
if (rs.getString(columnIp).isEmpty()) { return buildAuthFromResultSet(rs);
return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "192.168.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
if (!columnSalt.isEmpty()) {
return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
return new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
}
}
} else { } else {
return null; return null;
} }
@ -206,21 +199,25 @@ public class SQLite implements DataSource {
public synchronized boolean saveAuth(PlayerAuth auth) { public synchronized boolean saveAuth(PlayerAuth auth) {
PreparedStatement pst = null; PreparedStatement pst = null;
try { try {
if (columnSalt.isEmpty() && auth.getSalt().isEmpty()) { EncryptedPassword password = auth.getPassword();
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + columnIp + "," + columnLastLogin + "," + columnRealName + ") VALUES (?,?,?,?,?);"); if (columnSalt.isEmpty() && password.getSalt().isEmpty()) {
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword +
"," + columnIp + "," + columnLastLogin + "," + columnRealName + ") VALUES (?,?,?,?,?);");
pst.setString(1, auth.getNickname()); pst.setString(1, auth.getNickname());
pst.setString(2, auth.getHash()); pst.setString(2, password.getHash());
pst.setString(3, auth.getIp()); pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin()); pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getRealName()); pst.setString(5, auth.getRealName());
pst.executeUpdate(); pst.executeUpdate();
} else { } else {
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + "," + columnIp + "," + columnLastLogin + "," + columnSalt + "," + columnRealName + ") VALUES (?,?,?,?,?,?);"); pst = con.prepareStatement("INSERT INTO " + tableName + "(" + columnName + "," + columnPassword + ","
+ columnIp + "," + columnLastLogin + "," + columnSalt + "," + columnRealName
+ ") VALUES (?,?,?,?,?,?);");
pst.setString(1, auth.getNickname()); pst.setString(1, auth.getNickname());
pst.setString(2, auth.getHash()); pst.setString(2, password.getHash());
pst.setString(3, auth.getIp()); pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin()); pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getSalt()); pst.setString(5, password.getSalt());
pst.setString(6, auth.getRealName()); pst.setString(6, auth.getRealName());
pst.executeUpdate(); pst.executeUpdate();
} }
@ -244,9 +241,19 @@ public class SQLite implements DataSource {
public synchronized boolean updatePassword(PlayerAuth auth) { public synchronized boolean updatePassword(PlayerAuth auth) {
PreparedStatement pst = null; PreparedStatement pst = null;
try { try {
pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnPassword + "=? WHERE " + columnName + "=?;"); EncryptedPassword password = auth.getPassword();
pst.setString(1, auth.getHash()); boolean useSalt = !columnSalt.isEmpty();
pst.setString(2, auth.getNickname()); String sql = "UPDATE " + tableName + " SET " + columnPassword + " = ?"
+ (useSalt ? ", " + columnSalt + " = ?" : "")
+ " WHERE " + columnName + " = ?";
pst = con.prepareStatement(sql);
pst.setString(1, password.getHash());
if (useSalt) {
pst.setString(2, password.getSalt());
pst.setString(3, auth.getNickname());
} else {
pst.setString(2, auth.getNickname());
}
pst.executeUpdate(); pst.executeUpdate();
} catch (SQLException ex) { } catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage()); ConsoleLogger.showError(ex.getMessage());
@ -398,6 +405,7 @@ public class SQLite implements DataSource {
ResultSet rs = null; ResultSet rs = null;
int countIp = 0; int countIp = 0;
try { try {
// TODO ljacqu 20151230: Simply fetch COUNT(1) and return that
pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;"); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnIp + "=?;");
pst.setString(1, ip); pst.setString(1, ip);
rs = pst.executeQuery(); rs = pst.executeQuery();
@ -438,33 +446,6 @@ public class SQLite implements DataSource {
return true; return true;
} }
/**
* Method updateSalt.
*
* @param auth PlayerAuth
*
* @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSalt(PlayerAuth)
*/
@Override
public boolean updateSalt(PlayerAuth auth) {
if (columnSalt.isEmpty()) {
return false;
}
PreparedStatement pst = null;
try {
pst = con.prepareStatement("UPDATE " + tableName + " SET " + columnSalt + "=? WHERE " + columnName + "=?;");
pst.setString(1, auth.getSalt());
pst.setString(2, auth.getNickname());
pst.executeUpdate();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
return false;
} finally {
close(pst);
}
return true;
}
/** /**
* Method close. * Method close.
* *
@ -761,14 +742,6 @@ public class SQLite implements DataSource {
return result; return result;
} }
/**
* Method updateName.
*
* @param oldOne String
* @param newOne String
*
* @see fr.xephi.authme.datasource.DataSource#updateName(String, String)
*/
@Override @Override
public void updateName(String oldOne, String newOne) { public void updateName(String oldOne, String newOne) {
PreparedStatement pst = null; PreparedStatement pst = null;
@ -787,7 +760,7 @@ public class SQLite implements DataSource {
/** /**
* Method getAllAuths. * Method getAllAuths.
* *
* @return List<PlayerAuth> * @see fr.xephi.authme.datasource.DataSource#getAllAuths() * @return List<PlayerAuth>
*/ */
@Override @Override
public List<PlayerAuth> getAllAuths() { public List<PlayerAuth> getAllAuths() {
@ -798,17 +771,8 @@ public class SQLite implements DataSource {
pst = con.prepareStatement("SELECT * FROM " + tableName + ";"); pst = con.prepareStatement("SELECT * FROM " + tableName + ";");
rs = pst.executeQuery(); rs = pst.executeQuery();
while (rs.next()) { while (rs.next()) {
PlayerAuth pAuth; PlayerAuth auth = buildAuthFromResultSet(rs);
if (rs.getString(columnIp).isEmpty()) { auths.add(auth);
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
if (!columnSalt.isEmpty()) {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
}
}
auths.add(pAuth);
} }
} catch (SQLException ex) { } catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage()); ConsoleLogger.showError(ex.getMessage());
@ -822,7 +786,7 @@ public class SQLite implements DataSource {
/** /**
* Method getLoggedPlayers. * Method getLoggedPlayers.
* *
* @return List<PlayerAuth> * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers() * @return List<PlayerAuth>
*/ */
@Override @Override
public List<PlayerAuth> getLoggedPlayers() { public List<PlayerAuth> getLoggedPlayers() {
@ -833,17 +797,8 @@ public class SQLite implements DataSource {
pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;"); pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnLogged + "=1;");
rs = pst.executeQuery(); rs = pst.executeQuery();
while (rs.next()) { while (rs.next()) {
PlayerAuth pAuth; PlayerAuth auth = buildAuthFromResultSet(rs);
if (rs.getString(columnIp).isEmpty()) { auths.add(auth);
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), "127.0.0.1", rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
if (!columnSalt.isEmpty()) {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnSalt), rs.getInt(columnGroup), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
} else {
pAuth = new PlayerAuth(rs.getString(columnName), rs.getString(columnPassword), rs.getString(columnIp), rs.getLong(columnLastLogin), rs.getDouble(lastlocX), rs.getDouble(lastlocY), rs.getDouble(lastlocZ), rs.getString(lastlocWorld), rs.getString(columnEmail), rs.getString(columnRealName));
}
}
auths.add(pAuth);
} }
} catch (SQLException ex) { } catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage()); ConsoleLogger.showError(ex.getMessage());
@ -853,4 +808,25 @@ public class SQLite implements DataSource {
} }
return auths; return auths;
} }
private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException {
String salt = !columnSalt.isEmpty() ? row.getString(columnSalt) : null;
PlayerAuth.Builder authBuilder = PlayerAuth.builder()
.name(row.getString(columnName))
.email(row.getString(columnEmail))
.realName(row.getString(columnRealName))
.hash(row.getString(columnPassword), salt)
.lastLogin(row.getLong(columnLastLogin))
.locX(row.getDouble(lastlocX))
.locY(row.getDouble(lastlocY))
.locZ(row.getDouble(lastlocZ))
.locWorld(row.getString(lastlocWorld));
String ip = row.getString(columnIp);
if (!ip.isEmpty()) {
authBuilder.ip(ip);
}
return authBuilder.build();
}
} }

View File

@ -7,6 +7,7 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.security.crypts.EncryptedPassword;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener; import org.bukkit.plugin.messaging.PluginMessageListener;
@ -65,10 +66,8 @@ public class BungeeCordMessage implements PluginMessageListener {
+ " has registered out from one of your server!"); + " has registered out from one of your server!");
} else if ("changepassword".equals(act)) { } else if ("changepassword".equals(act)) {
final String password = args[2]; final String password = args[2];
auth.setHash(password); final String salt = args.length >= 4 ? args[3] : null;
if (args.length == 4) { auth.setPassword(new EncryptedPassword(password, salt));
auth.setSalt(args[3]);
}
PlayerCache.getInstance().updatePlayer(auth); PlayerCache.getInstance().updatePlayer(auth);
dataSource.updatePassword(auth); dataSource.updatePassword(auth);
} }

View File

@ -8,7 +8,6 @@ import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent; import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent;
import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.RandomString; import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
@ -138,7 +137,7 @@ public class AsynchronousLogin {
String email = pAuth.getEmail(); String email = pAuth.getEmail();
boolean passwordVerified = forceLogin || plugin.getPasswordSecurity() boolean passwordVerified = forceLogin || plugin.getPasswordSecurity()
.comparePassword(password, pAuth.getHash(), pAuth.getSalt(), realName); .comparePassword(password, pAuth.getPassword(), realName);
if (passwordVerified && player.isOnline()) { if (passwordVerified && player.isOnline()) {
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
@ -147,8 +146,7 @@ public class AsynchronousLogin {
.ip(getIP()) .ip(getIP())
.lastLogin(new Date().getTime()) .lastLogin(new Date().getTime())
.email(email) .email(email)
.hash(pAuth.getHash()) .hash(pAuth.getPassword())
.salt(pAuth.getSalt())
.build(); .build();
database.updateSession(auth); database.updateSession(auth);

View File

@ -8,7 +8,7 @@ import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -97,12 +97,11 @@ public class AsyncRegister {
m.send(player, MessageKey.MAX_REGISTER_EXCEEDED); m.send(player, MessageKey.MAX_REGISTER_EXCEEDED);
return; return;
} }
final HashResult hashResult = plugin.getPasswordSecurity().computeHash(password, name); final EncryptedPassword encryptedPassword = plugin.getPasswordSecurity().computeHash(password, name);
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(name) .name(name)
.realName(player.getName()) .realName(player.getName())
.hash(hashResult.getHash()) .hash(encryptedPassword)
.salt(hashResult.getSalt())
.ip(ip) .ip(ip)
.locWorld(player.getLocation().getWorld().getName()) .locWorld(player.getLocation().getWorld().getName())
.locX(player.getLocation().getX()) .locX(player.getLocation().getX())
@ -124,12 +123,11 @@ public class AsyncRegister {
} }
private void passwordRegister() throws Exception { private void passwordRegister() throws Exception {
final HashResult hashResult = plugin.getPasswordSecurity().computeHash(password, name); final EncryptedPassword encryptedPassword = plugin.getPasswordSecurity().computeHash(password, name);
PlayerAuth auth = PlayerAuth.builder() PlayerAuth auth = PlayerAuth.builder()
.name(name) .name(name)
.realName(player.getName()) .realName(player.getName())
.hash(hashResult.getHash()) .hash(encryptedPassword)
.salt(hashResult.getSalt())
.ip(ip) .ip(ip)
.locWorld(player.getLocation().getWorld().getName()) .locWorld(player.getLocation().getWorld().getName())
.locX(player.getLocation().getX()) .locX(player.getLocation().getX())

View File

@ -55,7 +55,7 @@ public class AsynchronousUnregister {
public void process() { public void process() {
PlayerAuth cachedAuth = PlayerCache.getInstance().getAuth(name); PlayerAuth cachedAuth = PlayerCache.getInstance().getAuth(name);
if (force || plugin.getPasswordSecurity().comparePassword( if (force || plugin.getPasswordSecurity().comparePassword(
password, cachedAuth.getHash(), cachedAuth.getSalt(), player.getName())) { password, cachedAuth.getPassword(), player.getName())) {
if (!plugin.getDataSource().removeAuth(name)) { if (!plugin.getDataSource().removeAuth(name)) {
m.send(player, MessageKey.ERROR); m.send(player, MessageKey.ERROR);
return; return;

View File

@ -3,12 +3,10 @@ package fr.xephi.authme.security;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.PasswordEncryptionEvent; import fr.xephi.authme.events.PasswordEncryptionEvent;
import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HashResult;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.HashMap;
/** /**
* Manager class for password-related operations. * Manager class for password-related operations.
*/ */
@ -24,48 +22,53 @@ public class PasswordSecurity {
this.supportOldAlgorithm = supportOldAlgorithm; this.supportOldAlgorithm = supportOldAlgorithm;
} }
public HashResult computeHash(String password, String playerName) { public EncryptedPassword computeHash(String password, String playerName) {
return computeHash(algorithm, password, playerName); return computeHash(algorithm, password, playerName);
} }
public HashResult computeHash(HashAlgorithm algorithm, String password, String playerName) { public EncryptedPassword computeHash(HashAlgorithm algorithm, String password, String playerName) {
EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName); EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName);
return method.computeHash(password, playerName); return method.computeHash(password, playerName);
} }
public boolean comparePassword(String password, String playerName) { public boolean comparePassword(String password, String playerName) {
// TODO ljacqu 20151230: Defining a dataSource.getPassword() method would be more efficient
PlayerAuth auth = dataSource.getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth != null) { if (auth != null) {
return comparePassword(auth.getHash(), auth.getSalt(), password, playerName); return comparePassword(password, auth.getPassword(), playerName);
} }
return false; return false;
} }
public boolean comparePassword(String hash, String salt, String password, String playerName) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) {
EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName); EncryptionMethod method = initializeEncryptionMethod(algorithm, playerName);
// User is not in data source, so the result will invariably be wrong because an encryption // 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 // method with hasSeparateSalt() == true NEEDS the salt to evaluate the password
String salt = encryptedPassword.getSalt();
if (method.hasSeparateSalt() && salt == null) { if (method.hasSeparateSalt() && salt == null) {
return false; return false;
} }
return method.comparePassword(hash, password, salt, playerName)
|| supportOldAlgorithm && compareWithAllEncryptionMethods(password, hash, salt, playerName); return method.comparePassword(password, encryptedPassword, playerName)
|| supportOldAlgorithm && compareWithAllEncryptionMethods(password, encryptedPassword, playerName);
} }
/** /**
* Compare the given hash with all available encryption methods to support the migration to a new encryption method. * Compare the given hash with all available encryption methods to support
* the migration to a new encryption method. Upon a successful match, the password
* will be hashed with the new encryption method and persisted.
* *
* @param password The clear-text password to check * @param password The clear-text password to check
* @param hash The hash to text the password against * @param encryptedPassword The encrypted password to test the clear-text password against
* @param salt The salt (or null if none available) * @param playerName The name of the player
* @param playerName The name of the player
* @return True if the * @return True if the
*/ */
private boolean compareWithAllEncryptionMethods(String password, String hash, String salt, String playerName) { private boolean compareWithAllEncryptionMethods(String password, EncryptedPassword encryptedPassword,
String playerName) {
for (HashAlgorithm algorithm : HashAlgorithm.values()) { for (HashAlgorithm algorithm : HashAlgorithm.values()) {
if (!HashAlgorithm.CUSTOM.equals(algorithm)) { if (!HashAlgorithm.CUSTOM.equals(algorithm)) {
EncryptionMethod method = initializeEncryptionMethodWithoutEvent(algorithm); EncryptionMethod method = initializeEncryptionMethodWithoutEvent(algorithm);
if (method != null && method.comparePassword(hash, password, salt, playerName)) { if (method != null && method.comparePassword(password, encryptedPassword, playerName)) {
hashPasswordForNewAlgorithm(password, playerName); hashPasswordForNewAlgorithm(password, playerName);
return true; return true;
} }
@ -75,8 +78,8 @@ public class PasswordSecurity {
} }
/** /**
* Get the encryption method from the given {@link HashAlgorithm} value and emits a * Get the encryption method from the given {@link HashAlgorithm} value and emit a
* {@link PasswordEncryptionEvent}. The encryption method from the event is returned, * {@link PasswordEncryptionEvent}. The encryption method from the event is then returned,
* which may have been changed by an external listener. * which may have been changed by an external listener.
* *
* @param algorithm The algorithm to retrieve the encryption method for * @param algorithm The algorithm to retrieve the encryption method for
@ -110,14 +113,10 @@ public class PasswordSecurity {
private void hashPasswordForNewAlgorithm(String password, String playerName) { private void hashPasswordForNewAlgorithm(String password, String playerName) {
PlayerAuth auth = dataSource.getAuth(playerName); PlayerAuth auth = dataSource.getAuth(playerName);
if (auth != null) { if (auth != null) {
HashResult hashResult = initializeEncryptionMethod(algorithm, playerName) EncryptedPassword encryptedPassword = initializeEncryptionMethod(algorithm, playerName)
.computeHash(password, playerName); .computeHash(password, playerName);
auth.setPassword(encryptedPassword);
// TODO #358: updatePassword() should just take the HashResult..., or at least hash & salt. Idem for setHash
auth.setSalt(hashResult.getSalt());
auth.setHash(hashResult.getHash());
dataSource.updatePassword(auth); dataSource.updatePassword(auth);
dataSource.updateSalt(auth);
} }
} }

View File

@ -520,14 +520,14 @@ public class BCRYPT implements EncryptionMethod {
} }
@Override @Override
public HashResult computeHash(String password, String name) { public EncryptedPassword computeHash(String password, String name) {
String salt = generateSalt(); String salt = generateSalt();
return new HashResult(hashpw(password, salt), null); return new EncryptedPassword(hashpw(password, salt), null);
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String name) { public boolean comparePassword(String password, EncryptedPassword hash, String name) {
return checkpw(password, hash); return checkpw(password, hash.getHash());
} }
@Override @Override

View File

@ -15,11 +15,13 @@ public class BCRYPT2Y extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) { public boolean comparePassword(String password, EncryptedPassword encrypted, String unusedName) {
String hash = encrypted.getHash();
if (hash.length() != 60) { if (hash.length() != 60) {
return false; return false;
} }
// The salt is the first 29 characters of the hash // The salt is the first 29 characters of the hash
String salt = hash.substring(0, 29); String salt = hash.substring(0, 29);
return hash.equals(computeHash(password, salt, null)); return hash.equals(computeHash(password, salt, null));
} }

View File

@ -28,11 +28,11 @@ public class CRAZYCRYPT1 extends UsernameSaltMethod {
} }
@Override @Override
public HashResult computeHash(String password, String name) { public EncryptedPassword computeHash(String password, String name) {
final String text = "ÜÄaeut//&/=I " + password + "7421€547" + name + "__+IÄIH§%NK " + password; final String text = "ÜÄaeut//&/=I " + password + "7421€547" + name + "__+IÄIH§%NK " + password;
final MessageDigest md = HashUtils.getDigest(MessageDigestAlgorithm.SHA512); final MessageDigest md = HashUtils.getDigest(MessageDigestAlgorithm.SHA512);
md.update(text.getBytes(charset), 0, text.length()); md.update(text.getBytes(charset), 0, text.length());
return new HashResult(byteArrayToHexString(md.digest())); return new EncryptedPassword(byteArrayToHexString(md.digest()));
} }
} }

View File

@ -20,8 +20,8 @@ public class CryptPBKDF2 extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String unusedName) {
String[] line = hash.split("\\$"); String[] line = encryptedPassword.getHash().split("\\$");
String salt = line[2]; String salt = line[2];
String derivedKey = line[3]; String derivedKey = line[3];
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000, derivedKey.getBytes()); PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 10000, derivedKey.getBytes());

View File

@ -19,8 +19,8 @@ public class CryptPBKDF2Django extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String unusedName) {
String[] line = hash.split("\\$"); String[] line = encryptedPassword.getHash().split("\\$");
String salt = line[2]; String salt = line[2];
byte[] derivedKey = DatatypeConverter.parseBase64Binary(line[3]); byte[] derivedKey = DatatypeConverter.parseBase64Binary(line[3]);
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000, derivedKey); PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA256", "ASCII", salt.getBytes(), 15000, derivedKey);

View File

@ -3,7 +3,7 @@ package fr.xephi.authme.security.crypts;
/** /**
* The result of a hash computation. See {@link #salt} for details. * The result of a hash computation. See {@link #salt} for details.
*/ */
public class HashResult { public class EncryptedPassword {
/** The generated hash. */ /** The generated hash. */
private final String hash; private final String hash;
@ -23,7 +23,7 @@ public class HashResult {
* @param hash The computed hash * @param hash The computed hash
* @param salt The generated salt * @param salt The generated salt
*/ */
public HashResult(String hash, String salt) { public EncryptedPassword(String hash, String salt) {
this.hash = hash; this.hash = hash;
this.salt = salt; this.salt = salt;
} }
@ -33,7 +33,7 @@ public class HashResult {
* *
* @param hash The computed hash * @param hash The computed hash
*/ */
public HashResult(String hash) { public EncryptedPassword(String hash) {
this(hash, null); this(hash, null);
} }

View File

@ -12,9 +12,9 @@ public interface EncryptionMethod {
* @param name The name of the player (sometimes required to generate a salt with) * @param name The name of the player (sometimes required to generate a salt with)
* *
* @return The hash result for the password. * @return The hash result for the password.
* @see HashResult * @see EncryptedPassword
*/ */
HashResult computeHash(String password, String name); EncryptedPassword 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.
@ -31,14 +31,13 @@ public interface EncryptionMethod {
/** /**
* Check whether the given hash matches the clear-text password. * Check whether the given hash matches the clear-text password.
* *
* @param hash The hash to verify * @param password The clear-text password to verify
* @param password The clear-text password to verify the hash against * @param encryptedPassword The hash to check the password against
* @param salt The salt if it is stored separately (null otherwise) * @param name The player name to do the check for (sometimes required for generating the salt)
* @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
*/ */
boolean comparePassword(String hash, String password, String salt, String name); boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name);
/** /**
* Generate a new salt to hash a password with. * Generate a new salt to hash a password with.
@ -49,7 +48,7 @@ public interface EncryptionMethod {
/** /**
* Return whether the encryption method requires the salt to be stored separately and * Return whether the encryption method requires the salt to be stored separately and
* passed again to {@link #comparePassword(String, String, String, String)}. Note that * passed again to {@link #comparePassword(String, EncryptedPassword, String)}. Note that
* an encryption method returning {@code false} does not imply that it uses no salt; it * 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. * may be embedded into the hash or it may use the username as salt.
* *

View File

@ -20,13 +20,13 @@ public abstract class HexSaltedMethod implements EncryptionMethod {
public abstract String computeHash(String password, String salt, String name); public abstract String computeHash(String password, String salt, String name);
@Override @Override
public HashResult computeHash(String password, String name) { public EncryptedPassword computeHash(String password, String name) {
String salt = generateSalt(); String salt = generateSalt();
return new HashResult(computeHash(password, salt, null)); return new EncryptedPassword(computeHash(password, salt, null));
} }
@Override @Override
public abstract boolean comparePassword(String hash, String password, String salt, String name); public abstract boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name);
@Override @Override
public String generateSalt() { public String generateSalt() {

View File

@ -13,7 +13,8 @@ public class JOOMLA extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String unusedSalt, String unusedName) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String unusedName) {
String hash = encryptedPassword.getHash();
String[] hashParts = hash.split(":"); String[] hashParts = hash.split(":");
return hashParts.length == 2 && hash.equals(computeHash(password, hashParts[1], null)); return hashParts.length == 2 && hash.equals(computeHash(password, hashParts[1], null));
} }

View File

@ -10,7 +10,8 @@ public class MD5VB extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String name) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
String hash = encryptedPassword.getHash();
String[] line = hash.split("\\$"); String[] line = hash.split("\\$");
return line.length == 4 && hash.equals(computeHash(password, line[2], name)); return line.length == 4 && hash.equals(computeHash(password, line[2], name));
} }

View File

@ -144,8 +144,8 @@ public class PHPBB extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String name) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
return phpbb_check_hash(password, hash); return phpbb_check_hash(password, encryptedPassword.getHash());
} }
@Override @Override

View File

@ -14,7 +14,8 @@ public class SHA256 extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String playerName) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) {
String hash = encryptedPassword.getHash();
String[] line = hash.split("\\$"); String[] line = hash.split("\\$");
return line.length == 4 && hash.equals(computeHash(password, line[2], "")); return line.length == 4 && hash.equals(computeHash(password, line[2], ""));
} }

View File

@ -4,8 +4,8 @@ import fr.xephi.authme.security.HashUtils;
public class SMF extends UsernameSaltMethod { public class SMF extends UsernameSaltMethod {
public HashResult computeHash(String password, String name) { public EncryptedPassword computeHash(String password, String name) {
return new HashResult(HashUtils.sha1(name.toLowerCase() + password)); return new EncryptedPassword(HashUtils.sha1(name.toLowerCase() + password));
} }
} }

View File

@ -12,14 +12,14 @@ public abstract class SeparateSaltMethod implements EncryptionMethod {
public abstract String generateSalt(); public abstract String generateSalt();
@Override @Override
public HashResult computeHash(String password, String name) { public EncryptedPassword computeHash(String password, String name) {
String salt = generateSalt(); String salt = generateSalt();
return new HashResult(computeHash(password, salt, name), salt); return new EncryptedPassword(computeHash(password, salt, name), salt);
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String name) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
return hash.equals(computeHash(password, salt, null)); return encryptedPassword.getHash().equals(computeHash(password, encryptedPassword.getSalt(), null));
} }
@Override @Override

View File

@ -15,8 +15,8 @@ public abstract class UnsaltedMethod implements EncryptionMethod {
public abstract String computeHash(String password); public abstract String computeHash(String password);
@Override @Override
public HashResult computeHash(String password, String name) { public EncryptedPassword computeHash(String password, String name) {
return new HashResult(computeHash(password)); return new EncryptedPassword(computeHash(password));
} }
@Override @Override
@ -25,8 +25,8 @@ public abstract class UnsaltedMethod implements EncryptionMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String name) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
return hash.equals(computeHash(password)); return encryptedPassword.getHash().equals(computeHash(password));
} }
@Override @Override

View File

@ -7,18 +7,18 @@ import fr.xephi.authme.security.crypts.description.Usage;
/** /**
* Common supertype of encryption methods that use a player's username * Common supertype of encryption methods that use a player's username
* (or something based on it) as salt. * (or something based on it) as embedded salt.
*/ */
@Recommendation(Usage.DO_NOT_USE) @Recommendation(Usage.DO_NOT_USE)
@HasSalt(SaltType.USERNAME) @HasSalt(SaltType.USERNAME)
public abstract class UsernameSaltMethod implements EncryptionMethod { public abstract class UsernameSaltMethod implements EncryptionMethod {
@Override @Override
public abstract HashResult computeHash(String password, String name); public abstract EncryptedPassword computeHash(String password, String name);
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String name) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
return hash.equals(computeHash(password, name).getHash()); return encryptedPassword.getHash().equals(computeHash(password, name).getHash());
} }
@Override @Override

View File

@ -12,8 +12,8 @@ public class WBB4 extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String playerName) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) {
return BCRYPT.checkpw(password, hash, 2); return BCRYPT.checkpw(password, encryptedPassword.getHash(), 2);
} }
@Override @Override

View File

@ -117,7 +117,8 @@ public class WORDPRESS extends UnsaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String name) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String name) {
String hash = encryptedPassword.getHash();
String comparedHash = crypt(password, hash); String comparedHash = crypt(password, hash);
return comparedHash.equals(hash); return comparedHash.equals(hash);
} }

View File

@ -23,7 +23,8 @@ public class XAUTH extends HexSaltedMethod {
} }
@Override @Override
public boolean comparePassword(String hash, String password, String salt, String playerName) { public boolean comparePassword(String password, EncryptedPassword encryptedPassword, String playerName) {
String hash = encryptedPassword.getHash();
int saltPos = (password.length() >= hash.length() ? hash.length() - 1 : password.length()); int saltPos = (password.length() >= hash.length() ? hash.length() - 1 : password.length());
String saltFromHash = hash.substring(saltPos, saltPos + 12); String saltFromHash = hash.substring(saltPos, saltPos + 12);
return hash.equals(computeHash(password, saltFromHash, null)); return hash.equals(computeHash(password, saltFromHash, null));

View File

@ -9,7 +9,7 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages; import fr.xephi.authme.output.Messages;
import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashResult; import fr.xephi.authme.security.crypts.EncryptedPassword;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -34,22 +34,21 @@ public class ChangePasswordTask implements Runnable {
final String name = player.getName().toLowerCase(); final String name = player.getName().toLowerCase();
PlayerAuth auth = PlayerCache.getInstance().getAuth(name); PlayerAuth auth = PlayerCache.getInstance().getAuth(name);
if (passwordSecurity.comparePassword(oldPassword, auth.getHash(), auth.getSalt(), player.getName())) { if (passwordSecurity.comparePassword(oldPassword, auth.getPassword(), player.getName())) {
HashResult hashResult = passwordSecurity.computeHash(newPassword, name); EncryptedPassword encryptedPassword = passwordSecurity.computeHash(newPassword, name);
auth.setHash(hashResult.getHash()); auth.setPassword(encryptedPassword);
auth.setSalt(hashResult.getSalt());
if (!plugin.getDataSource().updatePassword(auth)) { if (!plugin.getDataSource().updatePassword(auth)) {
m.send(player, MessageKey.ERROR); m.send(player, MessageKey.ERROR);
return; return;
} }
plugin.getDataSource().updateSalt(auth);
PlayerCache.getInstance().updatePlayer(auth); PlayerCache.getInstance().updatePlayer(auth);
m.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS); m.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
ConsoleLogger.info(player.getName() + " changed his password"); ConsoleLogger.info(player.getName() + " changed his password");
if (Settings.bungee) { if (Settings.bungee) {
final String hash = auth.getHash(); final String hash = encryptedPassword.getHash();
final String salt = auth.getSalt(); final String salt = encryptedPassword.getSalt();
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable(){ plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable(){
@Override @Override

View File

@ -1,7 +1,7 @@
package fr.xephi.authme.security; package fr.xephi.authme.security;
import fr.xephi.authme.security.crypts.EncryptedPassword;
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.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.WrapperMock; import fr.xephi.authme.util.WrapperMock;
@ -49,11 +49,11 @@ public class HashAlgorithmIntegrationTest {
for (HashAlgorithm algorithm : HashAlgorithm.values()) { for (HashAlgorithm algorithm : HashAlgorithm.values()) {
if (!HashAlgorithm.CUSTOM.equals(algorithm)) { if (!HashAlgorithm.CUSTOM.equals(algorithm)) {
EncryptionMethod method = algorithm.getClazz().newInstance(); EncryptionMethod method = algorithm.getClazz().newInstance();
HashResult hashResult = method.computeHash("pwd", "name"); EncryptedPassword encryptedPassword = method.computeHash("pwd", "name");
assertThat("Salt should not be null if method.hasSeparateSalt(), and vice versa. Method: '" assertThat("Salt should not be null if method.hasSeparateSalt(), and vice versa. Method: '"
+ method + "'", StringUtils.isEmpty(hashResult.getSalt()), equalTo(!method.hasSeparateSalt())); + method + "'", StringUtils.isEmpty(encryptedPassword.getSalt()), equalTo(!method.hasSeparateSalt()));
assertThat("Hash should not be empty for method '" + method + "'", assertThat("Hash should not be empty for method '" + method + "'",
StringUtils.isEmpty(hashResult.getHash()), equalTo(false)); StringUtils.isEmpty(encryptedPassword.getHash()), equalTo(false));
} }
} }
} }

View File

@ -36,47 +36,42 @@ public abstract class AbstractEncryptionMethodTest {
/** The encryption method to test. */ /** The encryption method to test. */
private EncryptionMethod method; private EncryptionMethod method;
/** Map with the hashes against which the entries in GIVEN_PASSWORDS are tested. */ /** Map with the hashes against which the entries in GIVEN_PASSWORDS are tested. */
private Map<String, String> hashes; private Map<String, EncryptedPassword> hashes;
/** The accompanying salts for the hashes in {@link #hashes} if necessary. Can be empty otherwise. */
private Map<String, String> salts;
/** /**
* Create a new test for the given encryption method. * Create a new test for the given encryption method.
* *
* @param method The encryption method to test * @param method The encryption method to test
* @param hash0 The pre-generated hash for the first {@link #GIVEN_PASSWORDS} * @param computedHashes The pre-generated hashes for the elements in {@link #GIVEN_PASSWORDS}
* @param hash1 The pre-generated hash for the second {@link #GIVEN_PASSWORDS}
* @param hash2 The pre-generated hash for the third {@link #GIVEN_PASSWORDS}
* @param hash3 The pre-generated hash for the fourth {@link #GIVEN_PASSWORDS}
*/ */
public AbstractEncryptionMethodTest(EncryptionMethod method, String hash0, String hash1, public AbstractEncryptionMethodTest(EncryptionMethod method, String... computedHashes) {
String hash2, String hash3) { if (method.hasSeparateSalt()) {
// TODO #358: Throw if method.hasSeparateSalt() is true throw new UnsupportedOperationException("Test must be initialized with EncryptedPassword objects if "
+ "the salt is stored separately. Use the other constructor");
} else if (computedHashes.length != GIVEN_PASSWORDS.length) {
throw new UnsupportedOperationException("Expected " + GIVEN_PASSWORDS.length + " hashes");
}
this.method = method; this.method = method;
hashes = new HashMap<>(); hashes = new HashMap<>();
hashes.put(GIVEN_PASSWORDS[0], hash0); for (int i = 0; i < GIVEN_PASSWORDS.length; ++i) {
hashes.put(GIVEN_PASSWORDS[1], hash1); hashes.put(GIVEN_PASSWORDS[i], new EncryptedPassword(computedHashes[i]));
hashes.put(GIVEN_PASSWORDS[2], hash2); }
hashes.put(GIVEN_PASSWORDS[3], hash3);
salts = new HashMap<>();
} }
public AbstractEncryptionMethodTest(EncryptionMethod method, HashResult result0, HashResult result1, public AbstractEncryptionMethodTest(EncryptionMethod method, EncryptedPassword result0, EncryptedPassword result1,
HashResult result2, HashResult result3) { EncryptedPassword result2, EncryptedPassword result3) {
// TODO #358: Throw if method.hasSeparateSalt() is false if (!method.hasSeparateSalt()) {
throw new UnsupportedOperationException("Salt is not stored separately, so test should be initialized"
+ " with the password hashes only. Use the other constructor");
}
this.method = method; this.method = method;
hashes = new HashMap<>(); hashes = new HashMap<>();
hashes.put(GIVEN_PASSWORDS[0], result0.getHash()); hashes.put(GIVEN_PASSWORDS[0], result0);
hashes.put(GIVEN_PASSWORDS[1], result1.getHash()); hashes.put(GIVEN_PASSWORDS[1], result1);
hashes.put(GIVEN_PASSWORDS[2], result2.getHash()); hashes.put(GIVEN_PASSWORDS[2], result2);
hashes.put(GIVEN_PASSWORDS[3], result3.getHash()); hashes.put(GIVEN_PASSWORDS[3], result3);
salts = new HashMap<>();
salts.put(GIVEN_PASSWORDS[0], result0.getSalt());
salts.put(GIVEN_PASSWORDS[1], result1.getSalt());
salts.put(GIVEN_PASSWORDS[2], result2.getSalt());
salts.put(GIVEN_PASSWORDS[3], result3.getSalt());
} }
@Test @Test
@ -108,6 +103,7 @@ public abstract class AbstractEncryptionMethodTest {
for (String password : internalPasswords) { for (String password : internalPasswords) {
final String salt = method.generateSalt(); final String salt = method.generateSalt();
final String hash = method.computeHash(password, salt, USERNAME); final String hash = method.computeHash(password, salt, USERNAME);
EncryptedPassword encryptedPassword = new EncryptedPassword(hash, salt);
// 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
if (testHashEqualityForSameSalt()) { if (testHashEqualityForSameSalt()) {
@ -116,22 +112,20 @@ public abstract class AbstractEncryptionMethodTest {
} }
assertTrue("Generated hash for '" + password + "' should match password (hash = '" + hash + "')", assertTrue("Generated hash for '" + password + "' should match password (hash = '" + hash + "')",
method.comparePassword(hash, password, salt, USERNAME)); method.comparePassword(password, encryptedPassword, 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 + "'",
method.comparePassword(hash, password.toLowerCase(), salt, USERNAME)); method.comparePassword(password.toLowerCase(), encryptedPassword, 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 + "'",
method.comparePassword(hash, password.toUpperCase(), salt, USERNAME)); method.comparePassword(password.toUpperCase(), encryptedPassword, USERNAME));
} }
} }
} }
private boolean doesGivenHashMatch(String password, EncryptionMethod method) { private boolean doesGivenHashMatch(String password, EncryptionMethod method) {
String hash = hashes.get(password); return method.comparePassword(password, hashes.get(password), USERNAME);
String salt = salts.get(password);
return method.comparePassword(hash, password, salt, USERNAME);
} }
// @org.junit.Test public void a() { AbstractEncryptionMethodTest.generateTest(); } // @org.junit.Test public void a() { AbstractEncryptionMethodTest.generateTest(); }
@ -150,9 +144,9 @@ public abstract class AbstractEncryptionMethodTest {
} }
if (method.hasSeparateSalt()) { if (method.hasSeparateSalt()) {
HashResult hashResult = method.computeHash(password, USERNAME); EncryptedPassword encryptedPassword = method.computeHash(password, USERNAME);
System.out.println(String.format("\t\tnew HashResult(\"%s\", \"%s\")%s// %s", System.out.println(String.format("\t\tnew EncryptedPassword(\"%s\", \"%s\")%s// %s",
hashResult.getHash(), hashResult.getSalt(), delim, password)); encryptedPassword.getHash(), encryptedPassword.getSalt(), delim, password));
} else { } else {
System.out.println("\t\t\"" + method.computeHash(password, USERNAME).getHash() System.out.println("\t\t\"" + method.computeHash(password, USERNAME).getHash()
+ "\"" + delim + "// " + password); + "\"" + delim + "// " + password);

View File

@ -7,10 +7,10 @@ public class IPB3Test extends AbstractEncryptionMethodTest {
public IPB3Test() { public IPB3Test() {
super(new IPB3(), super(new IPB3(),
new HashResult("f8ecea1ce42b5babef369ff7692dbe3f", "1715b"), //password new EncryptedPassword("f8ecea1ce42b5babef369ff7692dbe3f", "1715b"), //password
new HashResult("40a93731a931352e0619cdf09b975040", "ba91c"), //PassWord1 new EncryptedPassword("40a93731a931352e0619cdf09b975040", "ba91c"), //PassWord1
new HashResult("a77ca982373946d5800430bd2947ba11", "a7725"), //&^%te$t?Pw@_ new EncryptedPassword("a77ca982373946d5800430bd2947ba11", "a7725"), //&^%te$t?Pw@_
new HashResult("383d7b9e2b707d6e894ec7b30e3032c3", "fa9fd")); //âË_3(íù* new EncryptedPassword("383d7b9e2b707d6e894ec7b30e3032c3", "fa9fd")); //âË_3(íù*
} }
} }

View File

@ -7,10 +7,10 @@ public class MYBBTest extends AbstractEncryptionMethodTest {
public MYBBTest() { public MYBBTest() {
super(new MYBB(), super(new MYBB(),
new HashResult("57c7a16d860833db5030738f5a465d2b", "acdc14e6"), //password new EncryptedPassword("57c7a16d860833db5030738f5a465d2b", "acdc14e6"), //password
new HashResult("08fbdf721f2c42d9780b7d66df0ba830", "792fd7fb"), //PassWord1 new EncryptedPassword("08fbdf721f2c42d9780b7d66df0ba830", "792fd7fb"), //PassWord1
new HashResult("d602f38fb59ad9e185d5604f5d4ddb36", "4b5534a4"), //&^%te$t?Pw@_ new EncryptedPassword("d602f38fb59ad9e185d5604f5d4ddb36", "4b5534a4"), //&^%te$t?Pw@_
new HashResult("b3c39410d0ab8ae2a65c257820797fad", "e5a6cb14")); //âË_3(íù* new EncryptedPassword("b3c39410d0ab8ae2a65c257820797fad", "e5a6cb14")); //âË_3(íù*
} }
} }

View File

@ -7,10 +7,10 @@ public class PHPFUSIONTest extends AbstractEncryptionMethodTest {
public PHPFUSIONTest() { public PHPFUSIONTest() {
super(new PHPFUSION(), super(new PHPFUSION(),
new HashResult("f7a606c4eb3fcfbc382906476e05b06f21234a77d1a4eacc0f93f503deb69e70", "6cd1c97c55cb"), // password new EncryptedPassword("f7a606c4eb3fcfbc382906476e05b06f21234a77d1a4eacc0f93f503deb69e70", "6cd1c97c55cb"), // password
new HashResult("8a9b7bb706a3347e5f684a7cb905bfb26b9a0d099358064139ab3ed1a66aeb2b", "d6012370b73f"), // PassWord1 new EncryptedPassword("8a9b7bb706a3347e5f684a7cb905bfb26b9a0d099358064139ab3ed1a66aeb2b", "d6012370b73f"), // PassWord1
new HashResult("43f2f23f44c8f89e2dbf06050bc8c77dbcdf71a7b5d28c87ec657d474e63d62d", "f75400a209a4"), // &^%te$t?Pw@_ new EncryptedPassword("43f2f23f44c8f89e2dbf06050bc8c77dbcdf71a7b5d28c87ec657d474e63d62d", "f75400a209a4"), // &^%te$t?Pw@_
new HashResult("4e7f4eb7e3653d7460f1cf590def4153c6fcdf8b8e16fb95538fdf9e54a95245", "d552e0f5b23a")); // âË_3(íù* new EncryptedPassword("4e7f4eb7e3653d7460f1cf590def4153c6fcdf8b8e16fb95538fdf9e54a95245", "d552e0f5b23a")); // âË_3(íù*
} }
} }

View File

@ -17,10 +17,10 @@ public class SALTED2MD5Test extends AbstractEncryptionMethodTest {
public SALTED2MD5Test() { public SALTED2MD5Test() {
super(new SALTED2MD5(), super(new SALTED2MD5(),
new HashResult("9f3d13dc01a6fe61fd669954174399f3", "9b5f5749"), // password new EncryptedPassword("9f3d13dc01a6fe61fd669954174399f3", "9b5f5749"), // password
new HashResult("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"), // PassWord1 new EncryptedPassword("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"), // PassWord1
new HashResult("38dcb83cc68424afe3cda012700c2bb1", "eb2c3394"), // &^%te$t?Pw@_ new EncryptedPassword("38dcb83cc68424afe3cda012700c2bb1", "eb2c3394"), // &^%te$t?Pw@_
new HashResult("ad25606eae5b760c8a2469d65578ac39", "04eee598")); // âË_3(íù*) new EncryptedPassword("ad25606eae5b760c8a2469d65578ac39", "04eee598")); // âË_3(íù*)
} }
} }

View File

@ -7,10 +7,10 @@ public class SALTEDSHA512Test extends AbstractEncryptionMethodTest {
public SALTEDSHA512Test() { public SALTEDSHA512Test() {
super(new SALTEDSHA512(), super(new SALTEDSHA512(),
new HashResult("dea7a37cecf5384ae8e347fd1411efb51364b6ba1b328695de3b354612c1d7010807e8b7051c40f740e498490e1f133e2c2408327d13fbdd68e1b1f6d548e624", "29f8a3c52147f987fee7ba3e0fb311bd"), // password new EncryptedPassword("dea7a37cecf5384ae8e347fd1411efb51364b6ba1b328695de3b354612c1d7010807e8b7051c40f740e498490e1f133e2c2408327d13fbdd68e1b1f6d548e624", "29f8a3c52147f987fee7ba3e0fb311bd"), // password
new HashResult("7c06225aac574d2dc7c81a2ed306637adf025715f52083e05bdab014faaa234e24a97d0e69ea0108dfa77cc9228e58be319ee677e679b5d1ad168d40e50a42f6", "8ea37b85d020b98f60c0fe9b8ec9296c"), // PassWord1 new EncryptedPassword("7c06225aac574d2dc7c81a2ed306637adf025715f52083e05bdab014faaa234e24a97d0e69ea0108dfa77cc9228e58be319ee677e679b5d1ad168d40e50a42f6", "8ea37b85d020b98f60c0fe9b8ec9296c"), // PassWord1
new HashResult("55711adbe03c9616f3505f0d57077fdd528c32243eb6f9840c1a6ff9e553940d6b89790750ebd52ebda63ca793fbe9980d54057af40836820c648750fe22d49c", "9f58079631ef21d32b4710694f1f461b"), // &^%te$t?Pw@_ new EncryptedPassword("55711adbe03c9616f3505f0d57077fdd528c32243eb6f9840c1a6ff9e553940d6b89790750ebd52ebda63ca793fbe9980d54057af40836820c648750fe22d49c", "9f58079631ef21d32b4710694f1f461b"), // &^%te$t?Pw@_
new HashResult("29dc5be8702975ea4563ed3de5b145e2d2f1c37ae661bbe0d3e94d964402cf09d539d65f3b90ff6921ea3d40727f76fb38fb34d1e5c2d62238c4e0203efc372f", "048bb76168265d906f1fd1f81d0616a9")); // âË_3(íù* new EncryptedPassword("29dc5be8702975ea4563ed3de5b145e2d2f1c37ae661bbe0d3e94d964402cf09d539d65f3b90ff6921ea3d40727f76fb38fb34d1e5c2d62238c4e0203efc372f", "048bb76168265d906f1fd1f81d0616a9")); // âË_3(íù*
} }
} }

View File

@ -7,10 +7,10 @@ public class WBB3Test extends AbstractEncryptionMethodTest {
public WBB3Test() { public WBB3Test() {
super(new WBB3(), super(new WBB3(),
new HashResult("8df818ef7d56075ab2744f74b98ad68a375ccac4", "b7415b355492ea60314f259a35733a3092c03e3f"), // password new EncryptedPassword("8df818ef7d56075ab2744f74b98ad68a375ccac4", "b7415b355492ea60314f259a35733a3092c03e3f"), // password
new HashResult("106da5cf5df92cb845e12cf62cbdb5235b6dc693", "6110f19b2b52910dccf592a19c59126873f42e69"), // PassWord1 new EncryptedPassword("106da5cf5df92cb845e12cf62cbdb5235b6dc693", "6110f19b2b52910dccf592a19c59126873f42e69"), // PassWord1
new HashResult("940a9fb7acec0178c6691e8b3c14bd7d789078b1", "f9dd501ff3d1bf74904f9e89649e378429af56e7"), // &^%te$t?Pw@_ new EncryptedPassword("940a9fb7acec0178c6691e8b3c14bd7d789078b1", "f9dd501ff3d1bf74904f9e89649e378429af56e7"), // &^%te$t?Pw@_
new HashResult("0fa12e8d96c9e95f73aa91f3b76f8cdc815ec8a5", "736be8669f6159ddb2d5b47a3e6428cdb8b324de")); // âË_3(íù* new EncryptedPassword("0fa12e8d96c9e95f73aa91f3b76f8cdc815ec8a5", "736be8669f6159ddb2d5b47a3e6428cdb8b324de")); // âË_3(íù*
} }
} }