Table of contents
- The problem with encrypted chat applications nowadays
- We need to go deeper…
- Backend side!
- Frontend magic!
- What next?
1op.eu - check this out. Source code here
The problem with encrypted chat applications nowadays
There are many great applications that do their best to ensure your privacy using advanced mathematics, like for example Signal besides many others.
The problem I’ve found is that all these solutions make you create an account, which is a time consuming task. For example: if you just want to send a secret password for your e-mail account to a friend and you don’t want anyone to find out, you will not both sign up just because of that. You need a quick and easy way to ensure that:
- No middleman knows what you are talking about. I’m talking about Server-side here, folks. We don’t even want a server to read our messages.
- No one can decrypt our messages later in time, even knowing our initial password. And that’s a tough one.
We need to go deeper…
I wanted to create a fairly simple chat application with ensured privacy. Of course, I could use AES encryption and encypt everything using a given password, but i didn’t want users that create weak passwords to be at risk of compromising their chat history later on. This is proof-of-concept secure chat application. Let’s give it our best.
The idea I’ve come upon is to use AES only for encrypting RSA Public Keys, and encrypt messages separately for each user later on. This ensures that even when the server gets compromised and our network gets spoofed, we still will be able to either see legitimate messages, or none at all (no middleman gets inside). And the same rogue middleman will not be able to decrypt our messages later on, even knowing the password that was entered initially. This solution does guarantee 100% privacy when a weak password is given, but only if we trust the server that it’s not trying to crack the password in real time. But we need to trust it at some point. Otherwise, you can read the code and set it up yourself. Or use stronger passwords, which probably is a better idea.
Backend side!
When it comes to the backend, I really wanted to use Phoenix Framework along with its Channels. I’ve enclosed the whole idea into this chunk of code (along with bunch of helper methods):
Server side is very simple. On init, it just starts the ETS :chatrooms
table and for each user that connects to the socket, server does pattern matching to find out what the result of the lookup was:
So either the room exists and sha512 of the initial password matches or no such room is found. Otherwise (when the password’s sha512 does not match), it gives back an error.
Connected user sends its RSA Public Key, which is encrypted using AES with the given password. Server generates a random color for him/her and appends both to an Elixir socket for this user. Phoenix Presence
keeps track of all connected users and as soon as new one connects it notifies everybody about the current state. New guy gets a channel state as soon as he/she connects.
Frontend magic!
Now I wanted this App to be fairly small, so I dropped the idea of using React/Redux, in which I would normally code this kind of App. As this is my private project, I wanted to experiment with something new. I’ve chosen Vue.js along with Vuex, because I’m an amazed by functional paradigm guy. :)
State, state, state
The idea is simple. We have a bunch of components and the state, in which we store messages and users. We also have a bunch of actions and mutations to modify our state as “purely” as we can. We dispatch actions in componenets and our application adapt to new state, because of Vue.js magic. This pretty much sums it up. Just like in React/Redux, but components are built differently. For example take a look at the Chat component:
For such a small project, I’ve found applying this amount of logic to the HTML rather appealing.
Guess what. JavaScript code is in the same file:
…and styles withing the same file, but please don’t make me paste them.
Notice the SEND_MESSAGE
call. We call store’s actions inside the component.
Back to the store!
I have made a big action
called REQUEST_ENTRANCE
inside the store.js
file that handles whole initial WebSocket connection (called from Entrance.vue
component).
It’s pretty self-explanatory. Reads almost as if it was written in english (or Ruby). :)
Phoenix Presence JavaScript file!
HOOK_CHANNEL
in above code snippets is a call to this action:
All thanks to phoenix.js
file that I copied from the Phoenix Framework. That is how I manage track of users connected. And that’s where the magic happens.
Every message sent is handled by SEND_MESSAGE
action:
Server-side splits received JSON and sends every user message encrypted especially for him/her. That’s where the channel.on
hook fires up the RECEIVE_MESSAGE
action:
Message gets decrypted using your own RSA Public Key and Chat
components rerenders. :)
What next?
I probably will not try to monetize this project and I don’t want to spend a single minute on trying to learn marketing nuances. I just wanted to have a cool project to put into the portfolio and I wanted to solve some real life problem, which is an easy to use end-to-end realtime encryption in web chat application. (That’s a real life problem if you are still wondering)