extend and fix pubkeys

This commit is contained in:
Sen 2025-05-29 12:51:39 +02:00
parent 5a394749bf
commit 902c795ecc
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
5 changed files with 184 additions and 64 deletions

View file

@ -513,34 +513,54 @@ public class Client implements IThreadListener {
})).channel(NioSocketChannel.class)).connect(address, serverPort).syncUninterruptibly(); })).channel(NioSocketChannel.class)).connect(address, serverPort).syncUninterruptibly();
return networkmanager; return networkmanager;
} }
public void displayConnecting(ServerInfo server) {
this.displayGuiScreen(GuiLoading.makeWaitTask("Verbinde zu " + (server.getAddress() == null ? "localhost" : server.getAddress()) + ":" + server.getPort() + " ..."));
}
public void connect(ServerInfo server) { public void connect(final ServerInfo server) {
this.displayGuiScreen(GuiLoading.makeWaitTask("Verbinde zu " + (server.getAddress() == null ? "localhost" : server.getAddress()) + ":" + server.getPort() + " ...")); this.displayConnecting(server);
Log.NETWORK.info("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; new Thread(new Runnable() {
try public void run() {
{ final NetConnection connection;
connection = createNetworkManagerAndConnect(server.getAddress() == null ? InetAddress.getLoopbackAddress() : InetAddress.getByName(IDN.toASCII(server.getAddress())), server.getPort()); try
connection.setNetHandler(new ClientLoginHandler(connection, this, server)); {
connection.sendPacket(new HPacketHandshake(Util.PROTOCOL), new GenericFutureListener<Future<? super Void>>() { connection = createNetworkManagerAndConnect(server.getAddress() == null ? InetAddress.getLoopbackAddress() : InetAddress.getByName(IDN.toASCII(server.getAddress())), server.getPort());
public void operationComplete(Future<? super Void> u) throws Exception { connection.setNetHandler(new ClientLoginHandler(connection, Client.this, server));
connection.setConnectionState(PacketRegistry.LOGIN); connection.sendPacket(new HPacketHandshake(Util.PROTOCOL), new GenericFutureListener<Future<? super Void>>() {
} public void operationComplete(Future<? super Void> u) throws Exception {
}); connection.setConnectionState(PacketRegistry.LOGIN);
} }
catch (UnknownHostException u) });
{ }
Log.NETWORK.error(u, "Konnte nicht zu Server verbinden"); catch (UnknownHostException u)
this.disconnected("Unbekannter Hostname: " + (server.getAddress() == null ? "localhost" : server.getAddress())); {
return; Log.NETWORK.error(u, "Konnte nicht zu Server verbinden");
} Client.this.schedule(new Runnable() {
catch (Exception e) public void run() {
{ Client.this.disconnected("Unbekannter Hostname: " + (server.getAddress() == null ? "localhost" : server.getAddress()));
Log.NETWORK.error(e, "Konnte nicht zu Server verbinden"); }
this.disconnected(e.toString()); });
return; return;
} }
this.connection = connection; catch (Exception e)
{
Log.NETWORK.error(e, "Konnte nicht zu Server verbinden");
Client.this.schedule(new Runnable() {
public void run() {
Client.this.disconnected(e.toString());
}
});
return;
}
Client.this.schedule(new Runnable() {
public void run() {
Client.this.connection = connection;
}
});
}
}, "Server connector").start();
} }
public void unloadWorld() { public void unloadWorld() {

View file

@ -34,13 +34,15 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
private String password; private String password;
private String access; private String access;
private KeyPair keypair; private KeyPair keypair;
private String keyDigest;
private PublicKey serverKey; private PublicKey serverKey;
private String serverDigest;
private boolean enforceEncryption; private boolean enforceEncryption;
private long lastConnected; private long lastConnected;
public ServerInfo(String address, int port, String user, String password, String access) { public ServerInfo(String address, int port, String user, String password, String access) {
this.direct = true; this.direct = true;
this.name = "<Direktverbindung>"; this.name = DIRECT_NAME;
this.address = address; this.address = address;
this.port = port; this.port = port;
this.user = user; this.user = user;
@ -61,6 +63,10 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
this.lastConnected = lastConnected; this.lastConnected = lastConnected;
this.serverKey = serverKey; this.serverKey = serverKey;
this.enforceEncryption = enforceEnc; this.enforceEncryption = enforceEnc;
if(this.keypair != null)
this.keyDigest = EncryptUtil.getXorSha512Hash(this.keypair.getPublic().getEncoded());
if(this.serverKey != null)
this.serverDigest = EncryptUtil.getXorSha512Hash(this.serverKey.getEncoded());
} }
public boolean isDirect() { public boolean isDirect() {
@ -117,6 +123,8 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
this.keypair = keypair; this.keypair = keypair;
this.serverKey = serverKey; this.serverKey = serverKey;
this.enforceEncryption = encryptReq; this.enforceEncryption = encryptReq;
this.keyDigest = this.keypair != null ? EncryptUtil.getXorSha512Hash(this.keypair.getPublic().getEncoded()) : null;
this.serverDigest = this.serverKey != null ? EncryptUtil.getXorSha512Hash(this.serverKey.getEncoded()) : null;
} }
public void setLastConnected() { public void setLastConnected() {
@ -125,6 +133,7 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
public void setServerKey(PublicKey key) { public void setServerKey(PublicKey key) {
this.serverKey = key; this.serverKey = key;
this.serverDigest = this.serverKey != null ? EncryptUtil.getXorSha512Hash(this.serverKey.getEncoded()) : null;
} }
public int compareTo(ServerInfo comp) { public int compareTo(ServerInfo comp) {
@ -144,12 +153,22 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
public void draw(int x, int y, int mouseXIn, int mouseYIn, boolean hover) { public void draw(int x, int y, int mouseXIn, int mouseYIn, boolean hover) {
Drawing.drawText(this.name + TextColor.GRAY + " - " + TextColor.RESET + this.user, x + 2, y, 0xffffffff); Drawing.drawText(this.name + TextColor.GRAY + " - " + TextColor.RESET + this.user, x + 2, y, 0xffffffff);
Drawing.drawText(this.address + TextColor.GRAY + " Port " + TextColor.RESET + this.port, x + 2, y + 18, 0xff808080); if(this.keypair != null || !this.password.isEmpty())
Drawing.drawTextRight(
(this.keypair != null ? "Pubkey " + this.keyDigest : "") + (this.keypair != null && !this.password.isEmpty() ? " + " : "") + (!this.password.isEmpty() ? "Passwort" : ""),
x + 660 - 4 - 2, y, 0xffffffff);
Drawing.drawText(this.address + TextColor.GRAY + " Port " + TextColor.RESET + this.port + (this.enforceEncryption ? TextColor.GRAY + ", nur verschlüsselt" : ""),
x + 2, y + 18, 0xff808080);
if(!this.access.isEmpty())
Drawing.drawTextRight((this.keypair != null || !this.password.isEmpty() ? "+ " : "") + "Server-Passwort", x + 660 - 4 - 2, y + 18, 0xff808080);
Drawing.drawText("Zuletzt verbunden: " + (this.lastConnected == -1L ? "nie" : DATE_FORMAT.format(new Date(this.lastConnected))), x + 2, y + 18 + 16, 0xff808080); Drawing.drawText("Zuletzt verbunden: " + (this.lastConnected == -1L ? "nie" : DATE_FORMAT.format(new Date(this.lastConnected))), x + 2, y + 18 + 16, 0xff808080);
if(this.serverDigest != null)
Drawing.drawTextRight("Server-ID: " + this.serverDigest, x + 660 - 4 - 2, y + 18 + 16, 0xff808080);
} }
} }
public static final GuiConnect INSTANCE = new GuiConnect(); public static final GuiConnect INSTANCE = new GuiConnect();
private static final String DIRECT_NAME = "<Direktverbindung>";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
private static final File SERVERS_FILE = new File("servers.cfg"); private static final File SERVERS_FILE = new File("servers.cfg");
@ -185,7 +204,7 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
if(line == null || (line.startsWith("[") && line.endsWith("]"))) { if(line == null || (line.startsWith("[") && line.endsWith("]"))) {
if(!name.isEmpty() && !address.isEmpty() && !user.isEmpty() && user.length() < IPlayer.MAX_USER_LENGTH && IPlayer.isValidUser(user) && 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 && 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 || password.isEmpty()) && (access.length() >= 8 || access.isEmpty())) { port >= 1024 && port <= 32767 && (password.length() >= 8 || password.isEmpty()) && (access.length() >= 8 || access.isEmpty()) && !this.isNameTaken(name)) {
PrivateKey priv = key == null ? null : EncryptUtil.decodePrivateKey(key); PrivateKey priv = key == null ? null : EncryptUtil.decodePrivateKey(key);
PublicKey pub = pubkey == null ? null : EncryptUtil.decodePublicKey(pubkey); PublicKey pub = pubkey == null ? null : EncryptUtil.decodePublicKey(pubkey);
PublicKey serv = serverKey == null ? null : EncryptUtil.decodePublicKey(serverKey); PublicKey serv = serverKey == null ? null : EncryptUtil.decodePublicKey(serverKey);
@ -269,6 +288,14 @@ public class GuiConnect extends GuiList<GuiConnect.ServerInfo> implements Button
this.gm.displayGuiScreen(this); this.gm.displayGuiScreen(this);
} }
public boolean isNameTaken(String name) {
for(int z = 0; z < this.elements.size(); z++) {
if(this.selectedElement != z && this.elements.get(z).getName().equals(name))
return true;
}
return DIRECT_NAME.equals(name);
}
public void editServer(ServerInfo server) { public void editServer(ServerInfo server) {
if(!server.isDirect()) if(!server.isDirect())
this.save(); this.save();

View file

@ -37,11 +37,15 @@ public class GuiServer extends Gui implements FieldCallback {
private Label userLabel; private Label userLabel;
private Label passLabel; private Label passLabel;
private Label accLabel; private Label accLabel;
private Label keyLabel;
private Label idLabel;
private Toggle encToggle; private Toggle encToggle;
private ActButton keyButton; private ActButton keyButton;
private ActButton resetButton; private ActButton resetButton;
private KeyPair keypair; private KeyPair keypair;
private String keyDigest;
private PublicKey serverKey; private PublicKey serverKey;
private String serverDigest;
public GuiServer(ServerInfo server) { public GuiServer(ServerInfo server) {
this.server = server; this.server = server;
@ -59,34 +63,40 @@ public class GuiServer extends Gui implements FieldCallback {
private String lastAcc = ""; private String lastAcc = "";
public void init(int width, int height) { public void init(int width, int height) {
if(this.server != null) if(this.server != null) {
this.nameBox = this.add(new Field(0, -50, 400, 24, 128, this, this.server.getName())); this.nameBox = this.add(new Field(0, -50, 400, 24, 128, this, this.server.getName()));
this.keypair = this.server.getKeypair();
this.keyDigest = this.keypair == null ? null : EncryptUtil.getXorSha512Hash(this.keypair.getPublic().getEncoded());
}
this.addrBox = this.add(new Field(0, 20, 400, 24, 128, this, this.server == null ? this.lastAddr : this.server.getAddress())); this.addrBox = this.add(new Field(0, 20, 400, 24, 128, this, this.server == null ? this.lastAddr : this.server.getAddress()));
int port = this.server == null ? this.lastPort : this.server.getPort(); int port = this.server == null ? this.lastPort : this.server.getPort();
this.portBox = this.add(new Field(404, 20, 76, 24, 5, this, port < 0 ? "" : "" + port)); this.portBox = this.add(new Field(404, 20, 76, 24, 5, this, port < 0 ? "" : "" + port));
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.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.passBox = this.add(new Field(0, this.server == null ? 120 : 170, 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.accBox = this.add(new Field(0, this.server == null ? 170 : 220, 480, 24, IPlayer.MAX_PASS_LENGTH, this, this.server == null ? this.lastAcc : this.server.getAccess()));
this.add(new ActButton(0, this.server == null ? 220 : 370, 480, 24, new ButtonCallback() { this.add(new ActButton(0, this.server == null ? 220 : 350, 480, 24, new ButtonCallback() {
public void use(ActButton elem, PressType action) { public void use(ActButton elem, PressType action) {
GuiServer.this.connect(); GuiServer.this.connect();
} }
}, this.server == null ? "Verbinden" : (this.server.getName().isEmpty() ? "Hinzufügen" : "Übernehmen"))); }, this.server == null ? "Verbinden" : (this.server.getName().isEmpty() ? "Hinzufügen" : "Übernehmen")));
this.add(new NavButton(0, this.server == null ? 250 : 400, 480, 24, this.server != null ? GuiConnect.INSTANCE : GuiMenu.INSTANCE, "Zurück")); this.add(new NavButton(0, this.server == null ? 250 : 380, 480, 24, this.server != null ? GuiConnect.INSTANCE : GuiMenu.INSTANCE, "Zurück"));
if(this.server != null) if(this.server != null)
this.nameLabel = this.add(new Label(0, -70, 410, 20, "Name", true)); this.nameLabel = this.add(new Label(0, -70, 410, 20, "Name in der Liste", true));
this.addrLabel = this.add(new Label(0, 0, 410, 20, "Adresse", true)); this.addrLabel = this.add(new Label(0, 0, 410, 20, "Adresse / Hostname", true));
this.portLabel = this.add(new Label(404, 0, 76, 20, "Port", true)); this.portLabel = this.add(new Label(404, 0, 76, 20, "Port", true));
this.rangeLabel = this.add(new Label(370, 44, 110, 20, "[1024..32767]", true)); this.rangeLabel = this.add(new Label(370, 44, 110, 20, "[1024..32767]", true));
this.userLabel = this.add(new Label(0, 50, 220, 20, "Nutzer", true)); this.userLabel = this.add(new Label(0, 50, 220, 20, "Benutzername", true));
this.passLabel = this.add(new Label(0, 100, 480, 20, "Passwort (mind. 8 Zeichen)", true)); this.passLabel = this.add(new Label(0, this.server == null ? 100 : 150, 480, 20, (this.keypair == null ? "Anmelde" : "Ersatz") + "-Passwort (mind. 8 Zeichen)", true));
this.accLabel = this.add(new Label(0, 150, 480, 20, "Zugang (mind. 8 Zeichen)", true)); this.accLabel = this.add(new Label(0, this.server == null ? 150 : 200, 480, 20, "Server-Passwort (mind. 8 Zeichen)", true));
if(this.server != null) { if(this.server != null) {
this.keyButton = this.add(new ActButton(0, 220, 480, 24, new ButtonCallback() { this.keyButton = this.add(new ActButton(0, 120, 480, 24, new ButtonCallback() {
public void use(ActButton elem, PressType action) { public void use(ActButton elem, PressType action) {
if(GuiServer.this.keypair == null) { if(GuiServer.this.keypair == null) {
GuiServer.this.keypair = EncryptUtil.generateKeyPair(); GuiServer.this.keypair = EncryptUtil.generateKeyPair();
GuiServer.this.keyDigest = EncryptUtil.getXorSha512Hash(GuiServer.this.keypair.getPublic().getEncoded());
GuiServer.this.keyLabel.setText("Anmelde-Pubkey: RSA-2048 " + GuiServer.this.keyDigest);
GuiServer.this.keyButton.setText("Schlüsselpaar entfernen"); GuiServer.this.keyButton.setText("Schlüsselpaar entfernen");
GuiServer.this.passLabel.setText("Ersatz-Passwort (mind. 8 Zeichen)");
} }
else { else {
final String name = GuiServer.this.nameBox.getText(); final String name = GuiServer.this.nameBox.getText();
@ -97,6 +107,8 @@ public class GuiServer extends Gui implements FieldCallback {
final boolean reqEnc = GuiServer.this.encToggle.getValue(); final boolean reqEnc = GuiServer.this.encToggle.getValue();
final KeyPair keys = GuiServer.this.keypair; final KeyPair keys = GuiServer.this.keypair;
final PublicKey key = GuiServer.this.serverKey; final PublicKey key = GuiServer.this.serverKey;
final String digest = GuiServer.this.keyDigest;
final String sdigest = GuiServer.this.serverDigest;
GuiServer.this.gm.displayGuiScreen(new GuiConfirm(new GuiConfirm.Callback() { GuiServer.this.gm.displayGuiScreen(new GuiConfirm(new GuiConfirm.Callback() {
public void confirm(boolean confirmed) { public void confirm(boolean confirmed) {
GuiServer.this.gm.displayGuiScreen(GuiServer.this); GuiServer.this.gm.displayGuiScreen(GuiServer.this);
@ -107,30 +119,43 @@ public class GuiServer extends Gui implements FieldCallback {
GuiServer.this.accBox.setText(acc); GuiServer.this.accBox.setText(acc);
GuiServer.this.encToggle.setValue(reqEnc); GuiServer.this.encToggle.setValue(reqEnc);
GuiServer.this.serverKey = key; GuiServer.this.serverKey = key;
GuiServer.this.serverDigest = sdigest;
GuiServer.this.idLabel.setText("Server-Pubkey: " + (key != null ? "RSA-2048 " + GuiServer.this.serverDigest : "nicht vorhanden"));
GuiServer.this.resetButton.enabled = key != null; GuiServer.this.resetButton.enabled = key != null;
if(confirmed) { if(confirmed) {
GuiServer.this.keypair = null; GuiServer.this.keypair = null;
GuiServer.this.keyDigest = null;
GuiServer.this.keyLabel.setText("Anmelde-Pubkey: nicht vorhanden");
GuiServer.this.keyButton.setText("Neues Schlüsselpaar generieren"); GuiServer.this.keyButton.setText("Neues Schlüsselpaar generieren");
GuiServer.this.passLabel.setText("Anmelde-Passwort (mind. 8 Zeichen)");
} }
else { else {
GuiServer.this.keypair = keys; GuiServer.this.keypair = keys;
GuiServer.this.keyDigest = digest;
GuiServer.this.keyLabel.setText("Anmelde-Pubkey: RSA-2048 " + GuiServer.this.keyDigest);
GuiServer.this.keyButton.setText("Schlüsselpaar entfernen"); GuiServer.this.keyButton.setText("Schlüsselpaar entfernen");
GuiServer.this.passLabel.setText("Ersatz-Passwort (mind. 8 Zeichen)");
} }
} }
}, "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")); }, "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.keypair == 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")); this.keyLabel = this.add(new Label(0, 100, 480, 20, "Anmelde-Pubkey: " + (this.keypair != null ? "RSA-2048 " + this.keyDigest : "nicht vorhanden"), true));
GuiServer.this.serverKey = this.server.getServerKey(); this.encToggle = this.add(new Toggle(0, 250, 480, 24, false, this.server.requiresEncryption(), null, "Nur Verschlüsselte Verbindung akzeptieren"));
this.resetButton = this.add(new ActButton(0, 320, 480, 24, new ButtonCallback() { this.serverKey = this.server.getServerKey();
this.serverDigest = this.serverKey == null ? null : EncryptUtil.getXorSha512Hash(this.serverKey.getEncoded());
this.idLabel = this.add(new Label(0, 280, 480, 20, "Server-Pubkey: " + (this.serverKey != null ? "RSA-2048 " + this.serverDigest : "nicht vorhanden"), true));
this.resetButton = this.add(new ActButton(0, 300, 480, 24, new ButtonCallback() {
public void use(ActButton elem, PressType action) { public void use(ActButton elem, PressType action) {
if(GuiServer.this.serverKey != null) { if(GuiServer.this.serverKey != null) {
GuiServer.this.serverKey = null; GuiServer.this.serverKey = null;
GuiServer.this.serverDigest = null;
GuiServer.this.idLabel.setText("Server-Pubkey: nicht vorhanden");
GuiServer.this.resetButton.enabled = false; GuiServer.this.resetButton.enabled = false;
} }
} }
}, "Server-Key zurücksetzen")); }, "Server-Identifizierung / Pubkey zurücksetzen"));
this.resetButton.enabled = this.serverKey != null; this.resetButton.enabled = this.serverKey != null;
} }
this.shift(); this.shift();
@ -147,13 +172,17 @@ public class GuiServer extends Gui implements FieldCallback {
if(this.server != null) { if(this.server != null) {
name = this.nameBox.getText(); name = this.nameBox.getText();
if(name.isEmpty()) { if(name.isEmpty()) {
this.nameLabel.setText(TextColor.RED + "Name"); this.nameLabel.setText(TextColor.RED + "Name in der Liste");
return;
}
if(GuiConnect.INSTANCE.isNameTaken(name)) {
this.nameLabel.setText("Name in der Liste - " + TextColor.RED + "Bereits vorhanden");
return; return;
} }
} }
String addr = this.addrBox.getText(); String addr = this.addrBox.getText();
if(addr.isEmpty()) { if(addr.isEmpty()) {
this.addrLabel.setText(TextColor.RED + "Adresse"); this.addrLabel.setText(TextColor.RED + "Adresse / Hostname");
return; return;
} }
int port = -1; int port = -1;
@ -176,17 +205,17 @@ public class GuiServer extends Gui implements FieldCallback {
} }
String user = this.userBox.getText(); String user = this.userBox.getText();
if(user.isEmpty()) { if(user.isEmpty()) {
this.userLabel.setText(TextColor.RED + "Nutzer"); this.userLabel.setText(TextColor.RED + "Benutzername");
return; return;
} }
String pass = this.passBox.getText(); String pass = this.passBox.getText();
if(pass.length() < 8) { if(!pass.isEmpty() && pass.length() < 8) {
this.passLabel.setText(pass.isEmpty() ? TextColor.RED + "Passwort (mind. 8 Zeichen)" : "Passwort (" + TextColor.RED + "mind. 8 Zeichen" + TextColor.RESET + ")"); this.passLabel.setText((this.keypair == null ? "Anmelde" : "Ersatz") + "-Passwort (" + TextColor.RED + "mind. 8 Zeichen" + TextColor.RESET + ")");
return; return;
} }
String acc = this.accBox.getText(); String acc = this.accBox.getText();
if(acc.length() < 8) { if(!acc.isEmpty() && acc.length() < 8) {
this.accLabel.setText(acc.isEmpty() ? TextColor.RED + "Zugang (mind. 8 Zeichen)" : "Zugang (" + TextColor.RED + "mind. 8 Zeichen" + TextColor.RESET + ")"); this.accLabel.setText("Zugang (" + TextColor.RED + "mind. 8 Zeichen" + TextColor.RESET + ")");
return; return;
} }
if(this.server == null) { if(this.server == null) {
@ -211,19 +240,19 @@ public class GuiServer extends Gui implements FieldCallback {
} }
else if(value == FieldAction.FOCUS) { else if(value == FieldAction.FOCUS) {
if(elem == this.addrBox) if(elem == this.addrBox)
this.addrLabel.setText("Adresse"); this.addrLabel.setText("Adresse / Hostname");
else if(elem == this.portBox) { else if(elem == this.portBox) {
this.portLabel.setText("Port"); this.portLabel.setText("Port");
this.rangeLabel.setText("[1024..32767]"); this.rangeLabel.setText("[1024..32767]");
} }
else if(elem == this.userBox) else if(elem == this.userBox)
this.userLabel.setText("Nutzer"); this.userLabel.setText("Benutzername");
else if(elem == this.passBox) else if(elem == this.passBox)
this.passLabel.setText("Passwort (mind. 8 Zeichen)"); this.passLabel.setText((this.keypair == null ? "Anmelde" : "Ersatz") + "-Passwort (mind. 8 Zeichen)");
else if(elem == this.accBox) else if(elem == this.accBox)
this.accLabel.setText("Zugang (mind. 8 Zeichen)"); this.accLabel.setText("Server-Passwort (mind. 8 Zeichen)");
else if(this.server != null && elem == this.nameBox) else if(this.server != null && elem == this.nameBox)
this.nameLabel.setText("Name"); this.nameLabel.setText("Name in der Liste");
} }
} }
} }

View file

@ -11,7 +11,6 @@ import client.Client;
import client.gui.GuiConfirm; import client.gui.GuiConfirm;
import client.gui.GuiConnect; import client.gui.GuiConnect;
import client.gui.GuiConnect.ServerInfo; import client.gui.GuiConnect.ServerInfo;
import client.gui.GuiLoading;
import common.net.util.concurrent.Future; import common.net.util.concurrent.Future;
import common.net.util.concurrent.GenericFutureListener; import common.net.util.concurrent.GenericFutureListener;
import common.network.IClientLoginHandler; import common.network.IClientLoginHandler;
@ -80,22 +79,21 @@ public class ClientLoginHandler extends NetHandler implements IClientLoginHandle
if(confirmed) { if(confirmed) {
ClientLoginHandler.this.server.setServerKey(pubkey); ClientLoginHandler.this.server.setServerKey(pubkey);
GuiConnect.INSTANCE.editServer(ClientLoginHandler.this.server); GuiConnect.INSTANCE.editServer(ClientLoginHandler.this.server);
ClientLoginHandler.this.gm.displayGuiScreen( ClientLoginHandler.this.gm.displayConnecting(ClientLoginHandler.this.server);
GuiLoading.makeWaitTask("Verbinde zu " + (ClientLoginHandler.this.server.getAddress() == null ? "localhost" :
ClientLoginHandler.this.server.getAddress()) + ":" + ClientLoginHandler.this.server.getPort() + " ..."));
ClientLoginHandler.this.startEncryption(secret, pubkey, token); ClientLoginHandler.this.startEncryption(secret, pubkey, token);
} }
else { else {
ClientLoginHandler.this.connection.closeChannel("Verbindung wurde abgebrochen"); 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")); }, "Die Identität des Servers ist unbekannt", "Es wurde noch nie mit diesem Server verbunden.\nSoll die Verbindung wirklich fortgesetzt werden?\n\nDie Pubkey-ID des Servers lautet:\nRSA-2048 " + EncryptUtil.getXorSha512Hash(pubkey.getEncoded()) + "\n\nDer öffentliche Schlüssel des Servers lautet:\n" + Base64.getEncoder().encodeToString(pubkey.getEncoded()), "Verbindung herstellen", "Abbrechen und trennen"));
} }
}); });
return; return;
} }
else if(!this.server.getServerKey().equals(pubkey)) { 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())); 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\nDie Pubkey-ID des Servers lautet:\nRSA-2048 " + EncryptUtil.getXorSha512Hash(pubkey.getEncoded()) + "\n\nDer öffentliche Schlüssel des Servers lautet:\n" + Base64.getEncoder().encodeToString(pubkey.getEncoded()) + "\n\nDie vertrauenswürdige Pubkey-ID lautet:\nRSA-2048 " + EncryptUtil.getXorSha512Hash(this.server.getServerKey().getEncoded()) + "\n\nDer vertrauenswürdige Schlüssel lautet:\n" + Base64.getEncoder().encodeToString(this.server.getServerKey().getEncoded()) +
"\n\nFalls der Server trotzdem vertrauenswürdig wirkt, kann die Server-Identifizierung im den Einstellungen von '" + this.server.getName() + "' zurückgesetzt werden.");
return; return;
} }
this.startEncryption(secret, pubkey, token); this.startEncryption(secret, pubkey, token);
@ -125,7 +123,7 @@ public class ClientLoginHandler extends NetHandler implements IClientLoginHandle
this.state = LoginState.ENCRYPTED; this.state = LoginState.ENCRYPTED;
} }
public void handleConfig(RPacketServerConfig packet) { public void handleConfig(final RPacketServerConfig packet) {
if(this.state == LoginState.HANDSHAKE) { if(this.state == LoginState.HANDSHAKE) {
this.connection.setConnectionState(PacketRegistry.LOGIN); this.connection.setConnectionState(PacketRegistry.LOGIN);
if(this.server.requiresEncryption()) { if(this.server.requiresEncryption()) {
@ -133,11 +131,37 @@ public class ClientLoginHandler extends NetHandler implements IClientLoginHandle
+ this.server.getName() + "' als erforderlich eingestellt, stelle keine ungesicherte Verbindung her."); + this.server.getName() + "' als erforderlich eingestellt, stelle keine ungesicherte Verbindung her.");
return; return;
} }
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(null);
GuiConnect.INSTANCE.editServer(ClientLoginHandler.this.server);
ClientLoginHandler.this.gm.displayConnecting(ClientLoginHandler.this.server);
ClientLoginHandler.this.state = LoginState.HANDSHAKE;
ClientLoginHandler.this.handleConfig(packet);
}
else {
ClientLoginHandler.this.connection.closeChannel("Verbindung wurde abgebrochen");
}
}
}, "Der Server hat die Verschlüsselung deaktiviert", "Es wurde bereits verschlüsselt mit diesem Server kommuniziert.\n\nSoll die Verbindung wirklich fortgesetzt werden?\n\nDie Pubkey-Authentifizierung wird nicht verfügbar sein und die Server-ID wird ignoriert und zurückgesetzt.", "Unverschlüsselt verbinden", "Abbrechen und trennen"));
}
});
return;
}
} }
else if(this.state != LoginState.ENCRYPTED) { else if(this.state != LoginState.ENCRYPTED) {
this.connection.closeChannel("Unerwartetes Konfigurations-Paket"); this.connection.closeChannel("Unerwartetes Konfigurations-Paket");
return; return;
} }
if(packet.hasAccessPassword() && this.server.getAccess().isEmpty()) {
this.connection.closeChannel("Der Server verlangt ein Zugangs-Passwort zur Authentifizierung");
return;
}
boolean auth = packet.isAuthenticating(); boolean auth = packet.isAuthenticating();
boolean passwordAuth = packet.canUsePassword(); boolean passwordAuth = packet.canUsePassword();
boolean pubkeyAuth = packet.canUsePubkey() && this.state == LoginState.ENCRYPTED; boolean pubkeyAuth = packet.canUsePubkey() && this.state == LoginState.ENCRYPTED;

View file

@ -6,6 +6,7 @@ import java.security.Key;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
@ -117,4 +118,23 @@ public class EncryptUtil {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static String getXorSha512Hash(byte[] data) {
byte[] hash;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
hash = digest.digest(data);
}
catch(NoSuchAlgorithmException e) {
Log.SYSTEM.error(e, "Konnte Prüfwert nicht berechnen");
return "<?>";
}
byte[] xor = new byte[8];
for(int z = 0; z < hash.length / xor.length; z++) {
for(int n = 0; n < xor.length; n++) {
xor[n] ^= hash[z * xor.length + n];
}
}
return Util.getHexString(xor);
}
} }