* added encryption to chat

This commit is contained in:
dseredenko
2023-07-26 16:00:51 +02:00
parent d35aa29a0e
commit 7508801049
22 changed files with 280 additions and 208 deletions

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

14
.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="client" />
<module name="server" />
</profile>
</annotationProcessing>
</component>
</project>

11
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/client/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/client/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/server/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/server/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

20
.idea/jarRepositories.xml generated Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="central" />
<option name="url" value="https://nexus.scanacs.de/repository/maven-public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

12
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="openjdk-20" project-jdk-type="JavaSDK" />
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -1,14 +1,10 @@
package org.orinprojects; package org.orinprojects;
import org.orinprojects.encryption.Encryption; import org.orinprojects.encryption.EncryptionUtil;
import org.orinprojects.exceptions.ArgumentsException; 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.net.Socket;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.*; import java.util.*;
@@ -19,12 +15,14 @@ public class Client {
public static PublicKey serverPublicRSA; public static PublicKey serverPublicRSA;
public static SecretKey aesKey;
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
keys = Encryption.generateRSAKey(); Map<String, String> validatedArguments = getValidatedDataFromArguments(args);
// System.out.println(keys.getPublic());
keys = EncryptionUtil.generateRSAKeys();
String username = readUsername(); String username = readUsername();
Map<String, String> validatedArguments = getValidatedDataFromArguments(args);
Socket socket = new Socket( Socket socket = new Socket(
validatedArguments.get("ip"), validatedArguments.get("ip"),
@@ -36,18 +34,24 @@ public class Client {
Thread thr = new Thread(client); Thread thr = new Thread(client);
thr.start(); thr.start();
client.out.println("WLC" + username);
client.out.flush();
client.out.println("RSA" + EncryptionUtil.publicKeyToString(keys.getPublic()));
// MessageSender.sendMessage(client.out, new MessageProtocol().setWelcomeMessage(username, new AssymetricKeyPairSerializ(keys.getPublic()))); client.out.flush();
while (socket.isConnected()) { while (socket.isConnected()) {
Scanner scanner = new Scanner(System.in); Scanner scanner = new Scanner(System.in);
String inputText = scanner.nextLine(); String inputText = scanner.nextLine();
// String encrypted = Encryption.Encrypt(inputText.getBytes(), serverPublic); if (!client.aesReceived && !client.rsaReceived)
// MessageSender.sendMessage(client.out, new MessageProtocol().setTextMessage(new String(encrypted))); 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();
}
} }
} }

View File

@@ -1,19 +1,16 @@
package org.orinprojects; package org.orinprojects;
import org.bouncycastle.crypto.InvalidCipherTextException; import org.orinprojects.encryption.EncryptionUtil;
import org.orinprojects.encryption.Encryption;
import org.orinprojects.impl.MessageProtocol;
import org.orinprojects.impl.MessageType;
import org.orinprojects.interfaces.Protocol;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*; import java.io.*;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class ClientThread implements Runnable { public class ClientThread implements Runnable {
@@ -23,7 +20,9 @@ public class ClientThread implements Runnable {
final PrintWriter out; final PrintWriter out;
private PublicKey publicKey; public boolean rsaReceived = false;
public boolean aesReceived = false;
public ClientThread(Socket socket) throws IOException { public ClientThread(Socket socket) throws IOException {
this.clientSocket = socket; this.clientSocket = socket;
@@ -34,26 +33,50 @@ public class ClientThread implements Runnable {
@Override @Override
public void run() { public void run() {
while (clientSocket.isConnected()) { while (clientSocket.isConnected()) {
String receivedMessage;
try { try {
receivedMessage = in.readLine(); 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);
}
}
}
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) { } catch (IOException e) {
throw new RuntimeException(e); e.printStackTrace();
}
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;
} }
} }
} }

Binary file not shown.

View File

@@ -1,18 +1,19 @@
package org.orinprojects; package org.orinprojects;
import org.orinprojects.encryption.Encryption; import org.orinprojects.encryption.EncryptionUtil;
import org.orinprojects.impl.MessageProtocol;
import org.orinprojects.impl.MessageSender;
import org.orinprojects.impl.MessageType;
import org.orinprojects.interfaces.Protocol;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*; import java.io.*;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec; import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class ClientHandler implements Runnable { public class ClientHandler implements Runnable {
@@ -24,14 +25,18 @@ public class ClientHandler implements Runnable {
private String username; private String username;
private int requests = 0; private boolean rsaReceived = false;
private boolean aesSent = false;
public ClientHandler(Socket socket) throws IOException { public ClientHandler(Socket socket) throws IOException {
this.clientSocket = socket; this.clientSocket = socket;
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
out = new PrintWriter(clientSocket.getOutputStream()); out = new PrintWriter(clientSocket.getOutputStream());
out.println(Server.serverKeys.getPublic()); String key = EncryptionUtil.publicKeyToString(Server.serverKeys.getPublic());
out.println("RSA" + key);
out.flush(); out.flush();
} }
@@ -40,26 +45,44 @@ public class ClientHandler implements Runnable {
while (clientSocket.isConnected()) { while (clientSocket.isConnected()) {
try { try {
String receivedMessage = in.readLine(); String receivedMessage = in.readLine();
byte[] rsa = receivedMessage.getBytes(StandardCharsets.UTF_8); String prefix = receivedMessage.substring(0, 3);
PublicKey serverPublicKey = KeyFactory.getInstance("RSA") String restMessage = receivedMessage.substring(3);
.generatePublic(new X509EncodedKeySpec(rsa));
out.println(Encryption.encryptRSA(new String(Server.aesKey.getEncoded()), serverPublicKey)); 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(); out.flush();
} catch (Exception e) {
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); 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) { private void closeAllConnections(Socket socket, BufferedReader in, PrintWriter out) {
try { try {
if (socket != null) if (socket != null)

View File

@@ -1,7 +1,6 @@
package org.orinprojects; package org.orinprojects;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.orinprojects.encryption.EncryptionUtil;
import org.orinprojects.encryption.Encryption;
import org.orinprojects.exceptions.ArgumentsException; import org.orinprojects.exceptions.ArgumentsException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
@@ -30,8 +29,8 @@ public class Server {
public static SecretKey aesKey; public static SecretKey aesKey;
public static void main(String[] args) throws IOException, ArgumentsException, NoSuchAlgorithmException { public static void main(String[] args) throws IOException, ArgumentsException, NoSuchAlgorithmException {
Server.serverKeys = Encryption.generateRSAKey(); Server.serverKeys = EncryptionUtil.generateRSAKeys();
Server.aesKey = Encryption.generateAESKey(); Server.aesKey = EncryptionUtil.generateAESKey();
int portNumber = getPortNumber(args); int portNumber = getPortNumber(args);

View File

@@ -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();
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -1,5 +0,0 @@
package org.orinprojects.impl;
public enum MessageType {
FILE, TXT, WLC, AES, RSA
}

View File

@@ -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();
}

Binary file not shown.