commit d35aa29a0e141fa8a9598199b3d8b818f0274ec0 Author: CubeBit Date: Tue Jul 25 23:03:47 2023 +0200 init diff --git a/client/pom.xml b/client/pom.xml new file mode 100644 index 0000000..2dd4128 --- /dev/null +++ b/client/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + org.orinprojects + SecuredChat + 1.0-SNAPSHOT + + + client + + + 19 + 19 + UTF-8 + + + + org.orinprojects + server + 1.0-SNAPSHOT + compile + + + + \ No newline at end of file diff --git a/client/src/main/java/org/orinprojects/Client.java b/client/src/main/java/org/orinprojects/Client.java new file mode 100644 index 0000000..28ef721 --- /dev/null +++ b/client/src/main/java/org/orinprojects/Client.java @@ -0,0 +1,84 @@ +package org.orinprojects; + +import org.orinprojects.encryption.Encryption; +import org.orinprojects.exceptions.ArgumentsException; +import org.orinprojects.impl.MessageProtocol; +import org.orinprojects.impl.MessageSender; +import org.orinprojects.impl.MessageType; +import org.orinprojects.interfaces.Protocol; + +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.security.KeyPair; +import java.security.PublicKey; +import java.util.*; + +public class Client { + + public static KeyPair keys; + + public static PublicKey serverPublicRSA; + + public static void main(String[] args) throws Exception { + keys = Encryption.generateRSAKey(); +// System.out.println(keys.getPublic()); + + String username = readUsername(); + Map validatedArguments = getValidatedDataFromArguments(args); + + Socket socket = new Socket( + validatedArguments.get("ip"), + Integer.parseInt(validatedArguments.get("port")) + ); + + ClientThread client = new ClientThread(socket); + + Thread thr = new Thread(client); + thr.start(); + + + +// MessageSender.sendMessage(client.out, new MessageProtocol().setWelcomeMessage(username, new AssymetricKeyPairSerializ(keys.getPublic()))); + + + + while (socket.isConnected()) { + Scanner scanner = new Scanner(System.in); + String inputText = scanner.nextLine(); + +// String encrypted = Encryption.Encrypt(inputText.getBytes(), serverPublic); +// MessageSender.sendMessage(client.out, new MessageProtocol().setTextMessage(new String(encrypted))); + } + } + + private static String readUsername() { + System.out.print("Enter your username: "); + Scanner scanner = new Scanner(System.in); + + return scanner.nextLine(); + } + + private static Map getValidatedDataFromArguments(String[] args) throws ArgumentsException { + if (args.length != 4) + throw new ArgumentsException("Not enough or too much arguments. Usage: -h 127.0.0.1 -p 6666"); + + if (!args[0].equals("-h")) + throw new ArgumentsException("No host parameter specified. Use -h to specify ipv4 address"); + + if (!args[2].equals("-p")) + throw new ArgumentsException("No port parameter specified. Use -p to specify port number"); + + try { + Integer.parseInt(args[3]); + } catch (NumberFormatException numberFormatException) { + throw new ArgumentsException("Wrong number format! Example: -p 6666"); + } + + + Map result = new HashMap<>(); + result.put("ip", args[1]); + result.put("port", args[3]); + + return result; + } +} \ No newline at end of file diff --git a/client/src/main/java/org/orinprojects/ClientThread.java b/client/src/main/java/org/orinprojects/ClientThread.java new file mode 100644 index 0000000..e65ef8d --- /dev/null +++ b/client/src/main/java/org/orinprojects/ClientThread.java @@ -0,0 +1,59 @@ +package org.orinprojects; + +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.orinprojects.encryption.Encryption; +import org.orinprojects.impl.MessageProtocol; +import org.orinprojects.impl.MessageType; +import org.orinprojects.interfaces.Protocol; + +import java.io.*; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; + +public class ClientThread implements Runnable { + + private final Socket clientSocket; + + final BufferedReader in; + + final PrintWriter out; + + private PublicKey publicKey; + + public ClientThread(Socket socket) throws IOException { + this.clientSocket = socket; + this.in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + this.out = new PrintWriter(clientSocket.getOutputStream()); + } + + @Override + public void run() { + while (clientSocket.isConnected()) { + String receivedMessage; + try { + receivedMessage = in.readLine(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + byte[] rsa = receivedMessage.getBytes(StandardCharsets.UTF_8); + PublicKey serverPublicKey = null; + try { + serverPublicKey = KeyFactory.getInstance("RSA") + .generatePublic(new X509EncodedKeySpec(rsa)); + } catch (InvalidKeySpecException e) { + throw new RuntimeException(e); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + Client.serverPublicRSA = serverPublicKey; + + } + } +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..27e1179 --- /dev/null +++ b/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + org.orinprojects + SecuredChat + 1.0-SNAPSHOT + pom + + server + client + + + + + central + https://repo.maven.apache.org/maven2 + + + + + + org.bouncycastle + bcprov-jdk15on + 1.70 + + + + + 20 + 20 + UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 19 + 19 + + + + + \ No newline at end of file diff --git a/server/pom.xml b/server/pom.xml new file mode 100644 index 0000000..ba21e3f --- /dev/null +++ b/server/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + org.orinprojects + SecuredChat + 1.0-SNAPSHOT + + + server + + + 19 + 19 + UTF-8 + + + \ No newline at end of file diff --git a/server/src/main/java/org/orinprojects/ClientHandler.java b/server/src/main/java/org/orinprojects/ClientHandler.java new file mode 100644 index 0000000..0d7ccef --- /dev/null +++ b/server/src/main/java/org/orinprojects/ClientHandler.java @@ -0,0 +1,80 @@ +package org.orinprojects; + +import org.orinprojects.encryption.Encryption; +import org.orinprojects.impl.MessageProtocol; +import org.orinprojects.impl.MessageSender; +import org.orinprojects.impl.MessageType; +import org.orinprojects.interfaces.Protocol; + +import java.io.*; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +public class ClientHandler implements Runnable { + + private final Socket clientSocket; + + private final BufferedReader in; + + private final PrintWriter out; + + private String username; + + private int requests = 0; + + public ClientHandler(Socket socket) throws IOException { + this.clientSocket = socket; + in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + out = new PrintWriter(clientSocket.getOutputStream()); + + out.println(Server.serverKeys.getPublic()); + out.flush(); + } + + @Override + public void run() { + while (clientSocket.isConnected()) { + try { + String receivedMessage = in.readLine(); + byte[] rsa = receivedMessage.getBytes(StandardCharsets.UTF_8); + PublicKey serverPublicKey = KeyFactory.getInstance("RSA") + .generatePublic(new X509EncodedKeySpec(rsa)); + out.println(Encryption.encryptRSA(new String(Server.aesKey.getEncoded()), serverPublicKey)); + out.flush(); + } catch (Exception e) { + closeAllConnections(clientSocket, in, out); + } + } + } + +// private void printKey(String username) { +// System.out.println(Encryption.getKeyByUsername(username)); +// } + +// private void sendMessage(ObjectOutputStream out, Message message) throws IOException { +// out.writeObject(message); +// out.flush(); +// } + + private void closeAllConnections(Socket socket, BufferedReader in, PrintWriter out) { + try { + if (socket != null) + socket.close(); + + if (in != null) + in.close(); + + if (out != null) + out.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + + Server.clients.remove(this); + } +} diff --git a/server/src/main/java/org/orinprojects/Server.java b/server/src/main/java/org/orinprojects/Server.java new file mode 100644 index 0000000..10832b0 --- /dev/null +++ b/server/src/main/java/org/orinprojects/Server.java @@ -0,0 +1,66 @@ +package org.orinprojects; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.orinprojects.encryption.Encryption; +import org.orinprojects.exceptions.ArgumentsException; + +import javax.crypto.SecretKey; +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +public class Server { + + public static List clients = new ArrayList<>(); + + public static HashMap clientKeys = new HashMap<>(); + + public static ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(20); + + public static KeyPair serverKeys; + + public static SecretKey aesKey; + + public static void main(String[] args) throws IOException, ArgumentsException, NoSuchAlgorithmException { + Server.serverKeys = Encryption.generateRSAKey(); + Server.aesKey = Encryption.generateAESKey(); + + int portNumber = getPortNumber(args); + + ServerSocket server = new ServerSocket(portNumber); + while (!server.isClosed()) { + Socket clientSocket = server.accept(); + + ClientHandler clientHandler = new ClientHandler(clientSocket); + clients.add(clientHandler); + + executor.execute(clientHandler); + } + } + + private static int getPortNumber(String[] args) throws ArgumentsException { + if (args.length != 2) + throw new ArgumentsException("Not enough or too much arguments"); + + if (!args[0].equals("-p")) + throw new ArgumentsException("No port parameter. Use -p to specify port"); + + int port; + try { + port = Integer.parseInt(args[1]); + } catch (NumberFormatException numberFormatException) { + throw new ArgumentsException("Wrong number format! Example: -p 6666"); + } + + return port; + } + +} diff --git a/server/src/main/java/org/orinprojects/encryption/Encryption.java b/server/src/main/java/org/orinprojects/encryption/Encryption.java new file mode 100644 index 0000000..da7f496 --- /dev/null +++ b/server/src/main/java/org/orinprojects/encryption/Encryption.java @@ -0,0 +1,59 @@ +package org.orinprojects.encryption; + +import org.bouncycastle.util.encoders.Base64Encoder; + +import javax.crypto.*; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; +import java.security.spec.X509EncodedKeySpec; + +public class Encryption { + + private static final int rsaKeySize = 4096; + + private static final int aesKeySize = 128; + + public static KeyPair generateRSAKey() throws NoSuchAlgorithmException { + KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); + generator.initialize(rsaKeySize); + + return generator.generateKeyPair(); + } + + public static byte[] encryptAES(PublicKey pubKey, SecretKey aesKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + encryptCipher.init(Cipher.ENCRYPT_MODE, pubKey); + +// byte[] encryptedMessageBytes = encryptCipher.doFinal(aesKey.getEncoded()); + return encryptCipher.doFinal("hello".getBytes()); + } + + public static String decryptAES(PrivateKey privateKey, String aes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + decryptCipher.init(Cipher.DECRYPT_MODE, privateKey); + + byte[] decryptedAES = decryptCipher.doFinal(aes.getBytes()); + + return new String(decryptedAES); + } + + public static String encryptRSA(String data, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException { + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + return new String(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8))); + } + + public static String decryptRSA(String data, PrivateKey privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException { + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + return new String(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8))); + } + + public static SecretKey generateAESKey() throws NoSuchAlgorithmException { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(aesKeySize); + return keyGenerator.generateKey(); + } +} diff --git a/server/src/main/java/org/orinprojects/exceptions/ArgumentsException.java b/server/src/main/java/org/orinprojects/exceptions/ArgumentsException.java new file mode 100644 index 0000000..9e28429 --- /dev/null +++ b/server/src/main/java/org/orinprojects/exceptions/ArgumentsException.java @@ -0,0 +1,9 @@ +package org.orinprojects.exceptions; + +public class ArgumentsException extends Exception { + + public ArgumentsException(String errorMessage) { + super(errorMessage); + } + +} diff --git a/server/src/main/java/org/orinprojects/impl/MessageProtocol.java b/server/src/main/java/org/orinprojects/impl/MessageProtocol.java new file mode 100644 index 0000000..3d8a90c --- /dev/null +++ b/server/src/main/java/org/orinprojects/impl/MessageProtocol.java @@ -0,0 +1,50 @@ +package org.orinprojects.impl; + +import org.orinprojects.interfaces.Protocol; + +import java.util.Arrays; + +public class MessageProtocol implements Protocol { + + private byte[] text; + + private MessageType messageType; + + public MessageProtocol(MessageType messageType, byte[] text) { + this.messageType = messageType; + this.text = text; + } + + public MessageProtocol() {} + + @Override + public String encryptToString() { + return this.messageType.name() + this.text; + } + + @Override + public void decryptFromString(byte[] text) { + String s = new String(text, 0, 3); + switch (s) { + case "WLC" -> this.messageType = MessageType.WLC; + case "RSA" -> this.messageType = MessageType.RSA; + case "TXT" -> this.messageType = MessageType.TXT; + case "AES" -> this.messageType = MessageType.AES; + } + this.text = Arrays.copyOfRange(text, 2, text.length); + } + + @Override + public MessageType getMessageType() { + return this.messageType; + } + + public String getText(){ + return new String(this.text); + } + + public byte[] getBytes(){ + return this.text; + } + +} diff --git a/server/src/main/java/org/orinprojects/impl/MessageSender.java b/server/src/main/java/org/orinprojects/impl/MessageSender.java new file mode 100644 index 0000000..3923d7d --- /dev/null +++ b/server/src/main/java/org/orinprojects/impl/MessageSender.java @@ -0,0 +1,12 @@ +package org.orinprojects.impl; + +import java.io.PrintWriter; + +public class MessageSender { + + public static void sendMessage(PrintWriter out, String text) { + out.println(text); + out.flush(); + } + +} diff --git a/server/src/main/java/org/orinprojects/impl/MessageType.java b/server/src/main/java/org/orinprojects/impl/MessageType.java new file mode 100644 index 0000000..4860914 --- /dev/null +++ b/server/src/main/java/org/orinprojects/impl/MessageType.java @@ -0,0 +1,5 @@ +package org.orinprojects.impl; + +public enum MessageType { + FILE, TXT, WLC, AES, RSA +} diff --git a/server/src/main/java/org/orinprojects/interfaces/Protocol.java b/server/src/main/java/org/orinprojects/interfaces/Protocol.java new file mode 100644 index 0000000..1d40d83 --- /dev/null +++ b/server/src/main/java/org/orinprojects/interfaces/Protocol.java @@ -0,0 +1,16 @@ +package org.orinprojects.interfaces; + +import org.orinprojects.impl.MessageType; + +public interface Protocol { + + String encryptToString(); + + void decryptFromString(byte[] text); + + MessageType getMessageType(); + + String getText(); + + byte[] getBytes(); +} diff --git a/src/main/java/org/orinprojects/Main.java b/src/main/java/org/orinprojects/Main.java new file mode 100644 index 0000000..7926c12 --- /dev/null +++ b/src/main/java/org/orinprojects/Main.java @@ -0,0 +1,7 @@ +package org.orinprojects; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file