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 dslab.ComponentFactory;
|
||||
import dslab.exception.FailedVerificationException;
|
||||
import dslab.util.Config;
|
||||
|
||||
import javax.crypto.*;
|
||||
@ -40,7 +41,8 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
private PrintWriter dmapOut;
|
||||
private BufferedReader dmapIn;
|
||||
|
||||
private Cipher aesCipher;
|
||||
private Cipher aesEncryptCipher;
|
||||
private Cipher aesDecryptCipher;
|
||||
private byte[] challenge;
|
||||
|
||||
/**
|
||||
@ -73,20 +75,36 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
this.dmapOut = new PrintWriter(this.dmapSocket.getOutputStream(), true);
|
||||
|
||||
String input = null;
|
||||
String message = null;
|
||||
|
||||
if (!(input = this.dmapIn.readLine()).startsWith("ok DMAP2.0"))
|
||||
shutdown();
|
||||
|
||||
startSecure();
|
||||
loginUser();
|
||||
|
||||
while (!Thread.currentThread().isInterrupted() && ((input = this.dmapIn.readLine()) != null)) {
|
||||
// TODO initiate startsecure command
|
||||
// TODO login user (mailboxUser, mailboxPassword)
|
||||
// startSecure()
|
||||
// TODO implement commands
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.severe("Could not connect to MailboxHost " + this.mailboxHost + " on port " + this.mailboxPort);
|
||||
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 {
|
||||
String input;
|
||||
String componentId;
|
||||
@ -108,18 +126,65 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
serverPublicKey = kf.generatePublic(spec);
|
||||
logger.info("Server's Public Key: " + serverPublicKey);
|
||||
String clientChallenge = generateChallengeMessage(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) {
|
||||
// Send clientChallenge to server
|
||||
this.dmapOut.println(clientChallenge);
|
||||
// Receive AES encrypted message saying "ok <client-challenge>"
|
||||
String response = this.dmapIn.readLine();
|
||||
// Compare received client challenge with generated client challenge
|
||||
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());
|
||||
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() {
|
||||
try {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||
@ -142,7 +207,8 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
|
||||
private void setAesCipher(SecretKeySpec secretKey, IvParameterSpec iv) {
|
||||
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) {
|
||||
logger.severe("This should not be happening!");
|
||||
e.printStackTrace();
|
||||
@ -150,7 +216,8 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
}
|
||||
|
||||
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) {
|
||||
logger.severe("This should not be happening!");
|
||||
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