diff --git a/.gitignore b/.gitignore index 599d63c44c0..3fd2716c6bb 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ /out *.onetoc2 .gradle/ +bin/ # Eclipse m2e generated files # Eclipse Core diff --git a/config.yaml b/config.yaml index 8e4a6a9e252..0977309b4bb 100644 --- a/config.yaml +++ b/config.yaml @@ -170,7 +170,6 @@ server: UPDATE_INTERVAL: 777 #Dictates the frequency on which the "centralized server time" is updated. AUTOMATIC_REGISTER: true #Automatically register players when they login with a nonexistent username. - BCRYPT_MIGRATION: true #Performs a migration from old SHA-1 and SHA-512 password to bcrypt. COLLECTIVE_CHARSLOT: false #Available character slots are contabilized globally rather than per world server. DETERRED_MULTICLIENT: false #Enables detection of multi-client and suspicious remote IP on the login system. #Besides blocking logging in with several client sessions on the same machine, this also blocks suspicious login attempts for players that tries to login on an account using several diferent remote addresses. diff --git a/src/main/java/client/Client.java b/src/main/java/client/Client.java index 2a94aac43e8..46acab411f5 100644 --- a/src/main/java/client/Client.java +++ b/src/main/java/client/Client.java @@ -21,6 +21,34 @@ */ package client; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import javax.script.ScriptEngine; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import client.inventory.InventoryType; import config.YamlConfig; import constants.game.GameConstants; @@ -38,7 +66,6 @@ import net.packet.logging.MonitoredChrLogger; import net.server.Server; import net.server.channel.Channel; -import net.server.coordinator.login.LoginBypassCoordinator; import net.server.coordinator.session.Hwid; import net.server.coordinator.session.SessionCoordinator; import net.server.coordinator.session.SessionCoordinator.AntiMulticlientResult; @@ -50,8 +77,6 @@ import net.server.world.PartyCharacter; import net.server.world.PartyOperation; import net.server.world.World; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import scripting.AbstractPlayerInteraction; import scripting.event.EventInstanceManager; import scripting.event.EventManager; @@ -66,39 +91,9 @@ import server.maps.FieldLimit; import server.maps.MapleMap; import server.maps.MiniDungeonInfo; -import tools.BCrypt; import tools.HexTool; import tools.PacketCreator; - -import javax.script.ScriptEngine; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Semaphore; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import static java.util.concurrent.TimeUnit.SECONDS; +import utils.Crypto; public class Client extends ChannelInboundHandlerAdapter { private static final Logger log = LoggerFactory.getLogger(Client.class); @@ -509,11 +504,8 @@ public int login(String login, String pwd, Hwid hwid) { if (getLoginState() > LOGIN_NOTLOGGEDIN) { // already loggedin loggedIn = false; loginok = 7; - } else if (passhash.charAt(0) == '$' && passhash.charAt(1) == '2' && BCrypt.checkpw(pwd, passhash)) { + } else if (Crypto.checkpw(pwd, passhash)) { loginok = (tos == 0) ? 23 : 0; - } else if (pwd.equals(passhash) || checkHash(passhash, "SHA-1", pwd) || checkHash(passhash, "SHA-512", pwd)) { - // thanks GabrielSin for detecting some no-bcrypt inconsistencies here - loginok = (tos == 0) ? (!YamlConfig.config.server.BCRYPT_MIGRATION ? 23 : -23) : (!YamlConfig.config.server.BCRYPT_MIGRATION ? 0 : -10); // migrate to bcrypt } else { loggedIn = false; loginok = 4; diff --git a/src/main/java/net/server/handlers/login/LoginPasswordHandler.java b/src/main/java/net/server/handlers/login/LoginPasswordHandler.java index 6a974b828b5..1f1e6c7718b 100644 --- a/src/main/java/net/server/handlers/login/LoginPasswordHandler.java +++ b/src/main/java/net/server/handlers/login/LoginPasswordHandler.java @@ -21,21 +21,7 @@ */ package net.server.handlers.login; -import client.Client; -import client.DefaultDates; -import config.YamlConfig; -import database.DatabaseConnection; -import net.PacketHandler; -import net.packet.InPacket; -import net.server.Server; -import net.server.coordinator.session.Hwid; -import tools.BCrypt; -import tools.HexTool; -import tools.PacketCreator; - import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.sql.Connection; import java.sql.Date; @@ -46,6 +32,18 @@ import java.sql.Timestamp; import java.util.Calendar; +import client.Client; +import client.DefaultDates; +import config.YamlConfig; +import database.DatabaseConnection; +import net.PacketHandler; +import net.packet.InPacket; +import net.server.Server; +import net.server.coordinator.session.Hwid; +import tools.HexTool; +import tools.PacketCreator; +import utils.Crypto; + public final class LoginPasswordHandler implements PacketHandler { @Override @@ -53,12 +51,6 @@ public boolean validateState(Client c) { return !c.isLoggedIn(); } - private static String hashpwSHA512(String pwd) throws NoSuchAlgorithmException, UnsupportedEncodingException { - MessageDigest digester = MessageDigest.getInstance("SHA-512"); - digester.update(pwd.getBytes(StandardCharsets.UTF_8), 0, pwd.length()); - return HexTool.toHexString(digester.digest()).replace(" ", "").toLowerCase(); - } - @Override public final void handlePacket(InPacket p, Client c) { String remoteHost = c.getRemoteAddress(); @@ -79,9 +71,9 @@ public final void handlePacket(InPacket p, Client c) { if (YamlConfig.config.server.AUTOMATIC_REGISTER && loginok == 5) { try (Connection con = DatabaseConnection.getConnection(); - PreparedStatement ps = con.prepareStatement("INSERT INTO accounts (name, password, birthday, tempban) VALUES (?, ?, ?, ?);", Statement.RETURN_GENERATED_KEYS)) { //Jayd: Added birthday, tempban - ps.setString(1, login); - ps.setString(2, YamlConfig.config.server.BCRYPT_MIGRATION ? BCrypt.hashpw(pwd, BCrypt.gensalt(12)) : hashpwSHA512(pwd)); + PreparedStatement ps = con.prepareStatement("INSERT INTO accounts (name, password, birthday, tempban) VALUES (?, ?, ?, ?);", Statement.RETURN_GENERATED_KEYS)) { + ps.setString(1, login); + ps.setString(2, Crypto.hashpw(pwd, Crypto.gensalt(12))); ps.setDate(3, Date.valueOf(DefaultDates.getBirthday())); ps.setTimestamp(4, Timestamp.valueOf(DefaultDates.getTempban())); ps.executeUpdate(); @@ -101,7 +93,7 @@ public final void handlePacket(InPacket p, Client c) { if (YamlConfig.config.server.BCRYPT_MIGRATION && (loginok <= -10)) { // -10 means migration to bcrypt, -23 means TOS wasn't accepted try (Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("UPDATE accounts SET password = ? WHERE name = ?;")) { - ps.setString(1, BCrypt.hashpw(pwd, BCrypt.gensalt(12))); + ps.setString(1, Crypto.hashpw(pwd, Crypto.gensalt(12))); ps.setString(2, login); ps.executeUpdate(); } catch (SQLException e) { diff --git a/src/main/java/tools/BCrypt.java b/src/main/java/utils/Crypto.java similarity index 99% rename from src/main/java/tools/BCrypt.java rename to src/main/java/utils/Crypto.java index b238251d52a..c92c984b41b 100644 --- a/src/main/java/tools/BCrypt.java +++ b/src/main/java/utils/Crypto.java @@ -11,7 +11,7 @@ // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -package tools; +package utils; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; @@ -60,7 +60,7 @@ * @author Damien Miller * @version 0.4 */ -public class BCrypt { +public class Crypto { // BCrypt parameters private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10; @@ -770,7 +770,7 @@ public static String hashpw(String password, String salt) { * @return the hashed password */ public static String hashpw(byte[] passwordb, String salt) { - BCrypt B; + Crypto B; String real_salt; byte[] saltb, hashed; char minor = (char) 0; @@ -806,7 +806,7 @@ public static String hashpw(byte[] passwordb, String salt) { passwordb = Arrays.copyOf(passwordb, passwordb.length + 1); } - B = new BCrypt(); + B = new Crypto(); hashed = B.crypt_raw(passwordb, saltb, rounds, minor == 'x', // true for sign extension bug ('2x') minor == 'a' ? 0x10000 : 0, // safety factor for '2a' @@ -968,4 +968,4 @@ public static boolean checkpw(byte[] plaintext, String hashed) { } return ret == 0; } -} \ No newline at end of file +}