add pubkey auth
This commit is contained in:
parent
bdf67a89f7
commit
5a394749bf
24 changed files with 822 additions and 107 deletions
|
@ -41,6 +41,7 @@ import client.audio.Volume;
|
|||
import client.gui.FileCallback;
|
||||
import client.gui.Font;
|
||||
import client.gui.Gui;
|
||||
import client.gui.GuiConnect.ServerInfo;
|
||||
import client.gui.GuiConsole;
|
||||
import client.gui.GuiInfo;
|
||||
import client.gui.GuiLoading;
|
||||
|
@ -513,14 +514,14 @@ public class Client implements IThreadListener {
|
|||
return networkmanager;
|
||||
}
|
||||
|
||||
public void connect(String address, int port, String user, String pass, String access) {
|
||||
this.displayGuiScreen(GuiLoading.makeWaitTask("Verbinde zu " + (address == null ? "localhost" : address) + ":" + port + " ..."));
|
||||
Log.NETWORK.info("Verbinde zu " + (address == null ? "localhost" : address) + ":" + port);
|
||||
public void connect(ServerInfo server) {
|
||||
this.displayGuiScreen(GuiLoading.makeWaitTask("Verbinde zu " + (server.getAddress() == null ? "localhost" : server.getAddress()) + ":" + server.getPort() + " ..."));
|
||||
Log.NETWORK.info("Verbinde zu " + (server.getAddress() == null ? "localhost" : server.getAddress()) + ":" + server.getPort());
|
||||
final NetConnection connection;
|
||||
try
|
||||
{
|
||||
connection = createNetworkManagerAndConnect(address == null ? InetAddress.getLoopbackAddress() : InetAddress.getByName(IDN.toASCII(address)), port);
|
||||
connection.setNetHandler(new ClientLoginHandler(connection, this, user, access, pass));
|
||||
connection = createNetworkManagerAndConnect(server.getAddress() == null ? InetAddress.getLoopbackAddress() : InetAddress.getByName(IDN.toASCII(server.getAddress())), server.getPort());
|
||||
connection.setNetHandler(new ClientLoginHandler(connection, this, server));
|
||||
connection.sendPacket(new HPacketHandshake(Util.PROTOCOL), new GenericFutureListener<Future<? super Void>>() {
|
||||
public void operationComplete(Future<? super Void> u) throws Exception {
|
||||
connection.setConnectionState(PacketRegistry.LOGIN);
|
||||
|
@ -530,7 +531,7 @@ public class Client implements IThreadListener {
|
|||
catch (UnknownHostException u)
|
||||
{
|
||||
Log.NETWORK.error(u, "Konnte nicht zu Server verbinden");
|
||||
this.disconnected("Unbekannter Hostname: " + (address == null ? "localhost" : address));
|
||||
this.disconnected("Unbekannter Hostname: " + (server.getAddress() == null ? "localhost" : server.getAddress()));
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -28,10 +28,10 @@ public class GuiConfirm extends Gui implements ButtonCallback {
|
|||
}
|
||||
|
||||
public void init(int width, int height) {
|
||||
this.add(new Label(0, 0, 500, 24, this.messageLine1, true));
|
||||
this.add(new TransparentArea(0, 80, 500, 300, this.messageLine2, this.gm.world != null && !this.gm.charEditor));
|
||||
this.confirmBtn = this.add(new ActButton(48, 500, 200, 24, this, this.confirmButtonText));
|
||||
this.cancelBtn = this.add(new ActButton(252, 500, 200, 24, this, this.cancelButtonText));
|
||||
this.add(new Label(0, 0, 700, 24, this.messageLine1));
|
||||
this.add(new TransparentArea(0, 80, 700, 300, this.messageLine2, this.gm.world != null && !this.gm.charEditor));
|
||||
this.confirmBtn = this.add(new ActButton(100, 500, 245, 24, this, this.confirmButtonText));
|
||||
this.cancelBtn = this.add(new ActButton(355, 500, 245, 24, this, this.cancelButtonText));
|
||||
this.shift();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package client.gui;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
@ -16,27 +19,52 @@ import client.util.FileUtils;
|
|||
import common.color.TextColor;
|
||||
import common.log.Log;
|
||||
import common.network.IPlayer;
|
||||
import common.util.EncryptUtil;
|
||||
import common.util.Tuple;
|
||||
import common.util.Util;
|
||||
|
||||
public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements ButtonCallback {
|
||||
public class ServerInfo implements Comparable<ServerInfo>, ListEntry {
|
||||
private final boolean direct;
|
||||
|
||||
private String name;
|
||||
private String address;
|
||||
private int port;
|
||||
private String user;
|
||||
private String password;
|
||||
private String access;
|
||||
private KeyPair keypair;
|
||||
private PublicKey serverKey;
|
||||
private boolean enforceEncryption;
|
||||
private long lastConnected;
|
||||
|
||||
public ServerInfo(String name, String address, int port, String user, String password, String access, long lastConnected) {
|
||||
public ServerInfo(String address, int port, String user, String password, String access) {
|
||||
this.direct = true;
|
||||
this.name = "<Direktverbindung>";
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
this.access = access;
|
||||
this.lastConnected = -1L;
|
||||
}
|
||||
|
||||
public ServerInfo(String name, String address, int port, String user, String password, String access, KeyPair keypair, long lastConnected, PublicKey serverKey, boolean enforceEnc) {
|
||||
this.direct = false;
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
this.access = access;
|
||||
this.keypair = keypair;
|
||||
this.lastConnected = lastConnected;
|
||||
this.serverKey = serverKey;
|
||||
this.enforceEncryption = enforceEnc;
|
||||
}
|
||||
|
||||
public boolean isDirect() {
|
||||
return this.direct;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
@ -63,23 +91,42 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
|
|||
return this.access;
|
||||
}
|
||||
|
||||
public KeyPair getKeypair() {
|
||||
return this.keypair;
|
||||
}
|
||||
|
||||
public PublicKey getServerKey() {
|
||||
return this.serverKey;
|
||||
}
|
||||
|
||||
public boolean requiresEncryption() {
|
||||
return this.enforceEncryption;
|
||||
}
|
||||
|
||||
public long getLastConnected() {
|
||||
return this.lastConnected;
|
||||
}
|
||||
|
||||
public void setData(String name, String address, int port, String user, String password, String access) {
|
||||
public void setData(String name, String address, int port, String user, String password, String access, KeyPair keypair, PublicKey serverKey, boolean encryptReq) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
this.access = access;
|
||||
this.keypair = keypair;
|
||||
this.serverKey = serverKey;
|
||||
this.enforceEncryption = encryptReq;
|
||||
}
|
||||
|
||||
public void setLastConnected() {
|
||||
this.lastConnected = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void setServerKey(PublicKey key) {
|
||||
this.serverKey = key;
|
||||
}
|
||||
|
||||
public int compareTo(ServerInfo comp) {
|
||||
return this.lastConnected < comp.lastConnected ? 1 : (this.lastConnected > comp.lastConnected ? -1 : this.name.compareTo(comp.name));
|
||||
}
|
||||
|
@ -128,20 +175,32 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
|
|||
String user = "";
|
||||
String password = "";
|
||||
String access = "";
|
||||
byte[] key = null;
|
||||
byte[] pubkey = null;
|
||||
byte[] serverKey = null;
|
||||
boolean enforceEnc = false;
|
||||
long time = -1L;
|
||||
for(int z = 0; z <= lines.length; z++) {
|
||||
String line = z == lines.length ? null : lines[z];
|
||||
if(line == null || (line.startsWith("[") && line.endsWith("]"))) {
|
||||
if(!name.isEmpty() && !address.isEmpty() && !user.isEmpty() && user.length() < IPlayer.MAX_USER_LENGTH && IPlayer.isValidUser(user) &&
|
||||
password.length() < IPlayer.MAX_PASS_LENGTH && access.length() < IPlayer.MAX_PASS_LENGTH && address.length() < 128 && name.length() < 128 &&
|
||||
port >= 1024 && port <= 32767 && password.length() >= 8 && access.length() >= 8)
|
||||
this.elements.add(new ServerInfo(name, address, port, user, password, access, time));
|
||||
port >= 1024 && port <= 32767 && (password.length() >= 8 || password.isEmpty()) && (access.length() >= 8 || access.isEmpty())) {
|
||||
PrivateKey priv = key == null ? null : EncryptUtil.decodePrivateKey(key);
|
||||
PublicKey pub = pubkey == null ? null : EncryptUtil.decodePublicKey(pubkey);
|
||||
PublicKey serv = serverKey == null ? null : EncryptUtil.decodePublicKey(serverKey);
|
||||
this.elements.add(new ServerInfo(name, address, port, user, password, access, priv == null || pub == null ? null : new KeyPair(pub, priv), time, serv, enforceEnc));
|
||||
}
|
||||
if(line != null) {
|
||||
address = "";
|
||||
port = -1;
|
||||
user = "";
|
||||
password = "";
|
||||
access = "";
|
||||
key = null;
|
||||
pubkey = null;
|
||||
serverKey = null;
|
||||
enforceEnc = false;
|
||||
time = -1L;
|
||||
name = line.substring(1, line.length() - 1);
|
||||
}
|
||||
|
@ -168,6 +227,14 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
|
|||
}
|
||||
catch(NumberFormatException e) {
|
||||
}
|
||||
else if(value.first.equals("encryption_enforced"))
|
||||
enforceEnc = true;
|
||||
else if(value.first.equals("serverkey"))
|
||||
serverKey = Util.fromHexString(value.second);
|
||||
else if(value.first.equals("key"))
|
||||
key = Util.fromHexString(value.second);
|
||||
else if(value.first.equals("pubkey"))
|
||||
pubkey = Util.fromHexString(value.second);
|
||||
}
|
||||
}
|
||||
Collections.sort(this.elements);
|
||||
|
@ -202,19 +269,39 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
|
|||
this.gm.displayGuiScreen(this);
|
||||
}
|
||||
|
||||
public void editServer(ServerInfo server) {
|
||||
if(!server.isDirect())
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void connect(String address, int port, String user, String pass, String access) {
|
||||
this.gm.connect(new ServerInfo(address, port, user, pass, access));
|
||||
}
|
||||
|
||||
private void save() {
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(ServerInfo server : this.elements) {
|
||||
if(sb.length() > 0)
|
||||
sb.append("\n");
|
||||
sb.append("[" + server.getName() + "]\n");
|
||||
sb.append("address " + server.getAddress() + "\n");
|
||||
sb.append("port " + server.getPort() + "\n");
|
||||
sb.append("user " + server.getUser() + "\n");
|
||||
sb.append("password " + server.getPassword() + "\n");
|
||||
sb.append("access " + server.getAccess() + "\n");
|
||||
sb.append("connected " + server.getLastConnected());
|
||||
sb.append("[" + server.getName() + "]");
|
||||
sb.append("\naddress " + server.getAddress());
|
||||
sb.append("\nport " + server.getPort());
|
||||
sb.append("\nuser " + server.getUser());
|
||||
if(!server.getPassword().isEmpty())
|
||||
sb.append("\npassword " + server.getPassword());
|
||||
if(!server.getAccess().isEmpty())
|
||||
sb.append("\naccess " + server.getAccess());
|
||||
if(server.getKeypair() != null) {
|
||||
sb.append("\nkey " + Util.getHexString(server.getKeypair().getPrivate().getEncoded()));
|
||||
sb.append("\npubkey " + Util.getHexString(server.getKeypair().getPublic().getEncoded()));
|
||||
}
|
||||
if(server.requiresEncryption())
|
||||
sb.append("\nencryption_enforced");
|
||||
if(server.getLastConnected() != -1L)
|
||||
sb.append("\nconnected " + server.getLastConnected());
|
||||
if(server.getServerKey() != null)
|
||||
sb.append("\nserverkey " + Util.getHexString(server.getServerKey().getEncoded()));
|
||||
}
|
||||
FileUtils.write(SERVERS_FILE, sb.toString());
|
||||
}
|
||||
|
@ -246,12 +333,12 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
|
|||
ServerInfo server = this.getSelected();
|
||||
if(server != null) {
|
||||
server.setLastConnected();
|
||||
this.gm.connect(server.address, server.port, server.user, server.password, server.access);
|
||||
this.gm.connect(server);
|
||||
}
|
||||
}
|
||||
else if(button == this.createButton) {
|
||||
this.setSelected(-1);
|
||||
this.gm.displayGuiScreen(new GuiServer(new ServerInfo("", "", -1, "", "", "", -1L)));
|
||||
this.gm.displayGuiScreen(new GuiServer(new ServerInfo("", "", -1, "", "", "", null, -1L, null, false)));
|
||||
}
|
||||
else if(button == this.editButton) {
|
||||
ServerInfo server = this.getSelected();
|
||||
|
@ -262,7 +349,7 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
|
|||
ServerInfo server = this.getSelected();
|
||||
if(server != null) {
|
||||
this.setSelected(-1);
|
||||
this.gm.displayGuiScreen(new GuiServer(new ServerInfo(server.name, server.address, server.port, server.user, server.password, server.access, -1L)));
|
||||
this.gm.displayGuiScreen(new GuiServer(new ServerInfo(server.name, server.address, server.port, server.user, server.password, server.access, server.keypair, -1L, null, server.enforceEncryption)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package client.gui;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import client.gui.GuiConnect.ServerInfo;
|
||||
import client.gui.element.ActButton;
|
||||
import client.gui.element.ButtonCallback;
|
||||
import client.gui.element.Label;
|
||||
import client.gui.element.NavButton;
|
||||
import client.gui.element.PressType;
|
||||
import client.gui.element.Toggle;
|
||||
import client.gui.element.FieldAction;
|
||||
import client.gui.element.Field;
|
||||
import client.gui.element.FieldCallback;
|
||||
|
@ -13,6 +17,7 @@ import client.vars.CVarCategory;
|
|||
import client.vars.Variable;
|
||||
import common.color.TextColor;
|
||||
import common.network.IPlayer;
|
||||
import common.util.EncryptUtil;
|
||||
|
||||
public class GuiServer extends Gui implements FieldCallback {
|
||||
public static final GuiServer INSTANCE = new GuiServer(null);
|
||||
|
@ -32,6 +37,11 @@ public class GuiServer extends Gui implements FieldCallback {
|
|||
private Label userLabel;
|
||||
private Label passLabel;
|
||||
private Label accLabel;
|
||||
private Toggle encToggle;
|
||||
private ActButton keyButton;
|
||||
private ActButton resetButton;
|
||||
private KeyPair keypair;
|
||||
private PublicKey serverKey;
|
||||
|
||||
public GuiServer(ServerInfo server) {
|
||||
this.server = server;
|
||||
|
@ -57,12 +67,12 @@ public class GuiServer extends Gui implements FieldCallback {
|
|||
this.userBox = this.add(new Field(0, 70, 220, 24, IPlayer.MAX_USER_LENGTH, this, IPlayer.VALID_USER, this.server == null ? this.lastUser : this.server.getUser()));
|
||||
this.passBox = this.add(new Field(0, 120, 480, 24, IPlayer.MAX_PASS_LENGTH, this, this.server == null ? this.lastPass : this.server.getPassword()));
|
||||
this.accBox = this.add(new Field(0, 170, 480, 24, IPlayer.MAX_PASS_LENGTH, this, this.server == null ? this.lastAcc : this.server.getAccess()));
|
||||
this.add(new ActButton(0, 220, 480, 24, new ButtonCallback() {
|
||||
this.add(new ActButton(0, this.server == null ? 220 : 370, 480, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
GuiServer.this.connect();
|
||||
}
|
||||
}, this.server == null ? "Verbinden" : (this.server.getName().isEmpty() ? "Hinzufügen" : "Übernehmen")));
|
||||
this.add(new NavButton(0, 250, 480, 24, this.server != null ? GuiConnect.INSTANCE : GuiMenu.INSTANCE, "Zurück"));
|
||||
this.add(new NavButton(0, this.server == null ? 250 : 400, 480, 24, this.server != null ? GuiConnect.INSTANCE : GuiMenu.INSTANCE, "Zurück"));
|
||||
if(this.server != null)
|
||||
this.nameLabel = this.add(new Label(0, -70, 410, 20, "Name", true));
|
||||
this.addrLabel = this.add(new Label(0, 0, 410, 20, "Adresse", true));
|
||||
|
@ -71,6 +81,58 @@ public class GuiServer extends Gui implements FieldCallback {
|
|||
this.userLabel = this.add(new Label(0, 50, 220, 20, "Nutzer", true));
|
||||
this.passLabel = this.add(new Label(0, 100, 480, 20, "Passwort (mind. 8 Zeichen)", true));
|
||||
this.accLabel = this.add(new Label(0, 150, 480, 20, "Zugang (mind. 8 Zeichen)", true));
|
||||
if(this.server != null) {
|
||||
this.keyButton = this.add(new ActButton(0, 220, 480, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
if(GuiServer.this.keypair == null) {
|
||||
GuiServer.this.keypair = EncryptUtil.generateKeyPair();
|
||||
GuiServer.this.keyButton.setText("Schlüsselpaar entfernen");
|
||||
}
|
||||
else {
|
||||
final String name = GuiServer.this.nameBox.getText();
|
||||
final String addr = GuiServer.this.addrBox.getText();
|
||||
final String port = GuiServer.this.portBox.getText();
|
||||
final String pass = GuiServer.this.passBox.getText();
|
||||
final String acc = GuiServer.this.accBox.getText();
|
||||
final boolean reqEnc = GuiServer.this.encToggle.getValue();
|
||||
final KeyPair keys = GuiServer.this.keypair;
|
||||
final PublicKey key = GuiServer.this.serverKey;
|
||||
GuiServer.this.gm.displayGuiScreen(new GuiConfirm(new GuiConfirm.Callback() {
|
||||
public void confirm(boolean confirmed) {
|
||||
GuiServer.this.gm.displayGuiScreen(GuiServer.this);
|
||||
GuiServer.this.nameBox.setText(name);
|
||||
GuiServer.this.addrBox.setText(addr);
|
||||
GuiServer.this.portBox.setText(port);
|
||||
GuiServer.this.passBox.setText(pass);
|
||||
GuiServer.this.accBox.setText(acc);
|
||||
GuiServer.this.encToggle.setValue(reqEnc);
|
||||
GuiServer.this.serverKey = key;
|
||||
GuiServer.this.resetButton.enabled = key != null;
|
||||
if(confirmed) {
|
||||
GuiServer.this.keypair = null;
|
||||
GuiServer.this.keyButton.setText("Neues Schlüsselpaar generieren");
|
||||
}
|
||||
else {
|
||||
GuiServer.this.keypair = keys;
|
||||
GuiServer.this.keyButton.setText("Schlüsselpaar entfernen");
|
||||
}
|
||||
}
|
||||
}, "Schlüsselpaar wirklich entfernen?", "Wenn das Schlüsselpaar gelöscht wird, ist es nicht mehr möglich, sich damit auf dem Server zu identifizieren und sich anzumelden.\nDamit könnte der Zugriff auf den Server unmöglich werden.", "Schlüsselpaar löschen", "Abbrechen"));
|
||||
}
|
||||
}
|
||||
}, (this.keypair = this.server.getKeypair()) == null ? "Neues Schlüsselpaar generieren" : "Schlüsselpaar entfernen"));
|
||||
this.encToggle = this.add(new Toggle(0, 270, 480, 24, false, this.server.requiresEncryption(), null, "Nur Verschlüsselt verbinden"));
|
||||
GuiServer.this.serverKey = this.server.getServerKey();
|
||||
this.resetButton = this.add(new ActButton(0, 320, 480, 24, new ButtonCallback() {
|
||||
public void use(ActButton elem, PressType action) {
|
||||
if(GuiServer.this.serverKey != null) {
|
||||
GuiServer.this.serverKey = null;
|
||||
GuiServer.this.resetButton.enabled = false;
|
||||
}
|
||||
}
|
||||
}, "Server-Key zurücksetzen"));
|
||||
this.resetButton.enabled = this.serverKey != null;
|
||||
}
|
||||
this.shift();
|
||||
}
|
||||
|
||||
|
@ -134,10 +196,10 @@ public class GuiServer extends Gui implements FieldCallback {
|
|||
this.lastPass = pass;
|
||||
this.lastAcc = acc;
|
||||
this.gm.setDirty();
|
||||
this.gm.connect(addr, port, user, pass, acc);
|
||||
GuiConnect.INSTANCE.connect(addr, port, user, pass, acc);
|
||||
}
|
||||
else {
|
||||
this.server.setData(name, addr, port, user, pass, acc);
|
||||
this.server.setData(name, addr, port, user, pass, acc, this.keypair, this.serverKey, this.encToggle.getValue());
|
||||
GuiConnect.INSTANCE.applyServer(this.server);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,8 @@ public class Toggle extends Element {
|
|||
// this.type = this.value != 0 ? ElemType.TOGGLE_ON : ElemType.TOGGLE_OFF;
|
||||
// gui_update_style(this, 1);
|
||||
// this.r_dirty = true;
|
||||
this.func.use(this, this.value);
|
||||
if(this.func != null)
|
||||
this.func.use(this, this.value);
|
||||
this.formatText();
|
||||
this.playSound();
|
||||
}
|
||||
|
@ -50,4 +51,15 @@ public class Toggle extends Element {
|
|||
else
|
||||
super.drawBackground();
|
||||
}
|
||||
|
||||
public void setValue(boolean value) {
|
||||
if(this.value != value) {
|
||||
this.value = value;
|
||||
this.formatText();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,55 @@
|
|||
package client.network;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import client.Client;
|
||||
import client.gui.GuiConfirm;
|
||||
import client.gui.GuiConnect;
|
||||
import client.gui.GuiConnect.ServerInfo;
|
||||
import client.gui.GuiLoading;
|
||||
import common.net.util.concurrent.Future;
|
||||
import common.net.util.concurrent.GenericFutureListener;
|
||||
import common.network.IClientLoginHandler;
|
||||
import common.network.NetConnection;
|
||||
import common.network.NetHandler;
|
||||
import common.network.PacketRegistry;
|
||||
import common.packet.LPacketPasswordResponse;
|
||||
import common.packet.LPacketChallenge;
|
||||
import common.packet.LPacketPassword;
|
||||
import common.packet.LPacketPubkey;
|
||||
import common.packet.LPacketResponse;
|
||||
import common.packet.LPacketStartEncrypt;
|
||||
import common.packet.RPacketChallenge;
|
||||
import common.packet.RPacketDisconnect;
|
||||
import common.packet.RPacketEnableCompression;
|
||||
import common.packet.RPacketLoginSuccess;
|
||||
import common.packet.RPacketRequestEncrypt;
|
||||
import common.packet.RPacketResponse;
|
||||
import common.packet.RPacketServerConfig;
|
||||
import common.util.EncryptUtil;
|
||||
|
||||
public class ClientLoginHandler extends NetHandler implements IClientLoginHandler {
|
||||
private final Client gm;
|
||||
private final NetConnection networkManager;
|
||||
private final String user;
|
||||
private final String access;
|
||||
private final String password;
|
||||
private static enum LoginState {
|
||||
HANDSHAKE, CONFIRMING, CHALLENGE, ENCRYPTED, PROVING, AUTHENTICATING, DONE;
|
||||
}
|
||||
|
||||
public ClientLoginHandler(NetConnection conn, Client gmIn, String userIn, String accessIn, String passwordIn) {
|
||||
this.networkManager = conn;
|
||||
this.gm = gmIn;
|
||||
this.user = userIn;
|
||||
this.access = accessIn;
|
||||
this.password = passwordIn;
|
||||
private static final SecureRandom TOKEN_RNG = new SecureRandom();
|
||||
|
||||
private final Client gm;
|
||||
private final NetConnection connection;
|
||||
private final ServerInfo server;
|
||||
|
||||
private LoginState state = LoginState.HANDSHAKE;
|
||||
private byte[] token;
|
||||
|
||||
public ClientLoginHandler(NetConnection conn, Client gm, ServerInfo server) {
|
||||
this.connection = conn;
|
||||
this.gm = gm;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void onDisconnect(String reason)
|
||||
|
@ -39,32 +57,131 @@ public class ClientLoginHandler extends NetHandler implements IClientLoginHandle
|
|||
this.gm.disconnected(reason);
|
||||
}
|
||||
|
||||
public void handleDisconnect(RPacketDisconnect packetIn)
|
||||
public void handleDisconnect(RPacketDisconnect packet)
|
||||
{
|
||||
this.networkManager.closeChannel(packetIn.getReason());
|
||||
this.connection.closeChannel(packet.getReason());
|
||||
}
|
||||
|
||||
public void handleEncrypt(RPacketRequestEncrypt packet) {
|
||||
this.networkManager.setConnectionState(PacketRegistry.LOGIN);
|
||||
if(this.state != LoginState.HANDSHAKE) {
|
||||
this.connection.closeChannel("Unerwartetes Verschlüsselungs-Paket");
|
||||
return;
|
||||
}
|
||||
this.connection.setConnectionState(PacketRegistry.LOGIN);
|
||||
final SecretKey secret = EncryptUtil.createNewSharedKey();
|
||||
PublicKey pubkey = packet.getKey();
|
||||
this.networkManager.sendPacket(new LPacketStartEncrypt(secret, pubkey, packet.getToken()), new GenericFutureListener < Future <? super Void >> () {
|
||||
final PublicKey pubkey = packet.getKey();
|
||||
final byte[] token = packet.getToken();
|
||||
if(this.server.getServerKey() == null) {
|
||||
this.state = LoginState.CONFIRMING;
|
||||
this.gm.schedule(new Runnable() {
|
||||
public void run() {
|
||||
ClientLoginHandler.this.gm.displayGuiScreen(new GuiConfirm(new GuiConfirm.Callback() {
|
||||
public void confirm(boolean confirmed) {
|
||||
if(confirmed) {
|
||||
ClientLoginHandler.this.server.setServerKey(pubkey);
|
||||
GuiConnect.INSTANCE.editServer(ClientLoginHandler.this.server);
|
||||
ClientLoginHandler.this.gm.displayGuiScreen(
|
||||
GuiLoading.makeWaitTask("Verbinde zu " + (ClientLoginHandler.this.server.getAddress() == null ? "localhost" :
|
||||
ClientLoginHandler.this.server.getAddress()) + ":" + ClientLoginHandler.this.server.getPort() + " ..."));
|
||||
ClientLoginHandler.this.startEncryption(secret, pubkey, token);
|
||||
}
|
||||
else {
|
||||
ClientLoginHandler.this.connection.closeChannel("Verbindung wurde abgebrochen");
|
||||
}
|
||||
}
|
||||
}, "Die Identität des Servers ist unbekannt", "Es wurde noch nie mit diesem Server verbunden.\nSoll die Verbindung wirklich fortgesetzt werden?\n\nDer öffentliche Schlüssel des Servers lautet:\n" + Base64.getEncoder().encodeToString(pubkey.getEncoded()), "Verbindung herstellen", "Abbrechen und trennen"));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
else if(!this.server.getServerKey().equals(pubkey)) {
|
||||
this.connection.closeChannel("Die Identität des Servers hat sich geändert\n\nDer Server hat einen anderen öffentlichen Schlüssel als vorher bekannt war, dies kann bedeuten dass der Inhaber jetzt einen anderen Schlüssel verwendet oder sich ein anderer Server als dieser ausgibt (man-in-the-middle attack).\n\nDer öffentliche Schlüssel des Servers lautet:\n" + Base64.getEncoder().encodeToString(pubkey.getEncoded()) + "\n\nDer vertrauenswürdige Schlüssel lautet:\n" + Base64.getEncoder().encodeToString(this.server.getServerKey().getEncoded()));
|
||||
return;
|
||||
}
|
||||
this.startEncryption(secret, pubkey, token);
|
||||
}
|
||||
|
||||
private void startEncryption(SecretKey secret, PublicKey pubkey, byte[] token) {
|
||||
this.state = LoginState.CHALLENGE;
|
||||
this.connection.sendPacket(new LPacketStartEncrypt(secret, pubkey, token), new GenericFutureListener < Future <? super Void >> () {
|
||||
public void operationComplete(Future <? super Void > u) throws Exception {
|
||||
ClientLoginHandler.this.networkManager.startEncryption(secret);
|
||||
ClientLoginHandler.this.networkManager.sendPacket(new LPacketPasswordResponse(ClientLoginHandler.this.user, ClientLoginHandler.this.access, ClientLoginHandler.this.password));
|
||||
ClientLoginHandler.this.connection.startEncryption(secret);
|
||||
ClientLoginHandler.this.token = new byte[32];
|
||||
TOKEN_RNG.nextBytes(ClientLoginHandler.this.token);
|
||||
ClientLoginHandler.this.connection.sendPacket(new LPacketChallenge(pubkey, ClientLoginHandler.this.token));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void handleLoginSuccess(RPacketLoginSuccess packetIn)
|
||||
public void handleResponse(RPacketResponse packet) {
|
||||
if(this.state != LoginState.CHALLENGE) {
|
||||
this.connection.closeChannel("Unerwartetes Beweis-Paket");
|
||||
return;
|
||||
}
|
||||
if(!Arrays.equals(this.token, packet.getToken())) {
|
||||
this.connection.closeChannel("Fehlerhaftes Beweis-Token");
|
||||
return;
|
||||
}
|
||||
this.state = LoginState.ENCRYPTED;
|
||||
}
|
||||
|
||||
public void handleConfig(RPacketServerConfig packet) {
|
||||
if(this.state == LoginState.HANDSHAKE) {
|
||||
this.connection.setConnectionState(PacketRegistry.LOGIN);
|
||||
if(this.server.requiresEncryption()) {
|
||||
this.connection.closeChannel("Der Server unterstützt keine verschlüsselte Verbindung, dies ist in den Servereinstellungen von '"
|
||||
+ this.server.getName() + "' als erforderlich eingestellt, stelle keine ungesicherte Verbindung her.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(this.state != LoginState.ENCRYPTED) {
|
||||
this.connection.closeChannel("Unerwartetes Konfigurations-Paket");
|
||||
return;
|
||||
}
|
||||
boolean auth = packet.isAuthenticating();
|
||||
boolean passwordAuth = packet.canUsePassword();
|
||||
boolean pubkeyAuth = packet.canUsePubkey() && this.state == LoginState.ENCRYPTED;
|
||||
if(auth && (!passwordAuth || this.server.getPassword().isEmpty()) && (!pubkeyAuth || this.server.getKeypair() == null)) {
|
||||
this.connection.closeChannel("Der Server unterstützt keine der vorhandenen Authentifizierungsmethoden\n\nUnterstützt vom Server: " +
|
||||
(!passwordAuth && !pubkeyAuth ? "Keine" : ((passwordAuth ? "Passwort" : "") + (passwordAuth && pubkeyAuth ? " und " : "") + (pubkeyAuth ? "Pubkey" : ""))) +
|
||||
"\n\nVorhanden in Konfiguration für '" + this.server.getName() + "': " + (this.server.getPassword().isEmpty() && this.server.getKeypair() == null ? "Keine" :
|
||||
((this.server.getPassword().isEmpty() ? "Passwort" : "") +
|
||||
(this.server.getPassword().isEmpty() && this.server.getKeypair() != null ? " und " : "") + (this.server.getKeypair() != null ? "Pubkey" : ""))));
|
||||
return;
|
||||
}
|
||||
if(auth && pubkeyAuth && this.server.getKeypair() != null) {
|
||||
this.state = LoginState.PROVING;
|
||||
this.connection.sendPacket(new LPacketPubkey(this.server.getUser(), this.server.getAccess(), this.server.getKeypair().getPublic()));
|
||||
}
|
||||
else {
|
||||
this.state = LoginState.AUTHENTICATING;
|
||||
this.connection.sendPacket(new LPacketPassword(this.server.getUser(), this.server.getAccess(), auth ? this.server.getPassword() : ""));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleChallenge(RPacketChallenge packet) {
|
||||
if(this.state != LoginState.PROVING) {
|
||||
this.connection.closeChannel("Unerwartetes Anforderungs-Paket");
|
||||
return;
|
||||
}
|
||||
this.state = LoginState.AUTHENTICATING;
|
||||
this.connection.sendPacket(new LPacketResponse(packet.getToken(this.server.getKeypair().getPrivate())));
|
||||
}
|
||||
|
||||
public void handleLoginSuccess(RPacketLoginSuccess packet)
|
||||
{
|
||||
this.gm.debugWorld = packetIn.isDebug();
|
||||
this.networkManager.setConnectionState(PacketRegistry.PLAY);
|
||||
this.networkManager.setNetHandler(new ClientPlayer(this.gm, this.networkManager));
|
||||
if(this.state != LoginState.AUTHENTICATING) {
|
||||
this.connection.closeChannel("Unerwartetes Bestätigungs-Paket");
|
||||
return;
|
||||
}
|
||||
this.state = LoginState.DONE;
|
||||
this.gm.debugWorld = packet.isDebug();
|
||||
this.connection.setConnectionState(PacketRegistry.PLAY);
|
||||
this.connection.setNetHandler(new ClientPlayer(this.gm, this.connection));
|
||||
}
|
||||
|
||||
public void handleEnableCompression(RPacketEnableCompression packetIn)
|
||||
public void handleEnableCompression(RPacketEnableCompression packet)
|
||||
{
|
||||
this.networkManager.setCompressionTreshold(packetIn.getValue());
|
||||
this.connection.setCompressionTreshold(packet.getValue());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue