Implement startsecure() and login() on client
This commit is contained in:
parent
d1bf65698d
commit
e311064c48
@ -13,6 +13,7 @@ import java.util.Base64;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import dslab.ComponentFactory;
|
import dslab.ComponentFactory;
|
||||||
|
import dslab.exception.FailedVerificationException;
|
||||||
import dslab.util.Config;
|
import dslab.util.Config;
|
||||||
|
|
||||||
import javax.crypto.*;
|
import javax.crypto.*;
|
||||||
@ -40,7 +41,8 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
private PrintWriter dmapOut;
|
private PrintWriter dmapOut;
|
||||||
private BufferedReader dmapIn;
|
private BufferedReader dmapIn;
|
||||||
|
|
||||||
private Cipher aesCipher;
|
private Cipher aesEncryptCipher;
|
||||||
|
private Cipher aesDecryptCipher;
|
||||||
private byte[] challenge;
|
private byte[] challenge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,20 +75,36 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
this.dmapOut = new PrintWriter(this.dmapSocket.getOutputStream(), true);
|
this.dmapOut = new PrintWriter(this.dmapSocket.getOutputStream(), true);
|
||||||
|
|
||||||
String input = null;
|
String input = null;
|
||||||
|
String message = null;
|
||||||
|
|
||||||
if (!(input = this.dmapIn.readLine()).startsWith("ok DMAP2.0"))
|
if (!(input = this.dmapIn.readLine()).startsWith("ok DMAP2.0"))
|
||||||
shutdown();
|
shutdown();
|
||||||
|
|
||||||
|
startSecure();
|
||||||
|
loginUser();
|
||||||
|
|
||||||
while (!Thread.currentThread().isInterrupted() && ((input = this.dmapIn.readLine()) != null)) {
|
while (!Thread.currentThread().isInterrupted() && ((input = this.dmapIn.readLine()) != null)) {
|
||||||
// TODO initiate startsecure command
|
// TODO implement commands
|
||||||
// TODO login user (mailboxUser, mailboxPassword)
|
|
||||||
// startSecure()
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.severe("Could not connect to MailboxHost " + this.mailboxHost + " on port " + this.mailboxPort);
|
logger.severe("Could not connect to MailboxHost " + this.mailboxHost + " on port " + this.mailboxPort);
|
||||||
shutdown();
|
shutdown();
|
||||||
|
} catch (IllegalBlockSizeException | BadPaddingException e) {
|
||||||
|
logger.severe(e.getMessage());
|
||||||
|
shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loginUser() throws BadPaddingException, IllegalBlockSizeException, IOException {
|
||||||
|
String message;
|
||||||
|
logger.info("Trying to log in using " + this.mailboxUser + " " + this.mailboxPassword);
|
||||||
|
message = "login " + this.mailboxUser + " " + this.mailboxPassword;
|
||||||
|
this.dmapOut.println(getAesCiphertext(message));
|
||||||
|
String response = getAesPlaintext(this.dmapIn.readLine());
|
||||||
|
if (!response.startsWith("ok DMAP2.0"))
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
private void startSecure() throws IOException {
|
private void startSecure() throws IOException {
|
||||||
String input;
|
String input;
|
||||||
String componentId;
|
String componentId;
|
||||||
@ -108,18 +126,65 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
serverPublicKey = kf.generatePublic(spec);
|
serverPublicKey = kf.generatePublic(spec);
|
||||||
logger.info("Server's Public Key: " + serverPublicKey);
|
logger.info("Server's Public Key: " + serverPublicKey);
|
||||||
String clientChallenge = generateChallengeMessage(serverPublicKey);
|
String clientChallenge = generateChallengeMessage(serverPublicKey);
|
||||||
// TODO send clientChallenge to server
|
// Send clientChallenge to server
|
||||||
// TODO Receive AES encrypted message saying "ok <client-challenge>"
|
this.dmapOut.println(clientChallenge);
|
||||||
// TODO Compare received client challenge with generated client challenge
|
// Receive AES encrypted message saying "ok <client-challenge>"
|
||||||
// TODO Answer with AES encrypted "ok" if matching and use AES cipher for subsequent communication
|
String response = this.dmapIn.readLine();
|
||||||
// TODO immediately terminate upon encountering an error (pull try-catch out of submethods)
|
// Compare received client challenge with generated client challenge
|
||||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
verifyChallenge(response);
|
||||||
|
// Answer with AES encrypted "ok" if matching and use AES cipher for subsequent communication
|
||||||
|
this.dmapOut.println(getAesCiphertext("ok"));
|
||||||
|
} catch (NoSuchAlgorithmException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException | FailedVerificationException e) {
|
||||||
logger.severe(e.getMessage());
|
logger.severe(e.getMessage());
|
||||||
shutdown();
|
shutdown();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger.severe("MailboxHost " + mailboxHost + " on port " + mailboxPort + " did not respond with 'ok' <component-id>");
|
||||||
|
shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a plaintext message, encrypts and encodes it and returns the encoded ciphertext ready for sending.
|
||||||
|
* @param message Plaintext message
|
||||||
|
* @return B64 encoded and AES encrypted ciphertext
|
||||||
|
*/
|
||||||
|
private String getAesCiphertext(String message) throws IllegalBlockSizeException, BadPaddingException {
|
||||||
|
byte[] cipherText = aesEncryptCipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return Base64.getEncoder().encodeToString(cipherText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an AES encrypted message, decrypts and decodes it and returns the plaintext.
|
||||||
|
* @param message B64 encoded and AES encrypted message
|
||||||
|
* @return B64 decoded and AES decrypted plaintext
|
||||||
|
*/
|
||||||
|
private String getAesPlaintext(String message) throws BadPaddingException, IllegalBlockSizeException {
|
||||||
|
byte[] cipherText = Base64.getDecoder().decode(message.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return new String(aesDecryptCipher.doFinal(cipherText));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyChallenge(String response) throws FailedVerificationException {
|
||||||
|
// Decrypt to base64 encoded byte array
|
||||||
|
String plainText;
|
||||||
|
try {
|
||||||
|
plainText = new String(aesDecryptCipher.doFinal(Base64.getDecoder().decode(response)));
|
||||||
|
logger.info("Decrypted AES challenge: " + plainText);
|
||||||
|
} catch (IllegalBlockSizeException | BadPaddingException e) {
|
||||||
|
logger.severe("Error during decryption of client challenge. Aborting...");
|
||||||
|
shutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Decode <client-challenge>
|
||||||
|
if (plainText.split("\\s+").length != 2)
|
||||||
|
shutdown();
|
||||||
|
String clientChallenge = new String(Base64.getDecoder().decode(plainText.split("\\s+")[1]));
|
||||||
|
// Compare received challenge with sent
|
||||||
|
|
||||||
|
if (!clientChallenge.equals(new String(this.challenge)))
|
||||||
|
throw new FailedVerificationException("Server's clientChallenge " + clientChallenge + " does not match sent clientChallenge " + new String(this.challenge));
|
||||||
|
}
|
||||||
|
|
||||||
private SecretKeySpec generateSecretKey() {
|
private SecretKeySpec generateSecretKey() {
|
||||||
try {
|
try {
|
||||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||||
@ -142,7 +207,8 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
|
|
||||||
private void setAesCipher(SecretKeySpec secretKey, IvParameterSpec iv) {
|
private void setAesCipher(SecretKeySpec secretKey, IvParameterSpec iv) {
|
||||||
try {
|
try {
|
||||||
this.aesCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
this.aesEncryptCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
|
this.aesDecryptCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||||
logger.severe("This should not be happening!");
|
logger.severe("This should not be happening!");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -150,7 +216,8 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
|
this.aesEncryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
|
||||||
|
this.aesDecryptCipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
|
||||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||||
logger.severe("This should not be happening!");
|
logger.severe("This should not be happening!");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
package dslab.exception;
|
||||||
|
|
||||||
|
public class FailedVerificationException extends Exception {
|
||||||
|
public FailedVerificationException(String errorMessage) {
|
||||||
|
super(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user