* 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

View File

@@ -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)

View File

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

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.