From 75e873d44f869c74e7afab60a64eb0e4cc47b6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=A0s?= Date: Mon, 5 Dec 2022 13:03:14 +0100 Subject: [PATCH] =?UTF-8?q?FEAT:=20Multiclient=20+=20Crypt=C3=A9=20+=20Pse?= =?UTF-8?q?udo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/uiDesigner.xml | 124 ++++++++++++++++++++++++++++ .idea/workspace.xml | 94 ++++++++++++++------- key.ser | Bin 263 -> 0 bytes projet-mini-chat.iml | 17 ++++ src/client/Client.java | 121 ++++++++++++++++----------- src/client/ListenThread.java | 35 ++++++++ src/reseau/ResolutionDeNom.java | 27 ------ src/serveur/Server.java | 38 +++++++++ src/serveur/Serveur.java | 75 ----------------- src/serveur/ThreadServer.java | 83 +++++++++++++++++++ src/{reseau => utils}/AES.java | 57 ++++++++++--- src/{reseau => utils}/RSA.java | 2 +- src/utils/ResolutionDeNom.java | 23 ++++++ test/utils/ResolutionDeNomTest.java | 25 ++++++ 14 files changed, 525 insertions(+), 196 deletions(-) create mode 100644 .idea/uiDesigner.xml delete mode 100644 key.ser create mode 100644 src/client/ListenThread.java delete mode 100644 src/reseau/ResolutionDeNom.java create mode 100644 src/serveur/Server.java delete mode 100644 src/serveur/Serveur.java create mode 100644 src/serveur/ThreadServer.java rename src/{reseau => utils}/AES.java (56%) rename src/{reseau => utils}/RSA.java (98%) create mode 100644 src/utils/ResolutionDeNom.java create mode 100644 test/utils/ResolutionDeNomTest.java diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 2edd9ec..99ea954 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,10 +2,18 @@ + + + + + + - - + + + + \ No newline at end of file diff --git a/src/client/Client.java b/src/client/Client.java index 175a7a2..818f298 100644 --- a/src/client/Client.java +++ b/src/client/Client.java @@ -1,71 +1,92 @@ package client; -import java.io.*; +import utils.RSA; +import utils.ResolutionDeNom; + +import java.io.EOFException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.ConnectException; import java.net.Socket; -import java.rmi.UnknownHostException; import java.security.KeyPair; import java.security.PublicKey; +import java.util.Objects; import java.util.Scanner; -import reseau.RSA; - public class Client { - public static final Scanner scan = new Scanner(System.in); + private final String SERVER_IP; + private final int SERVER_PORT; + private final Scanner scanner; + private ObjectInputStream inputStream; + private ObjectOutputStream outputStream; + private KeyPair clientKeys; + private PublicKey serverKey; - public static void main(String[] args) { - Socket serverSocket = null; - ObjectOutputStream out = null; - ObjectInputStream in = null; + private String pseudo; - // Clé de chiffrage - KeyPair clientKeyPair = RSA.genererCle(); - PublicKey serverKey = null; + public Client(String ip, int port) { + this.SERVER_IP = ResolutionDeNom.getIPAddress(ip); + this.SERVER_PORT = port; + this.scanner = new Scanner(System.in); + this.clientKeys = RSA.genererCle(); + } - // Création des Sockets - try { - serverSocket = new Socket("localhost", 4444); - System.out.println("Connecté au serveur"); - out = new ObjectOutputStream(serverSocket.getOutputStream()); - in = new ObjectInputStream(serverSocket.getInputStream()); + public void start() { + System.out.print("Saisir un pseudo: "); + pseudo = scanner.nextLine(); - // On envoie la clé de chiffrage - out.writeObject(clientKeyPair.getPublic()); + try (Socket socket = new Socket(SERVER_IP, SERVER_PORT)) { + inputStream = new ObjectInputStream(socket.getInputStream()); + outputStream = new ObjectOutputStream(socket.getOutputStream()); - serverKey = (PublicKey) in.readObject(); + exchangeKeys(); - } catch (UnknownHostException e) { - System.out.println("Destination unknown"); - System.exit(-1); - } catch (IOException e) { - System.out.println("now to investigate this IO issue"); - System.exit(-1); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } + sendMessage(pseudo); - // Communication - String message; - byte[] messageCrypte; - try { + // Ecoute du serveur + ListenThread threadClient = new ListenThread(this); + threadClient.start(); + + // Ecoute de l'entrée du clavier + System.out.println("Tappez 'bye' pour quitter\n"); + String message; do { - // Envoi du message - System.out.print("client > "); - message = scan.nextLine(); - messageCrypte = RSA.encrypter(message, serverKey); - out.writeObject(messageCrypte); + message = scanner.nextLine(); + sendMessage(message); + } while (!Objects.equals(message, "bye")); - // Reception du message - messageCrypte = (byte[]) in.readObject(); - message = RSA.decrypter(messageCrypte, clientKeyPair.getPrivate()); - System.out.printf("serveur > %s\n", message); - } while (!message.equals("bye")); - - out.close(); - in.close(); - serverSocket.close(); - }catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); + } catch (ConnectException e) { + System.err.println("Serveur non trouvé"); + }catch (EOFException e) { + System.err.println("Connexion perdue"); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); } } + + public void exchangeKeys() throws IOException, ClassNotFoundException { + // Envoie sa clé + outputStream.writeObject(clientKeys.getPublic()); + + // Attend la clé du serveur + serverKey = (PublicKey) inputStream.readObject(); + } + + public void sendMessage(String message) throws IOException { + byte[] messageCrypte = RSA.encrypter(message, serverKey); + outputStream.writeObject(messageCrypte); + } + + public String getMessage() throws IOException, ClassNotFoundException { + byte[] messageCrypte = (byte[]) inputStream.readObject(); + return RSA.decrypter(messageCrypte, clientKeys.getPrivate()); + } + + + public static void main(String[] args) { + Client client = new Client("localhost", 4444); + client.start(); + } } diff --git a/src/client/ListenThread.java b/src/client/ListenThread.java new file mode 100644 index 0000000..2f2500d --- /dev/null +++ b/src/client/ListenThread.java @@ -0,0 +1,35 @@ +package client; + +import java.io.EOFException; +import java.io.IOException; +import java.net.SocketException; + +/** + * Thread for clients + */ +public class ListenThread extends Thread { + + private final Client client; + + public ListenThread(Client client) { + this.client = client; + } + + @Override + public void run() { + + try { + String message; + while (true) { + message = client.getMessage(); + System.out.println(message); + } + } catch (SocketException ignored) { + System.out.println("Vous avez quitté le salon"); + } catch (EOFException ignored) { + System.err.println("Connexion perdue"); + }catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } +} diff --git a/src/reseau/ResolutionDeNom.java b/src/reseau/ResolutionDeNom.java deleted file mode 100644 index 26f1fa3..0000000 --- a/src/reseau/ResolutionDeNom.java +++ /dev/null @@ -1,27 +0,0 @@ -package reseau; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -public class ResolutionDeNom { - - public static InetAddress getAddress(String host) { - InetAddress address; - try { - address = InetAddress.getByName(host); - return address; - } catch (UnknownHostException e) { - e.printStackTrace(); - } - return null; - } - - public static void main(String[] args) { -// String input = args[0]; - String input = "www.google.com"; - InetAddress address = getAddress(input); - if (address != null) { - System.out.printf("%s : %s\n", input, address.getHostAddress()); - } - } -} diff --git a/src/serveur/Server.java b/src/serveur/Server.java new file mode 100644 index 0000000..e8c8516 --- /dev/null +++ b/src/serveur/Server.java @@ -0,0 +1,38 @@ +package serveur; + +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; + +public class Server { + + private final int PORT; + private final ArrayList threads; + + public Server(int port) { + this.PORT = port; + this.threads = new ArrayList<>(); + } + + public void start() { + try (ServerSocket serversocket = new ServerSocket(PORT)) { + System.out.println("Server is started..."); + while (true) { + Socket socket = serversocket.accept(); + System.out.printf("Nouvelle connexion : %s\n", socket); + + ThreadServer thread = new ThreadServer(socket, threads); + + threads.add(thread); + thread.start(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + Server serveur = new Server(4444); + serveur.start(); + } +} diff --git a/src/serveur/Serveur.java b/src/serveur/Serveur.java deleted file mode 100644 index d6aa216..0000000 --- a/src/serveur/Serveur.java +++ /dev/null @@ -1,75 +0,0 @@ -package serveur; - -import reseau.RSA; - -import java.io.*; -import java.net.ServerSocket; -import java.net.Socket; -import java.security.KeyPair; -import java.security.PublicKey; -import java.util.Scanner; - -public class Serveur { - - private static final int PORT = 4444; - private static final Scanner scan = new Scanner(System.in); - - public static void main(String[] args) { - ServerSocket serverSocket = null; - Socket clientSocket = null; - - KeyPair serverKeyPairs = RSA.genererCle(); - PublicKey clientKey; - - // Connexion - try { - serverSocket = new ServerSocket(PORT); // Crée le serveur - clientSocket = serverSocket.accept(); // On recherche un client - } catch (IOException e) { - System.out.printf("Erreur de connexion sur le port: %d\n", PORT); - System.exit(-1); - } - - // Un client a été trouvé - System.out.println("Client connecté"); - - ObjectInputStream in; - ObjectOutputStream out; - - try { - in = new ObjectInputStream(clientSocket.getInputStream()); - out = new ObjectOutputStream(clientSocket.getOutputStream()); - - // On récupère la clé du client - clientKey = (PublicKey) in.readObject(); - out.writeObject(serverKeyPairs.getPublic()); - - // Communication - String message; - byte[] messageCrypte; - do { - // Envoi du message - messageCrypte = (byte[]) in.readObject(); - message = RSA.decrypter(messageCrypte, serverKeyPairs.getPrivate()); - System.out.printf("client > %s\n", message); - - - // Reception du message - System.out.print("serveur > "); - message = scan.nextLine(); - messageCrypte = RSA.encrypter(message, clientKey); - out.writeObject(messageCrypte); - } while (!message.equals("bye")); - - in.close(); - out.close(); - clientSocket.close(); - serverSocket.close(); - - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/serveur/ThreadServer.java b/src/serveur/ThreadServer.java new file mode 100644 index 0000000..18d7cb2 --- /dev/null +++ b/src/serveur/ThreadServer.java @@ -0,0 +1,83 @@ +package serveur; + +import utils.RSA; + +import java.io.*; +import java.net.Socket; +import java.security.KeyPair; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Objects; + + +public class ThreadServer extends Thread { + + private final ArrayList threads; + private final ObjectInputStream inputStream; + private final ObjectOutputStream outputStream; + private final KeyPair serverKeys; + private PublicKey clientKey; + private String clientPseudo; + + public ThreadServer(Socket socket, ArrayList threads) throws IOException { + this.threads = threads; + this.outputStream = new ObjectOutputStream(socket.getOutputStream()); + this.inputStream = new ObjectInputStream(socket.getInputStream()); + + this.serverKeys = RSA.genererCle(); + } + + @Override + public void run() { + try { + exchangeKeys(); + + // Récupère le pseudo + this.clientPseudo = getMessage(); + sendMessageToEveryone(String.format("** %s viens de rejoindre le salon **", clientPseudo), true); + + String message; + do { + message = getMessage(); + String reply = String.format("%s : %s", clientPseudo, message); + + sendMessageToEveryone(reply, true); + } while (!Objects.equals(message, "bye")); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } finally { + threads.remove(this); + try { + sendMessageToEveryone(String.format("** %s viens de quitter le salon **", clientPseudo), true); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void exchangeKeys() throws IOException, ClassNotFoundException { + // Attend la clé du client + clientKey = (PublicKey) inputStream.readObject(); + + // Envoie sa clé + outputStream.writeObject(serverKeys.getPublic()); + } + + public String getMessage() throws IOException, ClassNotFoundException { + byte[] messageCrypte = (byte[]) inputStream.readObject(); + return RSA.decrypter(messageCrypte, serverKeys.getPrivate()); + } + + public void sendMessage(String message, boolean log) throws IOException { + byte[] messageCrypte = RSA.encrypter(message, clientKey); + outputStream.writeObject(messageCrypte); + if (log) System.out.println(message); + } + + public void sendMessageToEveryone(String message, boolean log) throws IOException { + for (ThreadServer thread : threads) { + thread.sendMessage(message, false); + } + if (log) System.out.println(message); + } +} diff --git a/src/reseau/AES.java b/src/utils/AES.java similarity index 56% rename from src/reseau/AES.java rename to src/utils/AES.java index 5b742dd..f2eb994 100644 --- a/src/reseau/AES.java +++ b/src/utils/AES.java @@ -1,4 +1,4 @@ -package reseau; +package utils; import javax.crypto.*; import java.io.*; @@ -7,6 +7,13 @@ import java.security.*; public class AES { + private static final String SAVE_FILE = "key.sav"; + + /** + * TODO + * + * @return + */ public static Key genererCle() { Key key = null; @@ -19,40 +26,64 @@ public class AES { return key; } - public static String decrypter(byte[] msg, Key key) { + /** + * TODO + * + * @param msg + * @param key + * @return + */ + public static byte[] encrypter(String msg, Key key) { try { - Cipher cipher = Cipher.getInstance("DES") ; - cipher.init(Cipher.DECRYPT_MODE, key); - return new String(cipher.doFinal(msg), StandardCharsets.UTF_8); + Cipher cipher = Cipher.getInstance("DES"); + cipher.init(Cipher.ENCRYPT_MODE, key); + return cipher.doFinal(msg.getBytes()); } catch (Exception e) { e.printStackTrace(); } return null; } - public static byte[] encrypter(String msg, Key key){ + /** + * TODO + * + * @param message + * @param cle + * @return + */ + public static String decrypter(byte[] message, Key cle) { try { - Cipher cipher = Cipher.getInstance("DES") ; - cipher.init(Cipher.ENCRYPT_MODE, key) ; - return cipher.doFinal(msg.getBytes()); - } catch(Exception e){ + Cipher cipher = Cipher.getInstance("DES"); + cipher.init(Cipher.DECRYPT_MODE, cle); + return new String(cipher.doFinal(message), StandardCharsets.UTF_8); + } catch (Exception e) { e.printStackTrace(); } return null; } + /** + * TODO + * + * @param key + */ public static void sauvegarderCle(Key key) { - try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("key.ser"))) { + try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(SAVE_FILE))) { objectOutputStream.writeObject(key); } catch (IOException e) { throw new RuntimeException(e); } } + /** + * TODO + * + * @return + */ public static Key chargerCle() { - Key key = null; - try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("key.ser"))) { + Key key; + try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(SAVE_FILE))) { key = (Key) objectInputStream.readObject(); } catch (IOException | ClassNotFoundException e) { throw new RuntimeException(e); diff --git a/src/reseau/RSA.java b/src/utils/RSA.java similarity index 98% rename from src/reseau/RSA.java rename to src/utils/RSA.java index 8a2feb2..d6e19d3 100644 --- a/src/reseau/RSA.java +++ b/src/utils/RSA.java @@ -1,4 +1,4 @@ -package reseau; +package utils; import javax.crypto.Cipher; import java.nio.charset.StandardCharsets; diff --git a/src/utils/ResolutionDeNom.java b/src/utils/ResolutionDeNom.java new file mode 100644 index 0000000..c723d3b --- /dev/null +++ b/src/utils/ResolutionDeNom.java @@ -0,0 +1,23 @@ +package utils; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class ResolutionDeNom { + + /** + * TODO + * + * @param host + * @return + */ + public static String getIPAddress(String host) { + String address = null; + try { + address = InetAddress.getByName(host).getHostAddress(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return address; + } +} diff --git a/test/utils/ResolutionDeNomTest.java b/test/utils/ResolutionDeNomTest.java new file mode 100644 index 0000000..5a6d02f --- /dev/null +++ b/test/utils/ResolutionDeNomTest.java @@ -0,0 +1,25 @@ +package utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ResolutionDeNomTest { + + @Test + void getIPAddress() { + + final int EXPECTED = 1; + final int ACTUAL = 0; + final String[][] FIXTURE = { + {"localhost", "127.0.0.1"}, + {"www.univ-jfc.fr", "194.57.185.14"}, + }; + + for (String[] test : FIXTURE) { + assertEquals(test[EXPECTED], ResolutionDeNom.getIPAddress(test[ACTUAL])); + System.out.printf("%s -> %s : OK\n", test[ACTUAL], test[EXPECTED]); + } + + } +} \ No newline at end of file