An online end-to-end encryption chat application using Java RMI

by Efraim Rodrigues on October 23, 2017

Tagged as: java, rmi, encryption.

Available on GitHub

Intro

Let’s take the typical Alice and Bob scenario for instance. In this scenario Bob wants to communicate with Alice in a secure way. A client/server application is enough to satisfy Alice’s and Bob’s needs. However, end to end encryption will be used to ensure a man-in-the-middle attack is not feasible. So, this will be a real time chat which will have its messages centralized in the server. The centralized messages must be encrypted in a way only the clients are able to decipher them. Sender and receiver information will be encrypted too.

Server and clients are set with a symmetric key so they can safely exchange identity and asymmetric keys. As a result of this it will be impossible for a sniffer to identify clients and public keys. To address the process of identifying and communication between users and servers, each user will generate a pair of asymmetric keys locally and will share their public keys with the server service. It is important to mention that this communication will be done with a symmetric encryption technique. So, even if somehow a sniffer puts hands on the symmetric key, this sniffer might be able to decrypt one’s public key. But will never be able to decrypt a message because the end user is the only one able to do that with its private key (which was never shared).

Symmetric Encryption Technique: AES

Asymmetric Encryption Technique: RSA

Java RMI

All the communication is done over the Java RMI interface. RMI stands for Remote Method Invocation. This programming interface allows you to invoke remote classes’ methods. Most of Java RMI applications implement two applications, server and client. The server application will hold a server object and allow clients to use its methods. Client applications are required to have access to the objects interface, so they are oblivious to the way these methods are implemented.

Java RMI classes must extends from the java.rmi.Remote class.

Implementation


Server side

Server available on GitHub

As stated before, Java RMI applications implement a client and server. Before proceeding to the central object of the server, let’s lay eyes on ChatConUserInterface. This interface represents a user.

public interface ChatConUserInterface extends Remote,Serializable  {
	abstract protected void enviarMensagem(String mensagem) throws RemoteException;
	abstract protected ArrayList<String> getMensagens() throws RemoteException;
	abstract protected String getPublicKey() throws RemoteException;
	abstract protected Integer getContador() throws RemoteException;
}

1.abstract void enviarMensagem(String mensagem) throws RemoteException;

This method gets and adds a message to the user’s mailbox or buffer represented by a list of strings. These strings shall be consumed by the client application.

2.abstract ArrayList getMensagens() throws RemoteException;

This will simply return the buffer of messages.

3.abstract String getPublicKey() throws RemoteException;

User’s public key will be retreived by other user’s for encryption

4.abstract Integer getContador() throws RemoteException;

Returns the current size of the buffer

In addition, the central object of the server is the class ChatCon which is an implementation of ChatConInterface as follows:

public interface ChatConInterface extends Remote {
	abstract public void enviarMensagem(String user, String mensagem) throws RemoteException;
	abstract public ChatConUserInterface adicionaUsuario(String username, String publicKey) throws RemoteException;
	abstract public void removeUsuario(String username) throws RemoteException;
	abstract public ArrayList<String> getUsuarios() throws RemoteException;
	abstract public String getPublicKey(String username) throws RemoteException;
	abstract public boolean isOnline(String username) throws RemoteException;
}

This interface supports simple operations:

1.abstract public void enviarMensagem(String user, String mensagem) throws RemoteException;

Gets the username and encrypted message (receiver’s private key) and forwards to the user

2.abstract public ChatConUserInterface adicionaUsuario(String username, String publicKey) throws RemoteException;

Instantiates and returns a ChatConUser. Used for a user to login

3.abstract public void removeUsuario(String username) throws RemoteException;

Removes the specific user from the list of users. It’s used to logout

4.abstract public ArrayList getUsuarios() throws RemoteException;

Returns the list of logged in users.

5.abstract public String getPublicKey(String username) throws RemoteException;

Returns the public key of a certain user

6.abstract public boolean isOnline(String username) throws RemoteException;

Simply returns true if user is online, false otherwise

Client side

Client available on GitHub

Perhaps the client side application is the simplest one because it will only use what is already implemented. For this, it is only required that ChatConInterface and ChatConUserInterface are visible. The client application was built upon the JavaFX platform.

RMI Client Application

RMI Client Application