diff --git a/src/main/java/step2/Main.java b/src/main/java/step2/Main.java new file mode 100644 index 0000000..62b7c64 --- /dev/null +++ b/src/main/java/step2/Main.java @@ -0,0 +1,108 @@ +package step2; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.util.Base64; +import static common.Logger.*; +import static common.SocketManager.*; + +public class Main { + + private static final String PASSPHRASE = "laPassphrasePartagee"; + private static final int PBKDF2_ITERATION = 600_000; + private static final int KEY_LEN_BITS = 256; + + public static void main(String[] args){ + int port = 8888; + if (args.length >= 2 && args[0].equals("--port")) { + port = Integer.parseInt(args[1]); + } + + try (ServerSocket socket = new ServerSocket(port)) { + displayInfo("Server is running on port " + port + "\n waiting for the client to connect..."); + while (true) { + try { + handleClient(socket.accept()); + return; + } catch (IOException ignored) {} + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void handleClient(Socket socket) throws IOException, GeneralSecurityException { + socket.setSoTimeout(30000); + displayInfo("Client connected"); + + // Welcome message + send(socket, "Welcome to the phase 2 server!"); + + BufferedReader reader = new BufferedReader( + new InputStreamReader(socket.getInputStream()) + ); + + // Reçois le message chiffré et les éléments permettant de dériver la clé + String lineSalt = readResponse(reader); + String lineIv = readResponse(reader); + String lineCt = readResponse(reader); + displayReceived("Salt: " + lineSalt); + displayReceived("IV: " + lineIv); + displayReceived("Ciphered text: " + lineCt); + byte[] salt = Base64.getDecoder().decode(lineSalt.substring(5).trim()); + byte[] iv = Base64.getDecoder().decode(lineIv.substring(3).trim()); + byte[] ct = Base64.getDecoder().decode(lineCt.substring(3).trim()); + + // Dérivation clé PBKDF2-HMAC-SHA256 en 256 bits à partir des éléments reçus et de la passphrase commune + byte[] derivedKey = deriveKeyPBKDF2(PASSPHRASE.toCharArray(), salt, PBKDF2_ITERATION, KEY_LEN_BITS); + + // Déchiffrement du message avec AES/CBC/PKCS5Padding + String message = decryptAesCbcPkcs5(derivedKey, iv, ct); + displayInfo("Decrypted message: " + message); + + // Calcul du TAG : SHA3-256( key || message || "that's all folks" ) + byte[] tag = computeSha3_256(derivedKey, message.getBytes(StandardCharsets.UTF_8), "that's all folks".getBytes(StandardCharsets.UTF_8)); + String tagB64 = Base64.getEncoder().encodeToString(tag); + + // Envoie le TAG au client + send(socket, "TAG:" + tagB64); + displaySent("Tag: " + tagB64); + + // Client should OK/KO but doesn't ? + } + + private static byte[] deriveKeyPBKDF2(char[] passphrase, byte[] salt, int iterations, int keyLenBits) throws NoSuchAlgorithmException, InvalidKeySpecException { + PBEKeySpec spec = new PBEKeySpec(passphrase, salt, iterations, keyLenBits); + SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + SecretKey key = skf.generateSecret(spec); + return key.getEncoded(); + } + + private static String decryptAesCbcPkcs5(byte[] keyBytes, byte[] ivBytes, byte[] ciphertext) throws GeneralSecurityException, UnsupportedEncodingException { + SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); + cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); + byte[] plain = cipher.doFinal(ciphertext); + return new String(plain, StandardCharsets.UTF_8); + } + + private static byte[] computeSha3_256(byte[] keyPart, byte[] messageBytes, byte[] suffix) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA3-256"); + md.update(keyPart); + md.update(messageBytes); + md.update(suffix); + return md.digest(); + } + +} \ No newline at end of file