Bladeren bron

Save 06-11-2025 Working Chat directly and via Relay-Client, (Bug): CypherText in ChatWindow, Sending Files in someway implemented

Jan 2 maanden geleden
bovenliggende
commit
58f863f0ca

+ 5 - 9
src/main/java/config/Config.java

@@ -1,20 +1,19 @@
 package config;
 
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Properties;
 
 public class Config {
     public static boolean ENCRYPT_ON_SAVE = true;
-    public static boolean USE_RELAY = true;
-    public static String RELAY_SERVER_IP = "192.168.2.177"; // Default IP
+    public static boolean USE_RELAY = false;
+    public static String RELAY_SERVER_IP = "0.0.0.0"; // Default IP
     public static int RELAY_SERVER_PORT = 12345;
-    public static String APPEARANCE_NAME = "Jan";
-    // Method to save configuration to file (optional)
+    public static int DIRECT_CHAT_PORT = 54321;
+    public static String APPEARANCE_NAME = "Tester";
+
     public static void saveConfig() {
-        // Implementation to save settings to a properties file or database
         Properties props = new Properties();
         props.setProperty("RELAY_SERVER_IP", RELAY_SERVER_IP);
         props.setProperty("RELAY_SERVER_PORT", String.valueOf(RELAY_SERVER_PORT));
@@ -24,14 +23,11 @@ public class Config {
 
         try (FileOutputStream out = new FileOutputStream("config.properties")) {
             props.store(out, "Chat Application Configuration");
-        } catch (FileNotFoundException e) {
-            e.printStackTrace();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
 
-    // Method to load configuration from file (optional)
     public static void loadConfig() {
         try {
             Properties props = new Properties();

+ 18 - 0
src/main/java/crypto/KeyManager.java

@@ -1,6 +1,8 @@
 package crypto;
 
 import java.security.*;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
 import java.util.UUID;
 
 public class KeyManager {
@@ -15,6 +17,22 @@ public class KeyManager {
         return keyPair.getPublic();
     }
 
+    public static String publicKeyToString(PublicKey publicKey) {
+        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
+    }
+
+    public static PublicKey stringToPublicKey(String keyAsString) {
+        byte[] decodedKey = Base64.getDecoder().decode(keyAsString);
+        X509EncodedKeySpec spec = new X509EncodedKeySpec(decodedKey);
+        try{
+            KeyFactory keyFactory = KeyFactory.getInstance("RSA"); // Change "RSA" to your key type if different.
+            return keyFactory.generatePublic(spec);
+        }catch (Exception e){
+            e.printStackTrace();
+            System.out.println("Couldn't convert String to Public Key!");
+        }
+        return null;
+    }
     public static PrivateKey getPrivateKey() {
         return keyPair.getPrivate();
     }

+ 6 - 6
src/main/java/model/AuthMessage.java

@@ -1,18 +1,18 @@
 package model;
 
 import java.io.Serializable;
+import java.security.PublicKey;
 
 public class AuthMessage implements Serializable {
     private final String name;
-    private final String uuid;
+    private PublicKey publicKey;
 
-    public AuthMessage(String UUID, String appearanceName){
-        this.uuid = UUID;
+    public AuthMessage(String appearanceName, PublicKey publicKey){
         this.name = appearanceName;
+        this.publicKey = publicKey;
     }
-
-    public String getUuid() {
-        return uuid;
+    public PublicKey getPublicKey(){
+        return publicKey;
     }
 
     public String getName() {

+ 29 - 5
src/main/java/model/Chat.java

@@ -2,19 +2,39 @@ package model;
 
 import crypto.KeyManager;
 
+import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.util.*;
 
 public class Chat {
-    private String targetUUID;
+    private PublicKey targetKey;
     private List<Message> messages = new ArrayList<>();
     private boolean isUsingRelay;
     private String relayAddress;
+    private int port;
 
-    public Chat(boolean useRelay, String addressOrIp, String targetUUID) {
-        this.targetUUID = targetUUID;
+    /*
+    public Chat(boolean useRelay, String addressOrIp, PublicKey targetKey) {
+        this.targetKey = targetKey;
         this.isUsingRelay = useRelay;
         this.relayAddress = addressOrIp;
     }
+     */
+    public Chat(boolean useRelay, String addressOrIp, int port, PublicKey targetKey) {
+        this.targetKey = targetKey;
+        this.isUsingRelay = useRelay;
+        this.relayAddress = addressOrIp;
+        this.port = port;
+    }
+
+    public void decryptWholeChat(PrivateKey privateKey, PublicKey publicKey) throws Exception {
+        for(Message message: messages){
+            if(message.getSenderKey().equals(targetKey)){
+                message.decrypt(privateKey, publicKey);
+            }
+        }
+    }
+
 
     public List<Message> getMessages(){
         return messages;
@@ -31,7 +51,11 @@ public class Chat {
         return relayAddress;
     }
 
-    public String getTargetUUID() {
-        return targetUUID.toString();
+    public PublicKey getTargetKey() {
+        return targetKey;
+    }
+
+    public int getPort() {
+        return port;
     }
 }

+ 61 - 0
src/main/java/model/FileTransfer.java

@@ -0,0 +1,61 @@
+package model;
+
+import crypto.CryptoUtils;
+
+import java.io.Serializable;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.UUID;
+
+public class FileTransfer implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private UUID fileUUID;
+    private int index;
+    private int maxIndex;
+    private String encryptedData; // Base64-encoded, verschlüsselter Datenstring
+    private PublicKey senderKey;
+
+    public FileTransfer(UUID fileUUID, int index, int maxIndex, String data, PublicKey key) throws Exception {
+        this.fileUUID = fileUUID;
+        this.index = index;
+        this.maxIndex = maxIndex;
+        this.senderKey = key;
+        // Verschlüsseln beim Erstellen
+        this.encryptedData = CryptoUtils.encrypt(data, key);
+    }
+
+    public UUID getFileUUID() {
+        return fileUUID;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public int getMaxIndex() {
+        return maxIndex;
+    }
+
+    public PublicKey getSenderKey() {
+        return senderKey;
+    }
+
+    public String getEncryptedData() {
+        return encryptedData;
+    }
+
+    /** Entschlüsselt den verschlüsselten Inhalt mit einem PrivateKey. */
+    public String decryptData(PrivateKey privateKey) throws Exception {
+        return CryptoUtils.decrypt(encryptedData, privateKey);
+    }
+
+    @Override
+    public String toString() {
+        return "FileTransfer{" +
+                "UUID=" + fileUUID +
+                ", index=" + index +
+                ", maxIndex=" + maxIndex +
+                '}';
+    }
+}

+ 46 - 28
src/main/java/model/Message.java

@@ -2,59 +2,77 @@ package model;
 
 import crypto.CryptoUtils;
 
-import javax.crypto.Cipher;
 import java.io.Serializable;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.util.Base64;
 
 public class Message implements Serializable {
-    private String receiverUUID;
     private PublicKey receiverKey;
-
-    private String senderId;
     private PublicKey senderKey;
-
+    private boolean directMessage;
+    private String fromIp;
     private long timestamp;
-    private String content;
+    private String contentForReceiver;
+    private String contentForSender;
     private boolean encrypted = false;
+    private int usingPort;
 
-
-    public Message(String senderUUID, String receiverUUID, String content) {
-        this.senderId = senderUUID;
-        this.content = content;
-        this.receiverUUID = receiverUUID;
-        this.timestamp = System.currentTimeMillis();
-    }
     public Message(PublicKey senderKey, PublicKey receiverKey, String content) {
         this.senderKey = senderKey;
-        this.content = content;
+        this.contentForReceiver = content;
+        this.contentForSender = content;
         this.receiverKey = receiverKey;
         this.timestamp = System.currentTimeMillis();
     }
+    public boolean didISendThis(PublicKey key){
+        return senderKey.equals(key);
+    }
 
-    public void encrypt(PublicKey key) throws Exception {
-        if(!encrypted) {
-            this.content = CryptoUtils.encrypt(content, key);
+    public void encrypt() throws Exception {
+        if (!encrypted) {
+            this.contentForSender = CryptoUtils.encrypt(contentForSender, senderKey);
+            this.contentForReceiver = CryptoUtils.encrypt(contentForReceiver, receiverKey);
             encrypted = true;
         }
     }
 
-    public void decrypt(PrivateKey key) throws Exception {
-        if(encrypted){
-            this.content = CryptoUtils.decrypt(content, key);
-            encrypted = false;
+    public void decrypt(PrivateKey privateKey, PublicKey publicKey) throws Exception {
+        if (!encrypted) {
+            if (didISendThis(publicKey)) {
+                this.contentForSender = CryptoUtils.decrypt(contentForSender, privateKey);
+            } else {
+                this.contentForReceiver =CryptoUtils.decrypt(contentForReceiver, privateKey);
+            }
         }
     }
 
-    public String getReceiverUUID(){
-        return receiverUUID;
+    public PublicKey getReceiverKey(){
+        return receiverKey;
+    }
+
+    public PublicKey getSenderKey(){
+        return senderKey;
+    }
+    public String getContentForReceiver(){
+        return contentForReceiver;
+    }
+    public String getContentForSender(){
+        return contentForSender;
+    }
+    public void setDirectMessage(String fromIp, int port){
+        directMessage = true;
+        this.fromIp = fromIp;
+        this.usingPort = port;
+    }
+
+    public int getUsingPort() {
+        return usingPort;
     }
 
-    public String getSenderUUID(){
-        return senderId;
+    public String getFromIp(){
+        return fromIp;
     }
-    public String getContent(){
-        return content;
+    public boolean isDirectMessage(){
+        return directMessage;
     }
 }

+ 79 - 0
src/main/java/net/Handshake.java

@@ -0,0 +1,79 @@
+package net;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+
+public class Handshake {
+    private static final String AES = "AES";
+    private static final String AES_CIPHER_ALGORITHM
+            = "AES/CBC/PKCS5PADDING";
+
+    private PublicKey handShakeInitiator, handShakeAcceptor;
+    private SecretKey secretKey;
+    private String secretKeyStr;
+    public Handshake(PublicKey initiator, PublicKey acceptor) throws Exception {
+        this.handShakeInitiator = initiator;
+        this.handShakeAcceptor = acceptor;
+        this.secretKey = createAESKey();
+    }
+
+    byte[] initializationVector = createInitializationVector();
+
+    public static SecretKey createAESKey() throws Exception {
+        SecureRandom securerandom = new SecureRandom();
+        KeyGenerator keygenerator = KeyGenerator.getInstance(AES);
+
+        keygenerator.init(256, securerandom);
+        SecretKey key = keygenerator.generateKey();
+
+        return key;
+    }
+
+    // Function to initialize a vector
+    // with an arbitrary value
+    public static byte[] createInitializationVector()
+    {
+
+        // Used with encryption
+        byte[] initializationVector = new byte[16];
+        SecureRandom secureRandom = new SecureRandom();
+        secureRandom.nextBytes(initializationVector);
+        return initializationVector;
+    }
+
+    // This function takes plaintext,
+    // the key with an initialization
+    // vector to convert plainText
+    // into CipherText.
+    public static byte[] do_AESEncryption(String plainText, SecretKey secretKey) throws Exception {
+        byte[] initializationVector = createInitializationVector();
+        Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
+
+        IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector);
+
+        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
+
+        return cipher.doFinal(plainText.getBytes());
+    }
+
+    // This function performs the
+    // reverse operation of the
+    // do_AESEncryption function.
+    // It converts ciphertext to
+    // the plaintext using the key.
+    public static String do_AESDecryption(byte[] cipherText, SecretKey secretKey, byte[] initializationVector) throws Exception {
+        Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
+
+        IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector);
+
+        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
+
+        byte[] result = cipher.doFinal(cipherText);
+
+        return new String(result);
+    }
+}

+ 10 - 9
src/main/java/net/RelayClient.java

@@ -1,23 +1,25 @@
 package net;
 
 import config.Config;
+import crypto.KeyManager;
 import model.AuthMessage;
 import model.Message;
 
 import java.io.*;
 import java.net.*;
+import java.security.PublicKey;
 
 public class RelayClient {
     private Socket socket;
-    private ObjectOutputStream out; // Changed from PrintWriter
+    private ObjectOutputStream out;
     private ObjectInputStream in;
 
-    public RelayClient(String serverIp, String myId, MessageReceiver receiver) throws IOException {
+    public RelayClient(String serverIp, PublicKey myPublicKey, MessageReceiver messageReceiver) throws IOException {
         socket = new Socket(serverIp, 12345);
-        out = new ObjectOutputStream(socket.getOutputStream()); // Direct ObjectOutputStream
+        out = new ObjectOutputStream(socket.getOutputStream());
         in = new ObjectInputStream(socket.getInputStream());
 
-        AuthMessage auth = new AuthMessage(myId, Config.APPEARANCE_NAME);
+        AuthMessage auth = new AuthMessage(Config.APPEARANCE_NAME, myPublicKey);
         System.out.println("Sending auth: " + auth);
         send(auth);
 
@@ -26,12 +28,11 @@ public class RelayClient {
                 Object msg;
                 while ((msg = in.readObject()) != null) {
                     if(msg instanceof Message){
-                        receiver.onMessage((Message) msg);
+                        ((Message) msg).decrypt(KeyManager.getPrivateKey(), KeyManager.getPublicKey());
+                        messageReceiver.onMessage((Message) msg);
                     }
                 }
-            } catch (IOException e) {
-                e.printStackTrace();
-            } catch (ClassNotFoundException e) {
+            } catch (Exception e) {
                 e.printStackTrace();
             }
         }).start();
@@ -40,7 +41,7 @@ public class RelayClient {
     public void send(Object msg) {
         try {
             out.writeObject(msg);
-            out.flush(); // Important: flush after writing
+            out.flush();
             System.out.println("Sent: " + msg);
         } catch (IOException e) {
             e.printStackTrace();

+ 11 - 9
src/main/java/net/RelayServer.java

@@ -5,10 +5,11 @@ import model.Message;
 
 import java.net.*;
 import java.io.*;
+import java.security.PublicKey;
 import java.util.concurrent.*;
 
 public class RelayServer extends Thread {
-    private final ConcurrentHashMap<String, ObjectOutputStream> clients = new ConcurrentHashMap<>(); // Store ObjectOutputStream instead of Socket
+    private final ConcurrentHashMap<PublicKey, ObjectOutputStream> clients = new ConcurrentHashMap<>(); // Store ObjectOutputStream instead of Socket
     public void run() {
         try (ServerSocket server = new ServerSocket(12345)) {
             System.out.println("Relay Server läuft auf Port 12345...");
@@ -25,30 +26,31 @@ public class RelayServer extends Thread {
         try {
             System.out.println("New connection from: " + socket.getInetAddress());
             ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
-            ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); // Create ObjectOutputStream for responses
+            ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
 
             Object input = in.readObject();
 
 
             if(input instanceof AuthMessage){
                 AuthMessage auth = (AuthMessage) input;
-                String clientId = auth.getUuid();
                 String clientName = auth.getName();
-                clients.put(clientId, out); // Store the output stream
-                System.out.println("Received auth for: " + clientName + ",\n with UUID: " + clientId);
+                PublicKey publicKey = auth.getPublicKey();
+
+                clients.put(publicKey, out);
+                System.out.println("Received auth for: " + clientName + ",\n with PublicKey: " + publicKey);
 
                 Object msg;
                 while ((msg = in.readObject()) != null) {
                     System.out.println("Received message: " + msg);
                     if(msg instanceof Message){
-                        String receiverId = ((Message) msg).getReceiverUUID();
-                        ObjectOutputStream targetOut = clients.get(receiverId);
+                        PublicKey receiverKey = ((Message) msg).getReceiverKey();
+                        ObjectOutputStream targetOut = clients.get(receiverKey);
                         if (targetOut != null) {
                             targetOut.writeObject(msg);
                             targetOut.flush();
-                            System.out.println("Relayed message from " + clientId + " to " + receiverId + ": " + ((Message) msg).getContent());
+                            //System.out.println("Relayed message from " + publicKey + " to " + receiverKey + ": " + ((Message) msg).getContent());
                         } else {
-                            System.out.println("Target client not found: " + receiverId);
+                            System.out.println("Target client not found: " + receiverKey);
                         }
                     }
                 }

+ 39 - 7
src/main/java/net/direct/DirectClient.java

@@ -1,19 +1,51 @@
 package net.direct;
 
 
+import config.Config;
+import crypto.KeyManager;
+import model.Message;
+import net.RelayClient;
+
 import java.io.*;
 import java.net.*;
 
 public class DirectClient {
-    private final Socket socket;
-    private final PrintWriter out;
+    private Socket socket;
+    private ObjectOutputStream out;
+    private ObjectInputStream in;
+
+    public DirectClient(String ip, int port, RelayClient.MessageReceiver messageReceiver) throws IOException {
+        socket = new Socket(ip, port);
+        out = new ObjectOutputStream(socket.getOutputStream());
+        in = new ObjectInputStream(socket.getInputStream());
 
-    public DirectClient(String ip) throws IOException {
-        socket = new Socket(ip, 9876);
-        out = new PrintWriter(socket.getOutputStream(), true);
+        new Thread(() -> {
+            System.out.println("Startet DirectClient! Connecting to '" + ip + "' on Port: "+ port);
+            try {
+                Object msg;
+                while ((msg = in.readObject()) != null) {
+                    if(msg instanceof Message){
+                        ((Message) msg).decrypt(KeyManager.getPrivateKey(), KeyManager.getPublicKey());
+                        messageReceiver.onMessage((Message) msg);
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }).start();
     }
 
-    public void send(String msg) {
-        out.println(msg);
+    public void send(Object msg) {
+        try {
+            if(msg instanceof Message){
+                ((Message) msg).setDirectMessage("0.0.0.0", Config.DIRECT_CHAT_PORT);
+            }
+            out.writeObject(msg);
+            out.flush();
+            System.out.println("Sent: " + msg);
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
     }
 }

+ 35 - 15
src/main/java/net/direct/DirectServer.java

@@ -2,33 +2,53 @@ package net.direct;
 
 import java.io.*;
 import java.net.*;
-import ui.ChatWindow;
+
+import config.Config;
+import model.Message;
+import net.RelayClient;
 
 public class DirectServer extends Thread {
-    private final ChatWindow chatWindow;
+    private RelayClient.MessageReceiver messageReceiver;
 
-    public DirectServer(ChatWindow window) {
-        this.chatWindow = window;
+    public DirectServer(RelayClient.MessageReceiver messageReceiver) {
+        this.messageReceiver = messageReceiver;
     }
 
     public void run() {
-        try (ServerSocket server = new ServerSocket(9876)) {
-            while (true) {
-                Socket client = server.accept();
-                new Thread(() -> handleClient(client)).start();
+        startServer();
+    }
+
+    private void startServer(){
+        int port = Config.DIRECT_CHAT_PORT;
+        while(port < 99999){
+            try (ServerSocket server = new ServerSocket(port)) {
+                System.out.println("Started local Server on Port: " + port +" !");
+                while (true) {
+                    Socket client = server.accept();
+                    new Thread(() -> handleClient(client)).start();
+                }
+            } catch (IOException e) {
+                System.out.println("Port already in use! trying a new one...");
             }
-        } catch (IOException e) {
-            e.printStackTrace();
+            port++;
         }
+
+
     }
 
     private void handleClient(Socket socket) {
-        try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
-            String msg;
-            while ((msg = in.readLine()) != null) {
-                //chatWindow.receiveMessage("Peer: " + msg);
+        try {
+            ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
+            ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
+
+            Object msg;
+            while ((msg = in.readObject()) != null) {
+                System.out.println("Received message: " + msg);
+                if(msg instanceof Message){
+                    messageReceiver.onMessage((Message) msg);
+                }
             }
-        } catch (IOException e) {
+        } catch (IOException | ClassNotFoundException e) {
             e.printStackTrace();
         }
     }

+ 151 - 36
src/main/java/ui/ChatWindow.java

@@ -1,31 +1,41 @@
 package ui;
 
 import crypto.KeyManager;
-import model.AuthMessage;
 import model.Chat;
+import model.FileTransfer;
 import model.Message;
 import net.RelayClient;
 import net.direct.DirectClient;
-import net.direct.DirectServer;
 
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.security.PublicKey;
+
+import java.io.File;
+import java.util.List;
 
 public class ChatWindow extends JFrame implements RelayClient.MessageReceiver {
+    private Chat chat;
+    private MainWindow mainWindow;
     private String targetName;
     private JTextArea chatArea;
     private JTextField inputField;
-    private boolean useRelay;
-    private String targetUUID;
+    private PublicKey targetKey;
     private DirectClient directClient;
     private RelayClient relayClient;
+    private FileSplitMerger fileSplitMerger; // Neu
 
-    public ChatWindow(String targetName, Chat chat) {
-        this.useRelay = chat.isUsingRelay();
-        this.targetUUID = chat.getTargetUUID();
+    public ChatWindow(String targetName, Chat chat, MainWindow mainWindow) {
+        this.targetKey = chat.getTargetKey();
         this.targetName = targetName;
+        this.mainWindow = mainWindow;
+        this.chat = chat;
+        this.fileSplitMerger = new FileSplitMerger(); // Neu
+
         setTitle("Chat mit " + targetName);
         setSize(400, 500);
         setLocationRelativeTo(null);
@@ -34,34 +44,38 @@ public class ChatWindow extends JFrame implements RelayClient.MessageReceiver {
         chatArea = new JTextArea();
         chatArea.setEditable(false);
         inputField = new JTextField();
+
         JButton sendBtn = new JButton("Senden");
+        JButton fileBtn = new JButton("📎 Datei"); // 🔹 Neuer Button für Datei-Upload
+
         JPanel inputPanel = new JPanel(new BorderLayout());
+
+        // Panel für Buttons rechts nebeneinander
+        JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 5, 0));
+        buttonPanel.add(fileBtn);
+        buttonPanel.add(sendBtn);
+
         inputPanel.add(inputField, BorderLayout.CENTER);
-        inputPanel.add(sendBtn, BorderLayout.EAST);
+        inputPanel.add(buttonPanel, BorderLayout.EAST);
+
         add(new JScrollPane(chatArea), BorderLayout.CENTER);
         add(inputPanel, BorderLayout.SOUTH);
         setVisible(true);
 
-        setupMessages(chat);
-        // Create the send action that can be reused
+        try {
+            setupMessages(chat);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
         Runnable sendAction = () -> {
             String msg = inputField.getText();
             if (!msg.isEmpty()) {
-                inputField.setText("");
-                chatArea.append("Du: " + msg + "\n");
-                Message toSend = new Message(KeyManager.getMyUUID().toString(), targetUUID, msg);
-
-                chat.addMessage(toSend);
-                if (useRelay) {
-                    relayClient.send(toSend);
-                } else {
-                    directClient.send(msg);
-                }
+                sendMessage(msg, chat);
             }
         };
 
         sendBtn.addActionListener(e -> sendAction.run());
-
         inputField.addKeyListener(new KeyAdapter() {
             @Override
             public void keyPressed(KeyEvent e) {
@@ -71,9 +85,98 @@ public class ChatWindow extends JFrame implements RelayClient.MessageReceiver {
             }
         });
 
-        if (useRelay) {
+        // 🔹 Datei senden Aktion
+        fileBtn.addActionListener(e -> selectAndSendFile());
+
+        setupHandlers(chat);
+        setupOnClose();
+    }
+
+    /** 🔹 Öffnet Datei-Dialog, spaltet und sendet Datei über Socket */
+    private void selectAndSendFile() {
+        JFileChooser chooser = new JFileChooser();
+        chooser.setDialogTitle("Wähle eine Datei zum Senden aus");
+        int result = chooser.showOpenDialog(this);
+
+        if (result == JFileChooser.APPROVE_OPTION) {
+            File selectedFile = chooser.getSelectedFile();
+            chatArea.append("📤 Sende Datei: " + selectedFile.getName() + "\n");
+
+            try {
+                // Datei in Stücke teilen
+                List<FileTransfer> parts = fileSplitMerger.splitFile(
+                        selectedFile,
+                        1024 * 512, // 512 KB Stückgröße
+                        targetKey,
+                        KeyManager.getPublicKey()
+                );
+
+                // Alle Teile verschicken
+                for (FileTransfer ft : parts) {
+                    if (chat.isUsingRelay()) {
+                        relayClient.send(ft);
+                    } else {
+                        directClient.send(ft);
+                    }
+                }
+
+                chatArea.append("✅ Datei erfolgreich in " + parts.size() + " Teile aufgeteilt und gesendet.\n");
+
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                JOptionPane.showMessageDialog(this,
+                        "Fehler beim Senden der Datei:\n" + ex.getMessage(),
+                        "Dateiübertragungsfehler", JOptionPane.ERROR_MESSAGE);
+            }
+        }
+    }
+
+    public void updateChat(Chat newChat) throws Exception {
+        chatArea.removeAll();
+        this.chat = newChat;
+        setupMessages(newChat);
+    }
+
+    public void updateChat() throws Exception {
+        chatArea.removeAll();
+        setupMessages(chat);
+    }
+
+    private void setupOnClose() {
+        ChatWindow closedWindow = this;
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent e) {
+                mainWindow.closedWindow(closedWindow);
+                e.getWindow().dispose();
+            }
+        });
+    }
+
+    private void sendMessage(String msg, Chat chat) {
+        inputField.setText("");
+        Message toSend = new Message(KeyManager.getPublicKey(), targetKey, msg);
+
+        try {
+            toSend.encrypt();
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.out.println("Something went wrong with the Encryption of this message!");
+        }
+        if (chat.isUsingRelay()) {
+            relayClient.send(toSend);
+        } else {
+            directClient.send(toSend);
+        }
+        chat.addMessage(toSend);
+        chatArea.append("Du: " + msg + "\n");
+    }
+
+    private void setupHandlers(Chat chat) {
+        System.out.println("Setup handlers: relay=" + chat.isUsingRelay() + ", addr=" + chat.getRelayAddress() + ", port=" + chat.getPort());
+        if (chat.isUsingRelay()) {
             try {
-                relayClient = new RelayClient(chat.getRelayAddress(), KeyManager.getMyUUID().toString(), this);
+                relayClient = new RelayClient(chat.getRelayAddress(), KeyManager.getPublicKey(), this);
             } catch (Exception e) {
                 e.printStackTrace();
                 JOptionPane.showMessageDialog(this, "Verbindung zum Relay-Server fehlgeschlagen: " + e.getMessage(),
@@ -81,8 +184,7 @@ public class ChatWindow extends JFrame implements RelayClient.MessageReceiver {
             }
         } else {
             try {
-                directClient = new DirectClient(chat.getRelayAddress());
-                new DirectServer(this).start(); // Für eingehende Nachrichten
+                directClient = new DirectClient(chat.getRelayAddress(), chat.getPort(), this::onMessage);
             } catch (Exception e) {
                 e.printStackTrace();
                 JOptionPane.showMessageDialog(this, "Direkte Verbindung fehlgeschlagen: " + e.getMessage(),
@@ -91,22 +193,35 @@ public class ChatWindow extends JFrame implements RelayClient.MessageReceiver {
         }
     }
 
-    private void setupMessages(Chat chat) {
-        for(Message msg : chat.getMessages()){
-            if(msg.getSenderUUID().equals(targetUUID)){
-                chatArea.append(targetName + ": " + msg.getContent() + "\n");
-            }else if(msg.getReceiverUUID().equals(targetUUID)){
-                chatArea.append("Du: " + msg.getContent() + "\n");
-            }else{
-                chatArea.append("Something went wrong whilst loading this message! \n");
+    private void setupMessages(Chat chat) throws Exception {
+        chat.decryptWholeChat(KeyManager.getPrivateKey(), KeyManager.getPublicKey());
+        for (Message msg : chat.getMessages()) {
+            if (msg.didISendThis(KeyManager.getPublicKey())) {
+                chatArea.append("Du: " + msg.getContentForSender() + "\n");
+            } else {
+                chatArea.append(targetName + ": " + msg.getContentForReceiver() + "\n");
             }
         }
     }
 
     @Override
     public void onMessage(Message msg) {
-        //System.out.println("Empfangen: " + msg.getContent());
-        //String username = msg.getSenderUUID();
-        SwingUtilities.invokeLater(() -> chatArea.append(targetName + ": " + msg.getContent() + "\n"));
+        mainWindow.onMessage(msg);
+        SwingUtilities.invokeLater(() -> chatArea.append(targetName + ": " + msg.getContentForSender() + "\n"));
+    }
+
+    public Chat getChat() {
+        return chat;
+    }
+
+    public void addMessage(Message msg) {
+        try {
+            msg.decrypt(KeyManager.getPrivateKey(), KeyManager.getPublicKey());
+            chat.addMessage(msg);
+            updateChat();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
     }
 }
+

+ 20 - 9
src/main/java/ui/EditChatWindow.java

@@ -1,5 +1,7 @@
 package ui;
 
+import config.Config;
+import crypto.KeyManager;
 import model.Chat;
 import model.Message;
 
@@ -24,8 +26,9 @@ public class EditChatWindow extends JDialog {
 
         // Create form fields with current values
         JTextField nameField = new JTextField(currentName);
-        JTextField uuidField = new JTextField(currentChat.getTargetUUID());
+        JTextField publicKeyField = new JTextField(KeyManager.publicKeyToString(currentChat.getTargetKey()));
         JTextField relayAddressField = new JTextField(currentChat.getRelayAddress());
+        JTextField usingPort = new JTextField(""+currentChat.getPort());
         JCheckBox useRelayCheckbox = new JCheckBox("Relay verwenden", currentChat.isUsingRelay());
 
         // Enable/disable relay address field based on checkbox
@@ -42,15 +45,18 @@ public class EditChatWindow extends JDialog {
         add(new JLabel("Chat-Name:"));
         add(nameField);
 
-        add(new JLabel("Ziel-UUID:"));
-        add(uuidField);
+        add(new JLabel("Ziel-PublicKey:"));
+        add(publicKeyField);
 
         add(new JLabel("Relay verwenden:"));
         add(useRelayCheckbox);
 
-        add(new JLabel("Relay Server Adresse:"));
+        add(new JLabel("Relay Server/ Peer Ip Adresse:"));
         add(relayAddressField);
 
+        add(new JLabel("Relay Server/ Peer Port:"));
+        add(usingPort);
+
         add(saveBtn);
         add(cancelBtn);
 
@@ -60,12 +66,14 @@ public class EditChatWindow extends JDialog {
         // Save button action
         saveBtn.addActionListener(e -> {
             String newName = nameField.getText().trim();
-            String uuid = uuidField.getText().trim();
+            String publicKeyString = publicKeyField.getText().trim();
             String relayAddress = relayAddressField.getText().trim();
+            String usingPortText = usingPort.getText().trim();
+            int port = Config.RELAY_SERVER_PORT;
             boolean useRelay = useRelayCheckbox.isSelected();
 
-            if (newName.isEmpty() || uuid.isEmpty()) {
-                JOptionPane.showMessageDialog(this, "Chat-Name und UUID dürfen nicht leer sein!", "Fehler", JOptionPane.ERROR_MESSAGE);
+            if (newName.isEmpty() || publicKeyString.isEmpty()) {
+                JOptionPane.showMessageDialog(this, "Chat-Name und PublicKey dürfen nicht leer sein!", "Fehler", JOptionPane.ERROR_MESSAGE);
                 return;
             }
 
@@ -73,9 +81,12 @@ public class EditChatWindow extends JDialog {
                 JOptionPane.showMessageDialog(this, "Bitte geben Sie eine Relay Server Adresse ein!", "Fehler", JOptionPane.ERROR_MESSAGE);
                 return;
             }
+            if(!usingPortText.isEmpty()){
+                port = Integer.parseInt(usingPortText);
+            }
+
 
-            // Create updated chat object
-            Chat updatedChat = new Chat(useRelay, relayAddress, uuid);
+            Chat updatedChat = new Chat(useRelay, relayAddress, port, KeyManager.stringToPublicKey(publicKeyString));
 
             for(Message msg : originalChat.getMessages()){
                 updatedChat.addMessage(msg);

+ 112 - 0
src/main/java/ui/FileSplitMerger.java

@@ -0,0 +1,112 @@
+package ui;
+import model.FileTransfer;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.dnd.*;
+import java.awt.datatransfer.*;
+import java.io.*;
+import java.util.List;
+
+import javax.swing.*;
+import java.io.*;
+import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.util.*;
+
+public class FileSplitMerger {
+
+    // Zwischenspeicher für eingehende Fragmente
+    private final Map<UUID, List<FileTransfer>> filePartsBuffer = new HashMap<>();
+
+    /**
+     * Teilt eine Datei in kleine Stücke und erstellt verschlüsselte FileTransfer-Objekte.
+     *
+     * @param file Datei, die gesendet werden soll
+     * @param chunkSize Größe pro Teil in Bytes (z. B. 1024*1024 = 1MB)
+     * @param receiverKey Der PublicKey des Empfängers
+     * @param senderKey   Der PublicKey des Senders (für Weiterleitung über Relay)
+     * @return Liste von FileTransfer-Objekten
+     */
+    public List<FileTransfer> splitFile(File file, int chunkSize, PublicKey receiverKey, PublicKey senderKey) throws Exception {
+        List<FileTransfer> parts = new ArrayList<>();
+        byte[] fileBytes = readFile(file);
+        UUID fileUUID = UUID.randomUUID();
+
+        int totalParts = (int) Math.ceil((double) fileBytes.length / chunkSize);
+
+        for (int i = 0; i < totalParts; i++) {
+            int start = i * chunkSize;
+            int end = Math.min(start + chunkSize, fileBytes.length);
+            byte[] chunk = Arrays.copyOfRange(fileBytes, start, end);
+            String dataString = Base64.getEncoder().encodeToString(chunk);
+            parts.add(new FileTransfer(fileUUID, i, totalParts - 1, dataString, receiverKey));
+        }
+
+        return parts;
+    }
+
+    /**
+     * Fügt empfangene FileTransfer-Objekte in den Zwischenspeicher ein.
+     * Wenn alle Teile vorhanden sind, wird die Datei zusammengefügt und gespeichert.
+     */
+    public void addReceivedPart(FileTransfer part, PrivateKey privateKey, File saveDirectory) {
+        filePartsBuffer.putIfAbsent(part.getFileUUID(), new ArrayList<>());
+        List<FileTransfer> parts = filePartsBuffer.get(part.getFileUUID());
+        parts.add(part);
+
+        // Prüfe, ob vollständig
+        if (parts.size() == part.getMaxIndex() + 1) {
+            try {
+                mergeAndSave(parts, privateKey, saveDirectory);
+                filePartsBuffer.remove(part.getFileUUID());
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        } else {
+            // Prüfen, ob Lücken bestehen
+            List<Integer> receivedIndexes = new ArrayList<>();
+            for (FileTransfer ft : parts) receivedIndexes.add(ft.getIndex());
+
+            for (int i = 0; i <= part.getMaxIndex(); i++) {
+                if (!receivedIndexes.contains(i)) {
+                    JOptionPane.showMessageDialog(null,
+                            "Es fehlt noch Teil " + i + " der Datei mit UUID: " + part.getFileUUID(),
+                            "Fehlender Dateiabschnitt", JOptionPane.WARNING_MESSAGE);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Fügt alle FileTransfer-Objekte zusammen, entschlüsselt sie und speichert die Datei.
+     */
+    private void mergeAndSave(List<FileTransfer> parts, PrivateKey privateKey, File saveDirectory) throws Exception {
+        parts.sort(Comparator.comparingInt(FileTransfer::getIndex));
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        for (FileTransfer part : parts) {
+            String decryptedBase64 = part.decryptData(privateKey);
+            byte[] chunk = Base64.getDecoder().decode(decryptedBase64);
+            outputStream.write(chunk);
+        }
+
+        File outputFile = new File(saveDirectory, "merged_" + parts.get(0).getFileUUID() + ".bin");
+        try (FileOutputStream fos = new FileOutputStream(outputFile)) {
+            fos.write(outputStream.toByteArray());
+        }
+
+        JOptionPane.showMessageDialog(null,
+                "Datei erfolgreich zusammengefügt:\n" + outputFile.getAbsolutePath(),
+                "Fertig!", JOptionPane.INFORMATION_MESSAGE);
+    }
+
+    private byte[] readFile(File file) throws IOException {
+        try (FileInputStream fis = new FileInputStream(file)) {
+            return fis.readAllBytes();
+        }
+    }
+}
+

+ 45 - 35
src/main/java/ui/MainWindow.java

@@ -2,16 +2,18 @@ package ui;
 
 import config.Config;
 import crypto.KeyManager;
-import model.AuthMessage;
 import model.Chat;
 import model.Message;
 import net.RelayClient;
+import net.direct.DirectServer;
 
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
 import java.util.HashMap;
 
 public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
@@ -21,13 +23,14 @@ public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
     private JList<String> chatList = new JList<>(chatListModel);
     private JScrollPane chatScrollPane = new JScrollPane(chatList);
     private RelayClient relayClient;
+    private DirectServer directServer;
+    private ArrayList<ChatWindow> openChatWindows = new ArrayList();
 
     public MainWindow() {
         try {
             KeyManager.init();
         } catch (Exception e) {
-            System.out.println("KeyManager error! Please try again.");
-            e.printStackTrace();
+            System.out.println("KeyManager error! Please try starting the Application again.");
         }
         Config.loadConfig();
 
@@ -43,32 +46,31 @@ public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
     private void setupRelayConnection() {
         if(Config.USE_RELAY){
             try {
-                this.relayClient = new RelayClient(Config.RELAY_SERVER_IP, KeyManager.getMyUUID().toString(), this);
+                this.relayClient = new RelayClient(Config.RELAY_SERVER_IP, KeyManager.getPublicKey(), this);
             } catch (IOException e) {
-                e.printStackTrace();
+                System.out.println("Couldn't connect to main Relay-Server! Try changing your Settings.");
             }
+        }else{
+            this.directServer = new DirectServer(this);
+            this.directServer.start();
         }
     }
 
     private void initializeWindow() {
-        setTitle("Chat App");
+        setTitle("Peer-to-Peer Chat");
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-        setSize(500, 600); // Increased width to accommodate buttons
+        setSize(500, 600);
         setLocationRelativeTo(null);
         add(mainPanel);
     }
 
     private void setupUI() {
-        // Clear and setup main panel
         mainPanel.removeAll();
 
-        // Create a panel for the chat list with buttons
         JPanel chatListPanel = new JPanel(new BorderLayout());
 
-        // Add chat list with scroll pane
         chatListPanel.add(chatScrollPane, BorderLayout.CENTER);
 
-        // Add instruction label
         JLabel instructionLabel = new JLabel("Doppelklick zum Oeffnen, Rechtsklick fuer Optionen");
         instructionLabel.setHorizontalAlignment(SwingConstants.CENTER);
         instructionLabel.setForeground(Color.GRAY);
@@ -76,11 +78,9 @@ public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
 
         mainPanel.add(chatListPanel, BorderLayout.CENTER);
 
-        // Create and add button panel
         JPanel buttonPanel = createButtonPanel();
         mainPanel.add(buttonPanel, BorderLayout.SOUTH);
 
-        // Refresh UI
         mainPanel.revalidate();
         mainPanel.repaint();
     }
@@ -97,35 +97,33 @@ public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
     }
 
     private void setupEventListeners() {
-        // New Chat Button
         JButton newChatBtn = (JButton) ((JPanel) mainPanel.getComponent(1)).getComponent(0);
         newChatBtn.addActionListener(e -> {
             NewChatDialog dialog = new NewChatDialog(this, (name, chat) -> {
                 chatHashMap.put(name, chat);
                 updateChatList();
-                new ChatWindow(name, chat);
+                new ChatWindow(name, chat, this);
             });
             dialog.setVisible(true);
         });
 
-        // Settings Button
         JButton settingsBtn = (JButton) ((JPanel) mainPanel.getComponent(1)).getComponent(1);
         settingsBtn.addActionListener(e -> new SettingsDialog(this).setVisible(true));
 
-        // Chat List Double-Click
+        MainWindow receiver = this;
         chatList.addMouseListener(new MouseAdapter() {
             public void mouseClicked(MouseEvent e) {
                 if (e.getClickCount() == 2) {
                     String selected = chatList.getSelectedValue();
                     if (selected != null) {
                         Chat selectedChat = chatHashMap.get(selected);
-                        new ChatWindow(selected, selectedChat);
+                        new ChatWindow(selected, selectedChat, receiver);
                     }
                 }
             }
         });
 
-        // Add right-click context menu for chat list
+
         JPopupMenu contextMenu = createChatContextMenu();
         chatList.setComponentPopupMenu(contextMenu);
     }
@@ -141,7 +139,7 @@ public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
             String selected = chatList.getSelectedValue();
             if (selected != null) {
                 Chat selectedChat = chatHashMap.get(selected);
-                new ChatWindow(selected, selectedChat);
+                new ChatWindow(selected, selectedChat, this);
             }
         });
 
@@ -150,7 +148,6 @@ public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
             if (selected != null) {
                 Chat selectedChat = chatHashMap.get(selected);
                 new EditChatWindow(this, selected, selectedChat, (newName, updatedChat) -> {
-                    // Remove old entry and add updated one
                     chatHashMap.remove(selected);
                     chatHashMap.put(newName, updatedChat);
                     updateChatList();
@@ -163,7 +160,7 @@ public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
             if (selected != null) {
                 int result = JOptionPane.showConfirmDialog(
                         this,
-                        "Möchten Sie den Chat '" + selected + "' wirklich löschen?",
+                        "Möchten Sie den Chat mit '" + selected + "' wirklich löschen?",
                         "Chat löschen",
                         JOptionPane.YES_NO_OPTION
                 );
@@ -182,38 +179,51 @@ public class MainWindow extends JFrame implements RelayClient.MessageReceiver {
     }
 
     private void updateChatList() {
-        // Clear and repopulate the list model
         chatListModel.clear();
 
         for (String chatName : chatHashMap.keySet()) {
             chatListModel.addElement(chatName);
         }
 
-        // The JList will automatically update since it uses the same model
-        // Force UI refresh
         chatList.revalidate();
         chatList.repaint();
-        printChatList();
+        //printChatList();
     }
 
-    // Optional: Method to get the current chat list for debugging
     public void printChatList() {
         System.out.println("Current chats: " + chatHashMap.keySet());
     }
 
     @Override
     public void onMessage(Message msg) {
-        String senderUUID = msg.getSenderUUID();
-
-        if(chatHashMap.get(senderUUID) != null){
+        PublicKey senderPublicKey = msg.getSenderKey();
+        boolean found = false;
+        for(Chat chat : chatHashMap.values()){
+            if(chat.getTargetKey().equals(senderPublicKey)){
+                chat.addMessage(msg);
+                for(ChatWindow chatWindow : openChatWindows){
+                    if(chatWindow.getChat().getTargetKey().equals(senderPublicKey)){
+                        chatWindow.addMessage(msg);
+                    }
+                }
+                found = true;
+            }
+        }
+        if(!found && !senderPublicKey.equals(KeyManager.getPublicKey())){
+            Chat newChat;
+            if(!msg.isDirectMessage()){
+                newChat = new Chat(true, Config.RELAY_SERVER_IP, Config.RELAY_SERVER_PORT, msg.getSenderKey());
 
-            System.out.println("Known UUID");
-            chatHashMap.get(senderUUID).addMessage(msg);
-        }else{
-            Chat newChat = new Chat(true, Config.RELAY_SERVER_IP, msg.getSenderUUID());
+            }else {
+                newChat = new Chat(false, msg.getFromIp(), msg.getUsingPort(), msg.getSenderKey());
+            }
             newChat.addMessage(msg);
-            chatHashMap.put(senderUUID, newChat);
+            chatHashMap.put(KeyManager.publicKeyToString(senderPublicKey), newChat);
             updateChatList();
         }
     }
+
+    public void closedWindow(ChatWindow closedWindow) {
+        this.openChatWindows.remove(closedWindow);
+    }
 }

+ 33 - 16
src/main/java/ui/NewChatDialog.java

@@ -5,6 +5,7 @@ import model.Chat;
 
 import javax.swing.*;
 import java.awt.*;
+import java.security.PublicKey;
 import java.util.function.BiConsumer;
 
 public class NewChatDialog extends JDialog {
@@ -12,40 +13,56 @@ public class NewChatDialog extends JDialog {
         super(parent, "Neuen Chat starten", true);
         setSize(300, 200);
         setLocationRelativeTo(parent);
-        JTextField uuidField = new JTextField();
-        //JTextField myIdField = new JTextField();
+        JTextField publicKeyField = new JTextField();
+
         JTextField receiverNameField = new JTextField();
         JRadioButton relayBtn = new JRadioButton("Relay", true);
         JRadioButton directBtn = new JRadioButton("Direkt");
-        JTextField relayAddress = new JTextField();
-        relayAddress.setText("192.168.2.177");
+
+        JTextField addressField = new JTextField();
+        addressField.setText("0.0.0.0");
+        JTextField peerPortField = new JTextField();
+        peerPortField.setText("54321");
+
         ButtonGroup group = new ButtonGroup();
         group.add(relayBtn);
         group.add(directBtn);
         JButton startBtn = new JButton("Starten");
 
         setLayout(new GridLayout(6, 1));
-        add(new JLabel("Empfänger-UUID"));
-        add(uuidField);
+        add(new JLabel("Empfänger - PublicKey"));
+        add(publicKeyField);
         add(new JLabel("Empfängername"));
         add(receiverNameField);
-        //add(new JLabel("Deine ID (für Relay):"));
-        //add(myIdField);
+
         add(relayBtn);
         add(directBtn);
-        add(new JLabel("Die Ip des Relay-Servers (Nur wenn Relay ausgewählt)"));
-        add(relayAddress);
+        add(new JLabel("Die Ip des Relays/Peers"));
+        add(addressField);
+        add(new JLabel("Der Port des Peers"));
+        add(peerPortField);
         add(startBtn);
 
         startBtn.addActionListener(e -> {
-            String uuid = uuidField.getText();
-            String relayAddressText = relayAddress.getText();
+            String publicKeyFieldText = publicKeyField.getText();
+            String addressText = addressField.getText();
             String name = receiverNameField.getText();
-            if (!relayAddressText.isEmpty() && !uuid.isEmpty() && !name.isEmpty()) {
+            int peerPort = Integer.parseInt(peerPortField.getText());
+
+            if (!addressText.isEmpty() && !name.isEmpty()) {
                 boolean useRelay = relayBtn.isSelected();
-                Chat chat = new Chat(useRelay, relayAddressText, uuid);
-                dispose();
-                onCreate.accept(name, chat);
+                if(useRelay && !publicKeyFieldText.isEmpty()){
+                    PublicKey publicKey = KeyManager.stringToPublicKey(publicKeyField.getText());
+                    Chat chat = new Chat(true, addressText, peerPort, publicKey);
+                    dispose();
+                    onCreate.accept(name, chat);
+                }else if(!useRelay){
+                    PublicKey publicKey = KeyManager.stringToPublicKey(publicKeyField.getText());
+                    Chat chat = new Chat(false, addressText, peerPort, publicKey);
+                    dispose();
+                    onCreate.accept(name, chat);
+                }
+
 
             }
         });

+ 37 - 20
src/main/java/ui/SettingsDialog.java

@@ -3,6 +3,7 @@ package ui;
 import javax.swing.*;
 import config.Config;
 import crypto.KeyManager;
+import util.Util;
 
 import java.awt.*;
 import java.io.IOException;
@@ -15,15 +16,30 @@ public class SettingsDialog extends JDialog {
         setSize(350, 250); // Increased size to accommodate new fields
         setLocationRelativeTo(parent);
 
-        setLayout(new GridLayout(8, 2)); // Increased rows for new fields
+        setLayout(new GridLayout(9, 3));
+
         JTextField UUIDBox = new JTextField();
         UUIDBox.setText(KeyManager.getMyUUID().toString());
-        UUIDBox.setEditable(false); // UUID should not be editable
+        UUIDBox.setEditable(false);
+        JButton UUIDCopy = new JButton("Copy");
+        UUIDCopy.addActionListener(e -> {
+            Util.copyToClipboard(UUIDCopy.getText());
+            System.out.println("Copied to clipboard!");
+        });
+
+        JTextField publicKeyBox = new JTextField();
+        publicKeyBox.setText(KeyManager.publicKeyToString(KeyManager.getPublicKey()));
+        publicKeyBox.setEditable(false);
+        JButton publicKeyCopy = new JButton("Copy");
+        publicKeyCopy.addActionListener(e -> {
+            Util.copyToClipboard(publicKeyBox.getText());
+            System.out.println("Copied to clipboard!");
+        });
+
 
-        JCheckBox encryptBox = new JCheckBox("Verschlüsselung beim Speichern", Config.ENCRYPT_ON_SAVE);
-        encryptBox.addActionListener(e -> Config.ENCRYPT_ON_SAVE = encryptBox.isSelected());
+        JCheckBox useRelayBox = new JCheckBox("Use Relay-Server", Config.USE_RELAY);
+        useRelayBox.addActionListener(e -> Config.USE_RELAY = useRelayBox.isSelected());
 
-        // New fields for Relay Server configuration
         JTextField relayServerIpField = new JTextField(Config.RELAY_SERVER_IP);
         JTextField relayServerPortField = new JTextField(String.valueOf(Config.RELAY_SERVER_PORT));
 
@@ -33,9 +49,17 @@ public class SettingsDialog extends JDialog {
         JButton saveBtn = new JButton("Speichern");
         JButton cancelBtn = new JButton("Abbrechen");
 
-        // Add components to dialog
         add(new JLabel("Deine UUID: "));
         add(UUIDBox);
+        add(UUIDCopy);
+
+        add(new JLabel());
+
+        add(new JLabel("Dein PublicKey: "));
+        add(publicKeyBox);
+        add(publicKeyCopy);
+
+        add(new JLabel());
 
         add(new JLabel("Relay Server IP:"));
         add(relayServerIpField);
@@ -46,13 +70,12 @@ public class SettingsDialog extends JDialog {
         add(testConnectionBtn);
         add(connectionStatusLabel);
 
-        add(encryptBox);
-        add(new JLabel()); // Empty cell for layout
+        add(useRelayBox);
+        add(new JLabel());
 
         add(saveBtn);
         add(cancelBtn);
 
-        // Test connection button action
         testConnectionBtn.addActionListener(e -> {
             String ip = relayServerIpField.getText();
             int port;
@@ -67,9 +90,7 @@ public class SettingsDialog extends JDialog {
             testRelayConnection(ip, port, connectionStatusLabel);
         });
 
-        // Save button action
         saveBtn.addActionListener(e -> {
-            // Save Relay Server configuration
             Config.RELAY_SERVER_IP = relayServerIpField.getText();
             try {
                 Config.RELAY_SERVER_PORT = Integer.parseInt(relayServerPortField.getText());
@@ -78,20 +99,17 @@ public class SettingsDialog extends JDialog {
                 return;
             }
 
-            // Save other settings
-            Config.ENCRYPT_ON_SAVE = encryptBox.isSelected();
+            Config.ENCRYPT_ON_SAVE = useRelayBox.isSelected();
 
-            // Save to persistent storage if you have that functionality
             Config.saveConfig();
 
             JOptionPane.showMessageDialog(this, "Einstellungen gespeichert!", "Erfolg", JOptionPane.INFORMATION_MESSAGE);
             dispose();
         });
 
-        // Cancel button action
-        cancelBtn.addActionListener(e -> {
-            dispose();
-        });
+        cancelBtn.addActionListener(e ->
+            dispose()
+        );
     }
 
     private void testRelayConnection(String ip, int port, JLabel statusLabel) {
@@ -100,9 +118,8 @@ public class SettingsDialog extends JDialog {
 
         new Thread(() -> {
             try (Socket testSocket = new Socket()) {
-                testSocket.connect(new InetSocketAddress(ip, port), 5000); // 5 second timeout
+                testSocket.connect(new InetSocketAddress(ip, port), 5000);
 
-                // If we get here, connection was successful
                 SwingUtilities.invokeLater(() -> {
                     statusLabel.setText("Verbunden ✓");
                     statusLabel.setForeground(Color.GREEN);

+ 13 - 0
src/main/java/util/Util.java

@@ -0,0 +1,13 @@
+package util;
+
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+
+public class Util {
+    public static void copyToClipboard(String text) {
+        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
+        StringSelection data = new StringSelection(text);
+        cb.setContents(data, null);
+    }
+}