add encryption and enforce authentication

This commit is contained in:
Sen 2025-05-18 17:39:22 +02:00
parent 2ea3267e3a
commit 8d4b4b3619
16 changed files with 452 additions and 73 deletions

View file

@ -6,6 +6,9 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
@ -67,6 +70,7 @@ import common.packet.SPacketTimeUpdate;
import common.packet.SPacketWorld;
import common.potion.PotionEffect;
import common.util.BlockPos;
import common.util.EncryptUtil;
import common.util.ExtMath;
import common.util.LazyLoadBase;
import common.util.PortalType;
@ -118,6 +122,7 @@ public final class Server implements IThreadListener {
private final List<Dimension> unload = Lists.<Dimension>newArrayList();
private final Map<String, Position> warps = Maps.<String, Position>newTreeMap();
private final CommandEnvironment scriptEnv = new CommandEnvironment(this);
private final KeyPair keyPair;
private final boolean debug;
private WorldServer space;
@ -238,6 +243,7 @@ public final class Server implements IThreadListener {
}
}
}, "viewDistance");
this.keyPair = EncryptUtil.generateKeyPair();
}
public CommandEnvironment getScriptEnvironment() {
@ -811,24 +817,22 @@ public final class Server implements IThreadListener {
conn.readFromNBT(tag);
if(Config.playerLimit > 0 && this.players.size() >= Config.playerLimit && !conn.isAdmin())
return String.format("Der Server ist voll (%d/%d)!", this.players.size(), Config.playerLimit);
if(/* !connection.isLocalChannel() && */ Config.auth) {
if(conn.getPassword() == null) {
if(!Config.register)
return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)";
if(loginPass.length() == 0)
return "Ein neues Passwort ist erforderlich um diesen Server zu betreten (mindestens " + Config.minPassLength + " Zeichen)";
if(loginPass.length() < Config.minPassLength)
return "Passwort ist zu kurz, mindestens " + Config.minPassLength + " Zeichen";
conn.setPassword(loginPass);
Log.JNI.info(loginUser + " registrierte sich mit Passwort");
}
else if(!conn.getPassword().equals(loginPass)) {
return "Falsches Passwort";
}
else {
Log.JNI.info(loginUser + " loggte sich mit Passwort ein");
}
}
if(conn.getPassword() == null) {
if(!Config.register)
return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)";
if(loginPass.length() == 0)
return "Ein neues Passwort ist erforderlich um diesen Server zu betreten (mindestens " + Config.minPassLength + " Zeichen)";
if(loginPass.length() < Config.minPassLength)
return "Passwort ist zu kurz, mindestens " + Config.minPassLength + " Zeichen";
conn.setPassword(loginPass);
Log.JNI.info(loginUser + " registrierte sich mit Passwort");
}
else if(!conn.getPassword().equals(loginPass)) {
return "Falsches Passwort";
}
else {
Log.JNI.info(loginUser + " loggte sich mit Passwort ein");
}
if(Config.compression >= 0) {
connection.sendPacket(new RPacketEnableCompression(Config.compression), new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
@ -1300,4 +1304,12 @@ public final class Server implements IThreadListener {
public void logConsole(String message) {
Log.CONSOLE.info(message);
}
public PublicKey getPublicKey() {
return this.keyPair.getPublic();
}
public PrivateKey getPrivateKey() {
return this.keyPair.getPrivate();
}
}

View file

@ -1,5 +1,11 @@
package server.network;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.SecretKey;
import common.color.TextColor;
import common.init.Config;
import common.log.Log;
@ -7,23 +13,29 @@ import common.network.ILoginHandler;
import common.network.IPlayer;
import common.network.NetConnection;
import common.network.NetHandler;
import common.packet.LPacketLogin;
import common.packet.LPacketPasswordResponse;
import common.packet.LPacketStartEncrypt;
import common.packet.RPacketDisconnect;
import common.packet.RPacketRequestEncrypt;
import server.Server;
public class LoginHandler extends NetHandler implements ILoginHandler
{
private static enum LoginState {
PASSWORD, READY_TO_ACCEPT, ACCEPTED;
INIT, ENCRYPT, PASSWORD, AUTHENTICATED, ACCEPTED;
}
private static final SecureRandom TOKEN_RNG = new SecureRandom();
private final Server server;
public final NetConnection netManager;
private LoginState state = LoginState.PASSWORD;
private LoginState state = LoginState.INIT;
private int timer;
private String loginUser;
private String loginPass;
private byte[] loginToken;
public LoginHandler(Server server, NetConnection netManager)
{
@ -58,7 +70,7 @@ public class LoginHandler extends NetHandler implements ILoginHandler
public void update()
{
if(this.state == LoginState.READY_TO_ACCEPT)
if(this.state == LoginState.AUTHENTICATED)
this.tryAcceptPlayer();
// else if (this.currentLoginState == LoginState.DELAY_ACCEPT)
// {
@ -93,15 +105,25 @@ public class LoginHandler extends NetHandler implements ILoginHandler
this.state = LoginState.ACCEPTED;
}
// public void processLoginStart(LPacketLoginStart packetIn)
// {
// if(this.state != LoginState.HELLO)
// throw new IllegalStateException("Unerwartetes Start-Paket");
// if(!this.netManager.isLocalChannel()) {
// this.state = LoginState.PASSWORD;
// this.netManager.sendPacket(new RPacketPasswordRequest()); // !Config.password.isEmpty(), Config.auth
// }
// }
public void processLogin(LPacketLogin packet) {
if(this.state != LoginState.INIT)
throw new IllegalStateException("Unerwartetes Login-Paket");
this.state = LoginState.ENCRYPT;
this.loginToken = new byte[4];
TOKEN_RNG.nextBytes(this.loginToken);
this.netManager.sendPacket(new RPacketRequestEncrypt(this.server.getPublicKey(), this.loginToken));
}
public void processEncryption(LPacketStartEncrypt packet) {
if(this.state != LoginState.ENCRYPT)
throw new IllegalStateException("Unerwartetes Verschlüsselungs-Paket");
PrivateKey pkey = this.server.getPrivateKey();
if(!Arrays.equals(this.loginToken, packet.getToken(pkey)))
throw new IllegalStateException("Fehlerhaftes Token");
SecretKey key = packet.getKey(pkey);
this.netManager.startEncryption(key);
this.state = LoginState.PASSWORD;
}
public void processPasswordResponse(LPacketPasswordResponse packetIn) {
if(this.state != LoginState.PASSWORD)
@ -116,6 +138,6 @@ public class LoginHandler extends NetHandler implements ILoginHandler
this.closeConnection("Falsches Zugangspasswort");
return;
}
this.state = LoginState.READY_TO_ACCEPT;
this.state = LoginState.AUTHENTICATED;
}
}