A secure client–relay–client messaging system implemented in Go, designed to provide mutual authentication, end-to-end confidentiality, message integrity, and forward secrecy over an untrusted relay using Hashes for encryption.
This project implements a custom cryptographic protocol combining public-key authentication, Diffie–Hellman key exchange, and HMAC-based authenticated encryption.
- Mutual authentication between clients and relay using challenge–response
- End-to-end encrypted client-to-client communication
- Perfect Forward Secrecy using ephemeral Diffie–Hellman keys
- Message integrity and authenticity using HMAC
- Replay-attack protection via session IDs and message sequence numbers
- Debug logging support for both relay and clients
- All client ↔ relay communication is encrypted using long-term public keys
- Client ↔ client messages are encrypted using a session key unknown to the relay
This project requires Go 1.20+
-
Start the relay server:
go run ./relay -
Start the client using
go run ./client -
Once the client starts, the relay registers the client and attempts to create a session once both clients are online. Users can start typing messages at each client at this point.
Currently supported client pseudonyms: alice, bob. Add --debug to the above commands to create debug logs.
- Public-key based challenge–response using nonces
- Ensures both relay and clients verify each other’s identity
- Prevents spoofing and replay attacks
- Clients establish a shared session key using Diffie–Hellman
- Key exchange messages are digitally signed
- Ephemeral secrets are deleted after session key derivation
-
Messages encrypted using an HMAC-derived keystream
-
Each message contains the following contents:
- Random IV
- Ciphertext
- HMAC over
(IV || ciphertext || sessionID || sequenceNumber)
-
Message sequence numbers prevent replay attacks
- Expand to more than two clients. Most of the code for this is already present.
- Use different keys for HMAC and encryption. Currently using the same key for convenience.