Implement skeleton for MessageClient
This commit is contained in:
parent
970b62ed72
commit
93157eb9de
@ -1,12 +1,44 @@
|
||||
package dslab.client;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.*;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import dslab.ComponentFactory;
|
||||
import dslab.util.Config;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
|
||||
public class MessageClient implements IMessageClient, Runnable {
|
||||
private static final Logger logger = Logger.getLogger(MessageClient.class.getName());
|
||||
|
||||
private final String transferHost;
|
||||
private final int transferPort;
|
||||
private final String mailboxHost;
|
||||
private final int mailboxPort;
|
||||
|
||||
private final String transferEmail;
|
||||
|
||||
private final String mailboxUser;
|
||||
private final String mailboxPassword;
|
||||
|
||||
private Socket dmtpSocket;
|
||||
private Socket dmapSocket;
|
||||
|
||||
private PrintWriter dmtpOut;
|
||||
private BufferedReader dmtpIn;
|
||||
private PrintWriter dmapOut;
|
||||
private BufferedReader dmapIn;
|
||||
|
||||
/**
|
||||
* Creates a new client instance.
|
||||
@ -17,12 +49,95 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
* @param out the output stream to write console output to
|
||||
*/
|
||||
public MessageClient(String componentId, Config config, InputStream in, PrintStream out) {
|
||||
this.transferHost = config.getString("transfer.host");
|
||||
this.transferPort = config.getInt("transfer.port");
|
||||
this.mailboxHost = config.getString("mailbox.host");
|
||||
this.mailboxPort = config.getInt("mailbox.port");
|
||||
this.transferEmail = config.getString("transfer.email");
|
||||
this.mailboxUser = config.getString("mailbox.user");
|
||||
this.mailboxPassword = config.getString("mailbox.password");
|
||||
|
||||
logger.info(String.format("TransferHost: %s\nTransferPort: %d\nMailboxHost: %s\nMailboxPort: %d\nTransferEmail: %s\nMailboxUser: %s\nMailboxPassword: %s",
|
||||
transferHost, transferPort, mailboxHost, mailboxPort, transferEmail, mailboxUser, mailboxPassword));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logger.info("Starting connection to MailboxHost on " + this.mailboxHost + " on port " + this.mailboxPort);
|
||||
this.dmapSocket = new Socket(this.mailboxHost, this.mailboxPort);
|
||||
this.dmapIn = new BufferedReader(new InputStreamReader(this.dmapSocket.getInputStream()));
|
||||
this.dmapOut = new PrintWriter(this.dmapSocket.getOutputStream(), true);
|
||||
|
||||
String input = null;
|
||||
if (!(input = this.dmapIn.readLine()).startsWith("ok DMAP2.0"))
|
||||
shutdown();
|
||||
|
||||
while (!Thread.currentThread().isInterrupted() && ((input = this.dmapIn.readLine()) != null)) {
|
||||
// TODO initiate startsecure command
|
||||
// TODO login user (mailboxUser, mailboxPassword)
|
||||
// startSecure()
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.severe("Could not connect to MailboxHost " + this.mailboxHost + " on port " + this.mailboxPort);
|
||||
shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void startSecure() throws IOException {
|
||||
String input;
|
||||
String componentId;
|
||||
PublicKey serverPublicKey;
|
||||
this.dmapOut.println("startsecure");
|
||||
input = this.dmapIn.readLine();
|
||||
if (input.startsWith("ok") && (input.split("\\s+").length == 2)) {
|
||||
// Get the component-id from the server
|
||||
componentId = input.split("\\s+")[1];
|
||||
try {
|
||||
// Attempt to read server public key from file called <component-id>_pub.der
|
||||
byte[] keyBytes = Files.readAllBytes(Paths.get(componentId + "_pub.der"));
|
||||
logger.info("Read bytes from path " + Paths.get(componentId + ".der") + ": " + Arrays.toString(keyBytes));
|
||||
// Create X509 spec object from key
|
||||
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
|
||||
// Create generator for RSA scheme
|
||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
||||
// Make generator generate public key from X509 spec
|
||||
serverPublicKey = kf.generatePublic(spec);
|
||||
logger.info("Server's Public Key: " + serverPublicKey);
|
||||
String clientChallenge = generateChallenge(serverPublicKey);
|
||||
// TODO send clientChallenge to server
|
||||
// TODO Receive AES encrypted message saying "ok <client-challenge>"
|
||||
// TODO Compare received client challenge with generated client challenge
|
||||
// TODO Answer with AES encrypted "ok" if matching and use AES cipher for subsequent communication
|
||||
// TODO immediately terminate upon encountering an error (pull try-catch out of submethods)
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
logger.severe(e.getMessage());
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String generateChallenge(PublicKey serverPublicKey) {
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
try {
|
||||
Cipher 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 <clearTextChallenge> <secretKey> <IV>"
|
||||
cipher.update(("ok " + (new String(clearTextChallenge)) + " " + secretKey + " " + IV).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());
|
||||
shutdown();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -42,12 +157,42 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
|
||||
@Override
|
||||
public void msg(String to, String subject, String data) {
|
||||
|
||||
try {
|
||||
logger.info("Starting connection to TransferServer on host " + this.transferHost + " on port " + this.transferPort);
|
||||
this.dmtpSocket = new Socket(this.transferHost, this.transferPort);
|
||||
this.dmtpIn = new BufferedReader(new InputStreamReader(this.dmtpSocket.getInputStream()));
|
||||
this.dmtpOut = new PrintWriter(this.dmtpSocket.getOutputStream(), true);
|
||||
} catch (IOException e) {
|
||||
logger.severe("Could not connect to TransferHost " + transferHost + " on port " + transferPort);
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (dmtpSocket != null) {
|
||||
try {
|
||||
this.dmtpSocket.close();
|
||||
this.dmtpOut.close();
|
||||
this.dmtpIn.close();
|
||||
} catch (IOException e) {
|
||||
logger.severe("Could not close connection to TransferHost");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (dmapSocket != null) {
|
||||
try {
|
||||
this.dmapSocket.close();
|
||||
this.dmapOut.close();
|
||||
this.dmapIn.close();
|
||||
} catch (IOException e) {
|
||||
logger.severe("Could not close connection to MailboxHost");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user