DS-Lab / src / main / java / dslab / crypto / MessageClientHash.java
MessageClientHash.java
Raw
package dslab.crypto;

import dslab.protocol.Message;
import dslab.routing.Address;

import javax.crypto.Mac;
import java.io.File;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Comparator;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import static dslab.util.Keys.readSecretKey;
import static dslab.util.Utils.listElements;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

public class MessageClientHash {

    private final Mac mac;

    private static final Logger LOG = Logger.getLogger(MessageClientHash.class.getSimpleName());

    public MessageClientHash() {

        try {
            this.mac = Mac.getInstance("HmacSHA256");
            mac.init(readSecretKey(new File("keys/hmac.key")));

        } catch (IOException | InvalidKeyException | NoSuchAlgorithmException e) {
            throw new RuntimeException("Unable to initialize hash functionality", e);
        }

    }

    public String calculateHashValue(Message message){
        // Build the message from all given components
        String messageString = String.join("\n",
                message.getSender().toString(),
                message.getRecipients().stream().map(Address::toString).sorted().collect(joining(",")),
                message.getSubject(),
                message.getData());

        return calculateHashValue(messageString);
    }

    public String calculateHashValue(String message) {

        // Build the MAC in a single step
        byte[] hash = mac.doFinal(message.getBytes());

        // Because our DMTP protocol transfers data using plain text -> We will
        // use the Base64 binary-to-text encoding to encode the hash before sending it.
        var result = Base64.getEncoder().encodeToString(hash);

        LOG.info("Calculated hash '" + result + "' for message " + message);
        return result;
    }

    public boolean isValid(Message message) {
        return calculateHashValue(message).equals(message.getHash());
    }

    public void calculateAndSet(Message message) {
        message.setHash(calculateHashValue(message));
    }
}