Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete BCrypt Migration #20

Merged
merged 2 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
/out
*.onetoc2
.gradle/
bin/

# Eclipse m2e generated files
# Eclipse Core
Expand Down
1 change: 0 additions & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
68 changes: 30 additions & 38 deletions src/main/java/client/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
42 changes: 16 additions & 26 deletions src/main/java/net/server/handlers/login/LoginPasswordHandler.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
This file is part of the OdinMS Maple Story Server
o This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <[email protected]>
Matthias Butz <[email protected]>
Jan Christian Meyer <[email protected]>
Expand All @@ -21,6 +21,15 @@
*/
package net.server.handlers.login;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Calendar;

import client.Client;
import client.DefaultDates;
import config.YamlConfig;
Expand All @@ -29,22 +38,9 @@
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;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Calendar;
import utils.Crypto;

public final class LoginPasswordHandler implements PacketHandler {

Expand All @@ -53,12 +49,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();
Expand All @@ -79,9 +69,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();
Expand All @@ -90,7 +80,7 @@ public final void handlePacket(InPacket p, Client c) {
rs.next();
c.setAccID(rs.getInt(1));
}
} catch (SQLException | NoSuchAlgorithmException | UnsupportedEncodingException e) {
} catch (SQLException e) {
c.setAccID(-1);
e.printStackTrace();
} finally {
Expand All @@ -101,7 +91,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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -968,4 +968,4 @@ public static boolean checkpw(byte[] plaintext, String hashed) {
}
return ret == 0;
}
}
}