diff --git a/src/main/java/dslab/client/MessageClient.java b/src/main/java/dslab/client/MessageClient.java index 0595dad..8d0533c 100644 --- a/src/main/java/dslab/client/MessageClient.java +++ b/src/main/java/dslab/client/MessageClient.java @@ -9,6 +9,7 @@ import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; +import java.util.Base64; import java.util.logging.Logger; import dslab.ComponentFactory; @@ -16,6 +17,7 @@ import dslab.util.Config; import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; public class MessageClient implements IMessageClient, Runnable { private static final Logger logger = Logger.getLogger(MessageClient.class.getName()); @@ -38,6 +40,8 @@ public class MessageClient implements IMessageClient, Runnable { private PrintWriter dmapOut; private BufferedReader dmapIn; + private Cipher aesCipher; + /** * Creates a new client instance. * @@ -80,7 +84,6 @@ public class MessageClient implements IMessageClient, Runnable { logger.severe("Could not connect to MailboxHost " + this.mailboxHost + " on port " + this.mailboxPort); shutdown(); } - } private void startSecure() throws IOException { @@ -94,8 +97,8 @@ public class MessageClient implements IMessageClient, Runnable { componentId = input.split("\\s+")[1]; try { // Attempt to read server public key from file called _pub.der - byte[] keyBytes = Files.readAllBytes(Paths.get(componentId + "_pub.der")); - logger.info("Read bytes from path " + Paths.get(componentId + ".der") + ": " + Arrays.toString(keyBytes)); + byte[] keyBytes = Files.readAllBytes(Paths.get("keys", "client", componentId + "_pub.der")); + logger.info("Read bytes from path " + Paths.get("keys", "client", componentId + "_pub.der") + ": " + Arrays.toString(keyBytes)); // Create X509 spec object from key X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); // Create generator for RSA scheme @@ -103,7 +106,7 @@ public class MessageClient implements IMessageClient, Runnable { // Make generator generate public key from X509 spec serverPublicKey = kf.generatePublic(spec); logger.info("Server's Public Key: " + serverPublicKey); - String clientChallenge = generateChallenge(serverPublicKey); + String clientChallenge = generateChallengeMessage(serverPublicKey); // TODO send clientChallenge to server // TODO Receive AES encrypted message saying "ok " // TODO Compare received client challenge with generated client challenge @@ -116,39 +119,80 @@ public class MessageClient implements IMessageClient, Runnable { } } - private SecretKey generateSecretKey() throws NoSuchAlgorithmException { - KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); - keyGenerator.init(256); - return keyGenerator.generateKey(); + private SecretKeySpec generateSecretKey() { + try { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(256, SecureRandom.getInstanceStrong()); + return new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES"); + } catch (NoSuchAlgorithmException e) { + logger.severe("This should not be happening!"); + e.printStackTrace(); + shutdown(); + } + return null; } - private byte[] generateIv() { + private IvParameterSpec generateIv() { // Size of IV corresponds to AES block size (=128bits=16bytes) byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); - return new IvParameterSpec(iv).getIV(); + return new IvParameterSpec(iv); } - private String generateChallenge(PublicKey serverPublicKey) { - SecureRandom secureRandom = new SecureRandom(); + private void setAesCipher(SecretKeySpec secretKey, IvParameterSpec iv) { try { - Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + this.aesCipher = Cipher.getInstance("AES/CTR/NoPadding"); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + logger.severe("This should not be happening!"); + e.printStackTrace(); + shutdown(); + } + + try { + this.aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + logger.severe("This should not be happening!"); + e.printStackTrace(); + shutdown(); + } + } + + private byte[] generateChallenge(PublicKey serverPublicKey) { + SecureRandom secureRandom = new SecureRandom(); + // Generate new random 32 byte challenge + byte[] clearTextChallenge = new byte[32]; + secureRandom.nextBytes(clearTextChallenge); + return clearTextChallenge; + } + + private String generateChallengeMessage(PublicKey serverPublicKey) { + SecureRandom secureRandom = new SecureRandom(); + byte[] clearTextChallenge = generateChallenge(serverPublicKey); + SecretKeySpec secretKeySpec = generateSecretKey(); + assert secretKeySpec != null; + IvParameterSpec iv = generateIv(); + // Save AES cipher for subsequent communication + setAesCipher(secretKeySpec, iv); + // Concatenate challenge, secretKey and IV + byte[] concatenated = new byte[80]; + System.arraycopy(clearTextChallenge, 0, concatenated, 0, 32); + System.arraycopy(secretKeySpec.getEncoded(), 0, concatenated, 32, 32); + System.arraycopy(iv.getIV(), 0, concatenated, 64, 16); + String base64Encoded = Base64.getEncoder().encodeToString(concatenated); + // Encrypt "ok " + Cipher cipher = null; + try { + cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, serverPublicKey); - // Generate new random 32 byte challenge - byte[] clearTextChallenge = new byte[32]; - secureRandom.nextBytes(clearTextChallenge); - // Generate secretKey and initialization vector - String secretKey = ""; - String IV = ""; - // Encrypt "ok " - cipher.update(("ok " + (new String(clearTextChallenge)) + " " + secretKey + " " + IV).getBytes(StandardCharsets.UTF_8)); + cipher.update(("ok " + base64Encoded).getBytes(StandardCharsets.UTF_8)); byte[] cipherTextChallenge = cipher.doFinal(); return (new String(cipherTextChallenge, StandardCharsets.UTF_8)); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { - logger.severe(e.getMessage()); + logger.severe("This should not be happening!"); + e.printStackTrace(); shutdown(); - return null; } + return null; } @Override