Package org.hive2hive.core.network.messages

Source Code of org.hive2hive.core.network.messages.MessageReplyHandler$VerifyMessage

package org.hive2hive.core.network.messages;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.SignatureException;

import net.tomp2p.peers.PeerAddress;
import net.tomp2p.rpc.ObjectDataReply;

import org.hive2hive.core.H2HSession;
import org.hive2hive.core.exceptions.GetFailedException;
import org.hive2hive.core.exceptions.NoPeerConnectionException;
import org.hive2hive.core.exceptions.NoSessionException;
import org.hive2hive.core.network.NetworkManager;
import org.hive2hive.core.security.EncryptionUtil;
import org.hive2hive.core.security.HybridEncryptedContent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This is the general message handler of each node. It checks if received
* message is ok (depends on message e.g. routed to correct node). If accepted
* the message gets independently handled in a own thread. As soon as the
* handler thread has started the reply handler gives immediately response to
* the sender node. This design allows a quick and non-blocking message
* handling.
*
* @author Nendor, Seppi
*/
public class MessageReplyHandler implements ObjectDataReply {

  private static final Logger logger = LoggerFactory.getLogger(MessageReplyHandler.class);

  private final NetworkManager networkManager;

  public MessageReplyHandler(NetworkManager networkManager) {
    this.networkManager = networkManager;
  }

  @Override
  public Object reply(PeerAddress sender, Object request) {
    if (!(request instanceof HybridEncryptedContent)) {
      logger.error("Received unknown object.");
      return null;
    }

    H2HSession session;
    try {
      if (networkManager.getSession() == null) {
        throw new NoSessionException();
      } else {
        session = networkManager.getSession();
      }
    } catch (NoSessionException e) {
      logger.warn("Currently no user is logged in! Keys for decryption needed. Node ID = '{}'.",
          networkManager.getNodeId());
      return AcceptanceReply.FAILURE;
    }

    HybridEncryptedContent encryptedMessage = (HybridEncryptedContent) request;

    // get signature
    String senderId = encryptedMessage.getUserId();
    byte[] signature = encryptedMessage.getSignature();
    if (senderId == null || signature == null) {
      logger.warn("No signature for message.");
      return AcceptanceReply.FAILURE_SIGNATURE;
    }

    // asymmetrically decrypt message
    byte[] decryptedMessage = null;
    try {
      KeyPair keys = session.getKeyPair();
      decryptedMessage = EncryptionUtil.decryptHybrid(encryptedMessage, keys.getPrivate());
    } catch (Exception e) {
      logger.warn("Decryption of message failed.", e);
      return AcceptanceReply.FAILURE_DECRYPTION;
    }

    // deserialize decrypted message
    Object message = null;
    try {
      message = EncryptionUtil.deserializeObject(decryptedMessage);
    } catch (IOException | ClassNotFoundException e) {
      logger.error("Message could not be deserialized. Reason = '{}'.", e.getMessage());
    }

    if (message != null && message instanceof BaseMessage) {
      BaseMessage receivedMessage = (BaseMessage) message;

      // verify the signature
      if (session.getKeyManager().containsPublicKey(senderId)) {
        if (!verifySignature(senderId, decryptedMessage, signature))
          return AcceptanceReply.FAILURE_SIGNATURE;

        // give a network manager reference to work (verify, handle)
        try {
          receivedMessage.setNetworkManager(networkManager);
        } catch (NoPeerConnectionException e) {
          logger.error("Cannot process the message because the peer is not connected.");
          return AcceptanceReply.FAILURE;
        }

        // check if message gets accepted
        AcceptanceReply reply = receivedMessage.accept();
        if (AcceptanceReply.OK == reply) {
          // handle message in own thread
          logger.debug("Received and accepted the message. Node ID = '{}'.",
              networkManager.getNodeId());
          new Thread(receivedMessage).start();
        } else {
          logger.warn("Received but denied a message. Acceptance reply = '{}', Node ID = '{}'.",
              reply, networkManager.getNodeId());
        }

        return reply;
      } else {
        new Thread(new VerifyMessage(senderId, decryptedMessage, signature, receivedMessage)).start();
        return AcceptanceReply.OK_PROVISIONAL;
      }
    } else {
      logger.error("Received unknown object.");
      return null;
    }
  }

  private boolean verifySignature(String senderId, byte[] decryptedMessage, byte[] signature) {
    try {
      PublicKey publicKey = networkManager.getSession().getKeyManager().getPublicKey(senderId);
      if (EncryptionUtil.verify(decryptedMessage, signature, publicKey)) {
        logger.debug("Message signature from user '{}' verified. Node ID = '{}'.", senderId,
            networkManager.getNodeId());
        return true;
      } else {
        logger.error("Message from user '{}' has wrong signature. Node ID = '{}'.", senderId,
            networkManager.getNodeId());
        return false;
      }
    } catch (GetFailedException | InvalidKeyException | SignatureException | NoSessionException e) {
      logger.error("Verifying message from user '{}' failed. Reason = '{}'.", senderId, e.getMessage());
      return false;
    }
  }

  private class VerifyMessage implements Runnable {

    private final String senderId;
    private final byte[] decryptedMessage;
    private final byte[] signature;
    private final BaseMessage message;

    public VerifyMessage(String senderId, byte[] decryptedMessage, byte[] signature, BaseMessage message) {
      this.senderId = senderId;
      this.decryptedMessage = decryptedMessage;
      this.signature = signature;
      this.message = message;
    }

    @Override
    public void run() {
      if (!verifySignature(senderId, decryptedMessage, signature))
        return;

      // give a network manager reference to work (verify, handle)
      try {
        message.setNetworkManager(networkManager);
      } catch (NoPeerConnectionException e) {
        logger.error("Cannot process the message because the peer is not connected.");
        return;
      }

      // check if message gets accepted
      AcceptanceReply reply = message.accept();
      if (AcceptanceReply.OK == reply) {
        // handle message in own thread
        logger.debug("Received and accepted the message. Node ID = '{}'.", networkManager.getNodeId());
        new Thread(message).start();
      } else {
        logger.warn("Received but denied a message. Acceptance reply = '{}', Node ID = '{}'.", reply,
            networkManager.getNodeId());
      }
    }

  }
}
TOP

Related Classes of org.hive2hive.core.network.messages.MessageReplyHandler$VerifyMessage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.