Allow 'startsecure' to be issued at any time

This commit is contained in:
Tobias Eidelpes 2020-12-29 19:02:36 +01:00
parent a9eab7cfb9
commit 93a2a87f07
2 changed files with 91 additions and 20 deletions

View File

@ -12,6 +12,8 @@ import java.util.Arrays;
import java.util.Base64;
import java.util.logging.Logger;
import at.ac.tuwien.dsg.orvell.Shell;
import at.ac.tuwien.dsg.orvell.annotation.Command;
import dslab.ComponentFactory;
import dslab.exception.FailedVerificationException;
import dslab.util.Config;
@ -22,6 +24,8 @@ import javax.crypto.spec.SecretKeySpec;
public class MessageClient implements IMessageClient, Runnable {
private static final Logger logger = Logger.getLogger(MessageClient.class.getName());
private final String componentId;
private final InputStream consoleIn;
private final String transferHost;
private final int transferPort;
@ -38,9 +42,11 @@ public class MessageClient implements IMessageClient, Runnable {
private PrintWriter dmtpOut;
private BufferedReader dmtpIn;
private PrintWriter dmapOut;
private PrintStream dmapOut;
private BufferedReader dmapIn;
private final Shell shell;
private Cipher aesEncryptCipher;
private Cipher aesDecryptCipher;
private byte[] challenge;
@ -62,6 +68,13 @@ public class MessageClient implements IMessageClient, Runnable {
this.mailboxUser = config.getString("mailbox.user");
this.mailboxPassword = config.getString("mailbox.password");
this.componentId = componentId;
this.consoleIn = in;
this.shell = new Shell(in, out);
this.shell.register(this);
this.shell.setPrompt(this.componentId + "> ");
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));
}
@ -72,7 +85,7 @@ public class MessageClient implements IMessageClient, Runnable {
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);
this.dmapOut = new PrintStream(this.dmapSocket.getOutputStream(), true);
String input = null;
String message = null;
@ -84,10 +97,8 @@ public class MessageClient implements IMessageClient, Runnable {
startSecure();
loginUser();
shell.run();
while (!Thread.currentThread().isInterrupted() && ((input = this.dmapIn.readLine()) != null)) {
// TODO implement commands
}
} catch (IOException e) {
logger.severe("Could not connect to MailboxHost " + this.mailboxHost + " on port " + this.mailboxPort);
shutdown();
@ -103,7 +114,7 @@ public class MessageClient implements IMessageClient, Runnable {
message = "login " + this.mailboxUser + " " + this.mailboxPassword;
this.dmapOut.println(getAesCiphertext(message));
String response = getAesPlaintext(this.dmapIn.readLine());
if (!response.startsWith("ok DMAP2.0"))
if (!response.startsWith("ok"))
shutdown();
}
@ -128,7 +139,6 @@ public class MessageClient implements IMessageClient, Runnable {
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 = generateChallengeMessage(serverPublicKey);
// Send clientChallenge to server
logger.info("Send clientchallenge to Server: " + clientChallenge);
@ -274,21 +284,25 @@ public class MessageClient implements IMessageClient, Runnable {
return (Base64.getEncoder().encodeToString(cipherTextChallenge));
}
@Command
@Override
public void inbox() {
}
@Command
@Override
public void delete(String id) {
}
@Command
@Override
public void verify(String id) {
}
@Command
@Override
public void msg(String to, String subject, String data) {
try {
@ -302,6 +316,7 @@ public class MessageClient implements IMessageClient, Runnable {
}
}
@Command
@Override
public void shutdown() {
if (dmtpSocket != null) {

View File

@ -13,14 +13,12 @@ import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.nio.charset.Charset;
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.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.LinkedList;
@ -41,6 +39,8 @@ public class DMAPConnection implements Runnable {
private Cipher aesEncryptCipher;
private Cipher aesDecryptCipher;
private boolean secure = false;
public DMAPConnection(Socket connection, ConcurrentHashMap<Email, LinkedList<Message>> storage, ConcurrentHashMap<String, String> userStorage, String componentId) {
this.componentId = componentId;
this.socket = connection;
@ -56,20 +56,21 @@ public class DMAPConnection implements Runnable {
this.out = new PrintWriter(socket.getOutputStream(), true);
this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println("ok DMAP2.0");
startSecure();
login();
loginLoop();
String userInput;
while (!Thread.currentThread().isInterrupted() && (userInput = in.readLine()) != null) {
if ("quit".equals(userInput)) {
out.println("ok bye");
shutdown();
loginLoop();
} else if ("logout".equals(userInput)) {
out.println("ok");
shutdown();
currentUser = null;
loginLoop();
} else if ("list".equals(userInput)) {
listMessages();
} else if ("delete".equals(userInput.split("\\s+")[0])) {
} else if (userInput.startsWith("delete")) {
if (userInput.split("\\s+").length == 2) {
try {
deleteMessage(userInput.split("\\s+")[1]);
@ -79,7 +80,7 @@ public class DMAPConnection implements Runnable {
} else {
out.println("Please supply a message id to delete!");
}
} else if ("show".equals(userInput.split("\\s+")[0])) {
} else if (userInput.startsWith("show")) {
if (userInput.split("\\s+").length == 2) {
try {
showMessage(userInput.split("\\s+")[1]);
@ -89,6 +90,8 @@ public class DMAPConnection implements Runnable {
} else {
out.println("Please supply a message id to show!");
}
} else if (userInput.startsWith("startsecure")) {
startSecure();
} else {
out.println("error protocol error");
shutdown();
@ -104,6 +107,57 @@ public class DMAPConnection implements Runnable {
}
}
private void loginLoop() {
String userInput;
try {
while (!Thread.currentThread().isInterrupted()) {
userInput = in.readLine();
if (userInput.startsWith("quit")) {
out.println("ok bye");
shutdown();
} else if (userInput.startsWith("login")) {
String[] args = userInput.split("\\s+");
if (args.length != 3)
out.println("Please specify a username and password to login!");
if (this.userStorage.containsKey(args[1])) {
// Check if username exists
if (args[2].equals(this.userStorage.get(args[1]))) {
// Check if password matches
for (Email email : this.storage.keySet()) {
if (args[1].equals(email.getUsername())) {
// Set current user if login successful
currentUser = email;
logger.info("User successfully logged in: " + currentUser.toString());
out.println("ok");
return;
}
}
} else {
out.println("error wrong password");
}
} else {
out.println("error unknown user");
}
} else if (userInput.startsWith("startsecure")) {
startSecure();
} else {
out.println("error not logged in");
}
}
} catch (InterruptedIOException ioe) {
logger.info("Received interrupt from parent. Shutting down...");
shutdown();
} catch (SocketException e) {
logger.finer("Received interrupt. Exiting " + this.toString());
shutdown();
} catch (IOException e) {
logger.severe("Failed to get IO-Stream");
e.printStackTrace();
shutdown();
}
}
/**
* Handles the startsecure command issued by the MessageClient.
*/
@ -111,7 +165,6 @@ public class DMAPConnection implements Runnable {
String userInput;
try {
userInput = in.readLine(); // Should always be "startsecure"
// Send componentId
out.println("ok " + componentId);
// Receive client challenge, secret key and iv
@ -129,6 +182,7 @@ public class DMAPConnection implements Runnable {
logger.severe("Received " + userInput + "from MessageClient. Did not match 'ok'");
shutdown();
}
this.secure = true; // Encrypted communication from now on
} catch (InterruptedIOException ioe) {
logger.info("Received interrupt from parent. Shutting down...");
shutdown();
@ -230,11 +284,11 @@ public class DMAPConnection implements Runnable {
try {
while (!Thread.currentThread().isInterrupted()) {
userInput = getAesPlaintext(in.readLine());
if ("quit".equals(userInput.split("\\s+")[0])) {
out.println(getAesCiphertext("ok bye"));
userInput = in.readLine();
if (userInput.startsWith("quit")) {
out.println("ok bye");
shutdown();
} else if ("login".equals(userInput.split("\\s+")[0])) {
} else if (userInput.startsWith("login")) {
String[] args = userInput.split("\\s+");
if (args.length != 3)
out.println("Please specify a username and password to login!");
@ -297,12 +351,14 @@ public class DMAPConnection implements Runnable {
}
private void listMessages() {
logger.info("'list' command received");
if (storage.get(currentUser).isEmpty()) {
out.println("You do not have any messages at the moment!");
return;
}
for (Message m : storage.get(currentUser)) {
logger.info("Printing message from user: " + m.listMessage());
out.println(m.listMessage());
}
}