diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..7c073f8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..8c3a518 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..1f0cacc --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..9754fc9 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ 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 index 28ef721..21101bd 100644 --- a/client/src/main/java/org/orinprojects/Client.java +++ b/client/src/main/java/org/orinprojects/Client.java @@ -1,14 +1,10 @@ package org.orinprojects; -import org.orinprojects.encryption.Encryption; +import org.orinprojects.encryption.EncryptionUtil; 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 javax.crypto.SecretKey; import java.net.Socket; -import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.PublicKey; import java.util.*; @@ -19,12 +15,14 @@ public class Client { public static PublicKey serverPublicRSA; + public static SecretKey aesKey; + public static void main(String[] args) throws Exception { - keys = Encryption.generateRSAKey(); -// System.out.println(keys.getPublic()); + Map validatedArguments = getValidatedDataFromArguments(args); + + keys = EncryptionUtil.generateRSAKeys(); String username = readUsername(); - Map validatedArguments = getValidatedDataFromArguments(args); Socket socket = new Socket( validatedArguments.get("ip"), @@ -36,18 +34,24 @@ public class Client { Thread thr = new Thread(client); thr.start(); + client.out.println("WLC" + username); + client.out.flush(); - -// MessageSender.sendMessage(client.out, new MessageProtocol().setWelcomeMessage(username, new AssymetricKeyPairSerializ(keys.getPublic()))); - - + client.out.println("RSA" + EncryptionUtil.publicKeyToString(keys.getPublic())); + client.out.flush(); 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))); + if (!client.aesReceived && !client.rsaReceived) + System.out.println("Wait for complete initialisation!"); + + if (client.rsaReceived && client.aesReceived) { + String encryptedText = EncryptionUtil.encryptWithAES(inputText, aesKey); + client.out.println("TXT" + encryptedText); + client.out.flush(); + } } } diff --git a/client/src/main/java/org/orinprojects/ClientThread.java b/client/src/main/java/org/orinprojects/ClientThread.java index e65ef8d..1080e78 100644 --- a/client/src/main/java/org/orinprojects/ClientThread.java +++ b/client/src/main/java/org/orinprojects/ClientThread.java @@ -1,19 +1,16 @@ 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 org.orinprojects.encryption.EncryptionUtil; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import java.io.*; import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.security.KeyFactory; +import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; public class ClientThread implements Runnable { @@ -23,7 +20,9 @@ public class ClientThread implements Runnable { final PrintWriter out; - private PublicKey publicKey; + public boolean rsaReceived = false; + + public boolean aesReceived = false; public ClientThread(Socket socket) throws IOException { this.clientSocket = socket; @@ -34,26 +33,50 @@ public class ClientThread implements Runnable { @Override public void run() { while (clientSocket.isConnected()) { - String receivedMessage; try { - receivedMessage = in.readLine(); - } catch (IOException e) { - throw new RuntimeException(e); + String receivedMessage = in.readLine(); + String prefix = receivedMessage.substring(0, 3); + String restMessage = receivedMessage.substring(3); + + if (prefix.equals("RSA") && !rsaReceived) { + Client.serverPublicRSA = EncryptionUtil.stringToPublicKey(restMessage); + rsaReceived = true; + continue; + } + + if (prefix.equals("AES") && !aesReceived) { + String decryptedAES = EncryptionUtil.decryptWithRSA(restMessage, Client.keys.getPrivate()); + Client.aesKey = EncryptionUtil.aesKeyFromString(decryptedAES); + aesReceived = true; + continue; + } + + if (prefix.equals("TXT") && aesReceived && rsaReceived) { + String decryptedMessage = EncryptionUtil.decryptWithAES(restMessage, Client.aesKey); + System.out.println(decryptedMessage); + } + } catch (NoSuchPaddingException | IllegalBlockSizeException | IOException | NoSuchAlgorithmException | + InvalidKeySpecException | BadPaddingException | InvalidKeyException e) { + System.out.println("Disconnected from server!"); + System.exit(-1); + closeAllConnections(clientSocket, in, out); } + } + } - 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); - } + private void closeAllConnections(Socket socket, BufferedReader in, PrintWriter out) { + try { + if (socket != null) + socket.close(); - Client.serverPublicRSA = serverPublicKey; + if (in != null) + in.close(); + if (out != null) + out.close(); + + } catch (IOException e) { + e.printStackTrace(); } } } diff --git a/client/target/classes/org/orinprojects/Client.class b/client/target/classes/org/orinprojects/Client.class new file mode 100644 index 0000000..b048b98 Binary files /dev/null and b/client/target/classes/org/orinprojects/Client.class differ diff --git a/client/target/classes/org/orinprojects/ClientThread.class b/client/target/classes/org/orinprojects/ClientThread.class new file mode 100644 index 0000000..7551ce9 Binary files /dev/null and b/client/target/classes/org/orinprojects/ClientThread.class differ diff --git a/server/src/main/java/org/orinprojects/ClientHandler.java b/server/src/main/java/org/orinprojects/ClientHandler.java index 0d7ccef..e475ddd 100644 --- a/server/src/main/java/org/orinprojects/ClientHandler.java +++ b/server/src/main/java/org/orinprojects/ClientHandler.java @@ -1,18 +1,19 @@ 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 org.orinprojects.encryption.EncryptionUtil; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import java.io.*; import java.net.Socket; import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; -import java.util.Base64; public class ClientHandler implements Runnable { @@ -24,14 +25,18 @@ public class ClientHandler implements Runnable { private String username; - private int requests = 0; + private boolean rsaReceived = false; + + private boolean aesSent = false; 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()); + String key = EncryptionUtil.publicKeyToString(Server.serverKeys.getPublic()); + + out.println("RSA" + key); out.flush(); } @@ -40,26 +45,44 @@ public class ClientHandler implements Runnable { 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) { + String prefix = receivedMessage.substring(0, 3); + String restMessage = receivedMessage.substring(3); + + if (prefix.equals("RSA") && !rsaReceived) { + Server.clientKeys.put(username, EncryptionUtil.stringToPublicKey(restMessage)); + rsaReceived = true; + + String aesInString = EncryptionUtil.aesKeyToString(Server.aesKey); + String encryptedAES = EncryptionUtil.encryptWithRSA(aesInString, Server.clientKeys.get(username)); + + out.println("AES" + encryptedAES); + out.flush(); + + aesSent = true; + continue; + } + + if (prefix.equals("WLC")) { + this.username = restMessage; + continue; + } + + if (prefix.equals("TXT") && rsaReceived && aesSent) { + Server.clients.forEach(clientHandler -> { + if (!username.equals(clientHandler.username)) { + clientHandler.out.println(receivedMessage); + clientHandler.out.flush(); + } + }); + } + + } catch (NoSuchPaddingException | IllegalBlockSizeException | IOException | NoSuchAlgorithmException | + InvalidKeySpecException | BadPaddingException | InvalidKeyException 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) diff --git a/server/src/main/java/org/orinprojects/Server.java b/server/src/main/java/org/orinprojects/Server.java index 10832b0..1416020 100644 --- a/server/src/main/java/org/orinprojects/Server.java +++ b/server/src/main/java/org/orinprojects/Server.java @@ -1,7 +1,6 @@ package org.orinprojects; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.orinprojects.encryption.Encryption; +import org.orinprojects.encryption.EncryptionUtil; import org.orinprojects.exceptions.ArgumentsException; import javax.crypto.SecretKey; @@ -30,8 +29,8 @@ public class Server { public static SecretKey aesKey; public static void main(String[] args) throws IOException, ArgumentsException, NoSuchAlgorithmException { - Server.serverKeys = Encryption.generateRSAKey(); - Server.aesKey = Encryption.generateAESKey(); + Server.serverKeys = EncryptionUtil.generateRSAKeys(); + Server.aesKey = EncryptionUtil.generateAESKey(); int portNumber = getPortNumber(args); diff --git a/server/src/main/java/org/orinprojects/encryption/Encryption.java b/server/src/main/java/org/orinprojects/encryption/Encryption.java deleted file mode 100644 index da7f496..0000000 --- a/server/src/main/java/org/orinprojects/encryption/Encryption.java +++ /dev/null @@ -1,59 +0,0 @@ -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/encryption/EncryptionUtil.java b/server/src/main/java/org/orinprojects/encryption/EncryptionUtil.java new file mode 100644 index 0000000..90eca0e --- /dev/null +++ b/server/src/main/java/org/orinprojects/encryption/EncryptionUtil.java @@ -0,0 +1,99 @@ +package org.orinprojects.encryption; + +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +public class EncryptionUtil { + + public static final int rsaKeySize = 4096; + + public static final int aesKeySize = 256; + + public static KeyPair generateRSAKeys() throws NoSuchAlgorithmException { + KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); + generator.initialize(rsaKeySize); + + return generator.generateKeyPair(); + } + + public static String publicKeyToString(PublicKey publicKey) { + return Base64.getEncoder().encodeToString(publicKey.getEncoded()); + } + + public static String privateKeyToString(PrivateKey privateKey) { + return Base64.getEncoder().encodeToString(privateKey.getEncoded()); + } + + public static PublicKey stringToPublicKey(String encodedKey) throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] decodedKey = Base64.getDecoder().decode(encodedKey.getBytes()); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey); + + KeyFactory factory = KeyFactory.getInstance("RSA"); + + return factory.generatePublic(keySpec); + } + + public static PrivateKey stringToPrivateKey(String encodedKey) throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] decodedKey = Base64.getDecoder().decode(encodedKey.getBytes()); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey); + + KeyFactory kf = KeyFactory.getInstance("RSA"); + return kf.generatePrivate(keySpec); + } + + public static String encryptWithRSA(String data, PublicKey publicKey) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException { + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + + byte[] encryptedMessage = cipher.doFinal(data.getBytes()); + return Base64.getEncoder().encodeToString(encryptedMessage); + } + + public static String decryptWithRSA(String encryptedData, PrivateKey pk) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, pk); + + byte[] decryptedMessage = cipher.doFinal(Base64.getDecoder().decode(encryptedData)); + return new String(decryptedMessage); + } + + public static SecretKey generateAESKey() throws NoSuchAlgorithmException { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(aesKeySize); + + return keyGenerator.generateKey(); + } + + public static String encryptWithAES(String plainText, SecretKey aesKey) throws IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + Cipher aesChiper = Cipher.getInstance("AES"); + aesChiper.init(Cipher.ENCRYPT_MODE, aesKey); + + byte[] byteCipherText = aesChiper.doFinal(plainText.getBytes()); + + return Base64.getEncoder().encodeToString(byteCipherText); + } + + public static String decryptWithAES(String encryptedMessage, SecretKey aesKey) throws IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + Cipher aesChiper = Cipher.getInstance("AES"); + aesChiper.init(Cipher.DECRYPT_MODE, aesKey); + + byte[] byteCipherText = aesChiper.doFinal(Base64.getDecoder().decode(encryptedMessage)); + + return new String(byteCipherText); + } + + public static SecretKey aesKeyFromString(String encodedKey) { + byte[] decodedKey = Base64.getDecoder().decode(encodedKey); + return new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); + } + + public static String aesKeyToString(SecretKey secretKey) { + return Base64.getEncoder().encodeToString(secretKey.getEncoded()); + } + +} diff --git a/server/src/main/java/org/orinprojects/impl/MessageProtocol.java b/server/src/main/java/org/orinprojects/impl/MessageProtocol.java deleted file mode 100644 index 3d8a90c..0000000 --- a/server/src/main/java/org/orinprojects/impl/MessageProtocol.java +++ /dev/null @@ -1,50 +0,0 @@ -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 deleted file mode 100644 index 3923d7d..0000000 --- a/server/src/main/java/org/orinprojects/impl/MessageSender.java +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 4860914..0000000 --- a/server/src/main/java/org/orinprojects/impl/MessageType.java +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 1d40d83..0000000 --- a/server/src/main/java/org/orinprojects/interfaces/Protocol.java +++ /dev/null @@ -1,16 +0,0 @@ -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/server/target/classes/org/orinprojects/ClientHandler.class b/server/target/classes/org/orinprojects/ClientHandler.class new file mode 100644 index 0000000..7803bef Binary files /dev/null and b/server/target/classes/org/orinprojects/ClientHandler.class differ diff --git a/server/target/classes/org/orinprojects/Server.class b/server/target/classes/org/orinprojects/Server.class new file mode 100644 index 0000000..386feb4 Binary files /dev/null and b/server/target/classes/org/orinprojects/Server.class differ diff --git a/server/target/classes/org/orinprojects/encryption/EncryptionUtil.class b/server/target/classes/org/orinprojects/encryption/EncryptionUtil.class new file mode 100644 index 0000000..21da83e Binary files /dev/null and b/server/target/classes/org/orinprojects/encryption/EncryptionUtil.class differ diff --git a/server/target/classes/org/orinprojects/exceptions/ArgumentsException.class b/server/target/classes/org/orinprojects/exceptions/ArgumentsException.class new file mode 100644 index 0000000..9c57733 Binary files /dev/null and b/server/target/classes/org/orinprojects/exceptions/ArgumentsException.class differ