Implement HMAC verification
This commit is contained in:
parent
5ad8cded18
commit
a7994736f1
@ -1,8 +1,17 @@
|
||||
package dslab;
|
||||
|
||||
import dslab.exception.MissingInputException;
|
||||
import dslab.util.Keys;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Message {
|
||||
@ -89,6 +98,23 @@ public class Message {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a HMAC hash of the message.
|
||||
*
|
||||
* @return A Base64 encoded hash of the message.
|
||||
* @throws IOException Thrown if the HMAC key (in "keys/hmac.key") cannot be found.
|
||||
* @throws NoSuchAlgorithmException Thrown if HmacSHA256 is not known.
|
||||
* @throws InvalidKeyException Thrown if the key is not valid.
|
||||
*/
|
||||
public String calculateHash() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
|
||||
byte[] hashFormat = String.join("\n", getFrom().toString(), printTo(), getSubject(), getData())
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec hmac = Keys.readSecretKey(new File("keys/hmac.key"));
|
||||
mac.init(hmac);
|
||||
return (Base64.getEncoder().encodeToString(mac.doFinal(hashFormat)));
|
||||
}
|
||||
|
||||
public String listMessage() {
|
||||
return getId() + " " + getFrom() + " " + getSubject();
|
||||
}
|
||||
|
||||
@ -10,13 +10,17 @@ import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import at.ac.tuwien.dsg.orvell.Shell;
|
||||
import at.ac.tuwien.dsg.orvell.StopShellException;
|
||||
import at.ac.tuwien.dsg.orvell.annotation.Command;
|
||||
import dslab.ComponentFactory;
|
||||
import dslab.Email;
|
||||
import dslab.Message;
|
||||
import dslab.exception.FailedVerificationException;
|
||||
import dslab.exception.MalformedInputException;
|
||||
import dslab.util.Config;
|
||||
|
||||
import javax.crypto.*;
|
||||
@ -277,12 +281,13 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
|
||||
/**
|
||||
* Generates the full challenge message to be sent to the server.
|
||||
*
|
||||
* <p>
|
||||
* The challenge message is of the format:
|
||||
* ok <client-challenge> <secret-key> <iv>
|
||||
* The parameters are base64 encoded individually, then they are concatenated:
|
||||
* ok <base64-client-challenge> <base64-secret-key> <base64-iv>
|
||||
* The whole string is then AES encrypted and the result base64 encoded again.
|
||||
*
|
||||
* @return A base64 encoded full client challenge.
|
||||
*/
|
||||
private String generateChallengeMessage(PublicKey serverPublicKey) {
|
||||
@ -331,11 +336,70 @@ public class MessageClient implements IMessageClient, Runnable {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls a message by id from the MailboxServer and compares the calculated hash against the one received via the
|
||||
* 'hash' field.
|
||||
*
|
||||
* @param id The message id.
|
||||
*/
|
||||
@Command
|
||||
@Override
|
||||
public void verify(String id) {
|
||||
logger.info("Received 'verify' command for id " + id);
|
||||
Message msg = new Message();
|
||||
String response;
|
||||
// Get message from MailboxServer
|
||||
try {
|
||||
dmapOut.println(getAesCiphertext("show " + id));
|
||||
response = getAesPlaintext(dmapIn.readLine());
|
||||
if (response.startsWith("error")) {
|
||||
this.shell.out().println(response);
|
||||
return;
|
||||
}
|
||||
String[] commands = response.split("\n");
|
||||
if (commands.length != 6) {
|
||||
logger.severe("error expected different message format");
|
||||
return;
|
||||
}
|
||||
msg.setFrom(new Email(commands[0].split("\\s+")[1]));
|
||||
|
||||
String[] addresses = commands[1].split("\\s+")[1].split(",");
|
||||
for (String email : addresses) {
|
||||
msg.addTo(new Email(email));
|
||||
}
|
||||
|
||||
String[] split = commands[2].split("\\s+", 2);
|
||||
msg.setSubject(split.length == 2 ? split[1] : "");
|
||||
|
||||
split = commands[3].split("\\s+", 2);
|
||||
msg.setData(split.length == 2 ? split[1] : "");
|
||||
|
||||
split = commands[4].split("\\s+", 2);
|
||||
msg.setHash(split.length == 2 ? split[1] : "");
|
||||
|
||||
if (!commands[5].startsWith("ok")) {
|
||||
logger.severe("error expected 'ok', got " + commands[5] + " instead");
|
||||
}
|
||||
|
||||
String calculatedHash = msg.calculateHash();
|
||||
logger.info("Calculated hash: " + calculatedHash);
|
||||
if (msg.getHash().equals(calculatedHash)) {
|
||||
this.shell.out().println("ok");
|
||||
} else {
|
||||
this.shell.out().println("error");
|
||||
}
|
||||
} catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
logger.severe("Error during encryption/decryption");
|
||||
e.printStackTrace();
|
||||
shutdown();
|
||||
} catch (IOException e) {
|
||||
logger.severe("Cannot communicate with server");
|
||||
e.printStackTrace();
|
||||
shutdown();
|
||||
} catch (MalformedInputException e) {
|
||||
logger.severe("Error during reading of message");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Command
|
||||
|
||||
@ -109,6 +109,8 @@ public class DMAPConnection implements Runnable {
|
||||
if (secure) {
|
||||
out.println(getAesCiphertext("You are already secure!"));
|
||||
} else startSecure();
|
||||
} else if (userInput.startsWith("inbox")) {
|
||||
printInbox();
|
||||
} else {
|
||||
if (secure) {
|
||||
out.println(getAesCiphertext("error protocol error"));
|
||||
@ -130,6 +132,9 @@ public class DMAPConnection implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void printInbox() {
|
||||
}
|
||||
|
||||
private void loginLoop() {
|
||||
String userInput;
|
||||
|
||||
@ -330,8 +335,8 @@ public class DMAPConnection implements Runnable {
|
||||
for (Message m : storage.get(currentUser)) {
|
||||
if (m.getId() == i) {
|
||||
if (secure) {
|
||||
out.println(getAesCiphertext(m.toString()));
|
||||
} else out.println(m.toString());
|
||||
out.println(getAesCiphertext(m.toString() + "ok"));
|
||||
} else out.println(m.toString() + "\nok");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -349,11 +354,14 @@ public class DMAPConnection implements Runnable {
|
||||
}
|
||||
|
||||
for (Message m : storage.get(currentUser)) {
|
||||
logger.info("Printing message from user: " + m.listMessage());
|
||||
logger.fine("Printing message from user: " + m.listMessage());
|
||||
if (secure) {
|
||||
out.println(getAesCiphertext(m.listMessage()));
|
||||
} else out.println(m.listMessage());
|
||||
}
|
||||
if (secure) {
|
||||
out.println(getAesCiphertext("ok"));
|
||||
} else out.println("ok");
|
||||
}
|
||||
|
||||
public void deleteMessage(String id) throws MessageNotFoundException, BadPaddingException, IllegalBlockSizeException {
|
||||
|
||||
@ -110,6 +110,10 @@ public class DMTPConnection implements Runnable {
|
||||
String data = userInput.split("\\s+", 2)[1];
|
||||
msg.setData(data);
|
||||
out.println("ok");
|
||||
} else if (userInput.startsWith("hash")) {
|
||||
String hash = userInput.split("\\s+", 2)[1];
|
||||
msg.setHash(hash);
|
||||
out.println("ok");
|
||||
} else {
|
||||
out.println("error protocol error");
|
||||
shutdown();
|
||||
|
||||
@ -92,6 +92,13 @@ public class ClientConnection implements Runnable {
|
||||
logger.info("Setting data to: " + data);
|
||||
msg.setData(data);
|
||||
out.println("ok");
|
||||
} else if (userInput.startsWith("hash")) {
|
||||
String hash = "";
|
||||
if (userInput.split("\\s+", 2).length > 1)
|
||||
hash = userInput.split("\\s+", 2)[1];
|
||||
logger.info("Setting hash to: " + hash);
|
||||
msg.setHash(hash);
|
||||
out.println("ok");
|
||||
} else {
|
||||
out.println("error protocol error");
|
||||
shutdown();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user