Resources
- Git repository: https://codeberg.org/jacklund/torchat-rs
Background
Torchat is a project I’ve been working on for a while - it’s an anonymous, authenticated, peer-to-peer chat program, encrypted end-to-end, which is entirely serverless. The application uses Tor Onion Services as both the communication endpoints and as the authentication mechanism, while preserving anonymity.
I was looking for a way to solve a few problems with encrypted chat:
- Most users are behind NAT-ted firewalls or routers, so connections from outside are difficult at best
- Even if you could solve the first problem, mapping the user you’re trying to connect to to an IP address is difficult when IP addresses change, users use VPNs, etc. Most apps solve this by forcing users to connect to a centralized server (or set of servers), which solves those problems, but opens up new problems, like DNS spoofing, compromised servers, or a service provider supplying authorities with logs (yeah, I’m looking at you, ProtonMail).
Instead, if two people wanted to chat anonymously and securely (and potentially even anonymous from each other), they could both start up Tor onion services, exchange their onion service addresses, and Tor would do the routing. Additionally:
- Since the whole purpose of Tor is to obfuscate the IP addresses of who is connecting to what, there would be a very small likelihood of either person’s locations being leaked
- Since there’s no single server involved, server compromise, by either technical or legal attack, would be useless
- The onion address (and it’s underlying ED25519 public key) would serve as the identity of the users - as long as they controlled the underlying private key, you could be assured that you’re connecting to who you think you are.
Current Status
I wrote the entire code in Rust, using iced for the UI, tor-client-lib, another project of mine, as the Tor interface (and to help with some of the cryptographic transformations from Tor onion service crypto to what I’m using), noise for the cryptographic handshake, and ED25519 for the handshake (necessary, since the public/private keypair of both sides are ED25519), ChaCha20Poly1305 AEAD for the cipher, and SHA256 for the hash.
Basically, each side, when they create a new onion service, has a public/private keypair associated with the service (the onion address of the service is an encoded version of the public key). They each use that, along with some other information, to perform a Diffie-Hellman key exchange, using the noise protocol, to derive a key to encrypt the communications using ChaCha20Poly1305 for the cipher, and SHA256 for the hashing function.
What’s Next
Here’s my general to do list:
- Make the UI better - as I said before, I’m not a UI designer
- See about using Signal’s ratchet algorithm for the encryption
- Figure out how to do multi-person chat.
- Possible way to go: Use a DHT like Kademlia for user discovery and distributed storage of the chat history