change key exchange to ED25519

This commit is contained in:
Sen 2025-06-16 15:12:39 +02:00
parent 256721aa12
commit 6afc26e601
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
11 changed files with 148 additions and 105 deletions

View file

@ -97,7 +97,7 @@ public class GuiServer extends Gui implements FieldCallback {
if(GuiServer.this.keypair == null) {
GuiServer.this.keypair = EncryptUtil.createKeypair();
GuiServer.this.keyDigest = EncryptUtil.getXorSha512Hash(GuiServer.this.keypair.getPublic().getEncoded());
GuiServer.this.keyLabel.setText("Anmelde-Pubkey: RSA-4096 " + GuiServer.this.keyDigest);
GuiServer.this.keyLabel.setText("Anmelde-Pubkey: " + EncryptUtil.KEY_ALGO_DISPLAY + " " + GuiServer.this.keyDigest);
GuiServer.this.keyButton.setText("Schlüsselpaar entfernen");
GuiServer.this.passLabel.setText("Ersatz-Passwort (mind. 8 Zeichen)");
GuiServer.this.copyKeyButton.enabled = true;
@ -124,7 +124,7 @@ public class GuiServer extends Gui implements FieldCallback {
GuiServer.this.encToggle.setValue(reqEnc);
GuiServer.this.serverKey = key;
GuiServer.this.serverDigest = sdigest;
GuiServer.this.idLabel.setText("Server-Pubkey: " + (key != null ? "RSA-4096 " + GuiServer.this.serverDigest : "nicht vorhanden"));
GuiServer.this.idLabel.setText("Server-Pubkey: " + (key != null ? EncryptUtil.KEY_ALGO_DISPLAY + " " + GuiServer.this.serverDigest : "nicht vorhanden"));
GuiServer.this.resetButton.enabled = key != null;
GuiServer.this.copyIdButton.enabled = key != null;
GuiServer.this.copyKeyButton.enabled = !confirmed;
@ -138,7 +138,7 @@ public class GuiServer extends Gui implements FieldCallback {
else {
GuiServer.this.keypair = keys;
GuiServer.this.keyDigest = digest;
GuiServer.this.keyLabel.setText("Anmelde-Pubkey: RSA-4096 " + GuiServer.this.keyDigest);
GuiServer.this.keyLabel.setText("Anmelde-Pubkey: " + EncryptUtil.KEY_ALGO_DISPLAY + " " + GuiServer.this.keyDigest);
GuiServer.this.keyButton.setText("Schlüsselpaar entfernen");
GuiServer.this.passLabel.setText("Ersatz-Passwort (mind. 8 Zeichen)");
}
@ -154,7 +154,7 @@ public class GuiServer extends Gui implements FieldCallback {
}
}, "Kopieren"));
this.copyKeyButton.enabled = this.keypair != null;
this.keyLabel = this.add(new Label(0, 102, 480, "Anmelde-Pubkey: " + (this.keypair != null ? "RSA-4096 " + this.keyDigest : "nicht vorhanden"), true));
this.keyLabel = this.add(new Label(0, 102, 480, "Anmelde-Pubkey: " + (this.keypair != null ? EncryptUtil.KEY_ALGO_DISPLAY + " " + this.keyDigest : "nicht vorhanden"), true));
this.encToggle = this.add(new Toggle(0, 190, 480, 0, false, this.server.requiresEncryption(), null, "Nur Verschlüsselte Verbindung akzeptieren"));
this.serverKey = this.server.getServerKey();
this.serverDigest = this.serverKey == null ? null : EncryptUtil.getXorSha512Hash(this.serverKey.getEncoded());
@ -177,7 +177,7 @@ public class GuiServer extends Gui implements FieldCallback {
}
}, "Kopieren"));
this.copyIdButton.enabled = this.serverKey != null;
this.idLabel = this.add(new Label(0, 224, 480, "Server-Pubkey: " + (this.serverKey != null ? "RSA-4096 " + this.serverDigest : "nicht vorhanden"), true));
this.idLabel = this.add(new Label(0, 224, 480, "Server-Pubkey: " + (this.serverKey != null ? EncryptUtil.KEY_ALGO_DISPLAY + " " + this.serverDigest : "nicht vorhanden"), true));
}
this.shift();
}

View file

@ -1,12 +1,10 @@
package client.network;
import java.security.KeyPair;
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;
@ -41,6 +39,7 @@ public class ClientLoginHandler implements IClientLoginHandler {
private final Client gm;
private final NetConnection connection;
private final ServerInfo server;
private final KeyPair tempKeys;
private LoginState state = LoginState.HANDSHAKE;
private byte[] token;
@ -49,6 +48,7 @@ public class ClientLoginHandler implements IClientLoginHandler {
this.connection = conn;
this.gm = gm;
this.server = server;
this.tempKeys = EncryptUtil.createDHKeypair();
}
public void onDisconnect(String reason)
@ -67,9 +67,8 @@ public class ClientLoginHandler implements IClientLoginHandler {
return;
}
this.connection.setConnectionState(PacketRegistry.LOGIN);
final SecretKey secret = EncryptUtil.createSharedKey();
final PublicKey pubkey = packet.getKey();
final byte[] token = packet.getToken();
final PublicKey tempKey = packet.getTempKey();
if(this.server.getServerKey() == null) {
this.state = LoginState.CONFIRMING;
this.gm.schedule(new Runnable() {
@ -80,33 +79,33 @@ public class ClientLoginHandler implements IClientLoginHandler {
ClientLoginHandler.this.server.setServerKey(pubkey);
GuiConnect.INSTANCE.editServer(ClientLoginHandler.this.server);
ClientLoginHandler.this.gm.displayConnecting(ClientLoginHandler.this.server);
ClientLoginHandler.this.startEncryption(secret, pubkey, token);
ClientLoginHandler.this.startEncryption(tempKey);
}
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\nDie Pubkey-ID des Servers lautet:\nRSA-4096 " + EncryptUtil.getXorSha512Hash(pubkey.getEncoded()) + "\n\nDer öffentliche Schlüssel des Servers lautet:\n" + Util.breakString(Base64.getEncoder().encodeToString(pubkey.getEncoded()), 64), "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:\n" + EncryptUtil.KEY_ALGO_DISPLAY + " " + EncryptUtil.getXorSha512Hash(pubkey.getEncoded()) + "\n\nDer öffentliche Schlüssel des Servers lautet:\n" + Util.breakString(Base64.getEncoder().encodeToString(pubkey.getEncoded()), 64), "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,\ndies kann bedeuten dass der Inhaber jetzt einen anderen Schlüssel verwendet\noder sich ein anderer Server als dieser ausgibt (\"Man-in-the-middle-attack\").\n\nDie Pubkey-ID des Servers lautet: RSA-4096 " + EncryptUtil.getXorSha512Hash(pubkey.getEncoded()) + "\n\nDer öffentliche Schlüssel des Servers lautet:\n" + Util.breakString(Base64.getEncoder().encodeToString(pubkey.getEncoded()), 64) + "\n\nDie vertrauenswürdige Pubkey-ID lautet: RSA-4096 " + EncryptUtil.getXorSha512Hash(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,\ndies kann bedeuten dass der Inhaber jetzt einen anderen Schlüssel verwendet\noder sich ein anderer Server als dieser ausgibt (\"Man-in-the-middle-attack\").\n\nDie Pubkey-ID des Servers lautet: " + EncryptUtil.KEY_ALGO_DISPLAY + " " + EncryptUtil.getXorSha512Hash(pubkey.getEncoded()) + "\n\nDer öffentliche Schlüssel des Servers lautet:\n" + Util.breakString(Base64.getEncoder().encodeToString(pubkey.getEncoded()), 64) + "\n\nDie vertrauenswürdige Pubkey-ID lautet: " + EncryptUtil.KEY_ALGO_DISPLAY + " " + EncryptUtil.getXorSha512Hash(this.server.getServerKey().getEncoded()) +
"\n\nFalls der Server trotzdem vertrauenswürdig wirkt, kann die Server-Identifizierung\nin den Einstellungen von '" + this.server.getName() + "' zurückgesetzt werden.");
return;
}
this.startEncryption(secret, pubkey, token);
this.startEncryption(tempKey);
}
private void startEncryption(SecretKey secret, PublicKey pubkey, byte[] token) {
private void startEncryption(PublicKey serverKey) {
this.state = LoginState.CHALLENGE;
this.connection.sendPacket(new LPacketStartEncrypt(secret, pubkey, token), new GenericFutureListener < Future <? super Void >> () {
this.connection.sendPacket(new LPacketStartEncrypt(this.tempKeys.getPublic()), new GenericFutureListener < Future <? super Void >> () {
public void operationComplete(Future <? super Void > u) throws Exception {
ClientLoginHandler.this.connection.startEncryption(secret);
ClientLoginHandler.this.connection.startEncryption(EncryptUtil.makeKeyAgreement(ClientLoginHandler.this.tempKeys.getPrivate(), serverKey));
ClientLoginHandler.this.token = new byte[32];
TOKEN_RNG.nextBytes(ClientLoginHandler.this.token);
ClientLoginHandler.this.connection.sendPacket(new LPacketChallenge(pubkey, ClientLoginHandler.this.token));
ClientLoginHandler.this.connection.sendPacket(new LPacketChallenge(ClientLoginHandler.this.token));
}
});
}
@ -116,7 +115,7 @@ public class ClientLoginHandler implements IClientLoginHandler {
this.connection.closeChannel("Unerwartetes Beweis-Paket");
return;
}
if(!Arrays.equals(this.token, packet.getToken())) {
if(!packet.verifyToken(this.server.getServerKey(), this.token)) {
this.connection.closeChannel("Fehlerhaftes Beweis-Token");
return;
}
@ -189,7 +188,7 @@ public class ClientLoginHandler implements IClientLoginHandler {
return;
}
this.state = LoginState.AUTHENTICATING;
this.connection.sendPacket(new LPacketResponse(packet.getToken(this.server.getKeypair().getPrivate())));
this.connection.sendPacket(new LPacketResponse(this.server.getKeypair().getPrivate(), packet.getToken()));
}
public void handleLoginSuccess(RPacketLoginSuccess packet)