In this post, we’ll dive into the secure chat service you can set up with Go, designed to work over a Tailscale network. This service uses encrypted communication channels, secure key exchanges, and allows client registration, broadcasting, and private messaging—all over an encrypted TCP connection. Let’s walk through the setup, functionality, and security protocols used in this project.
Project Overview and Setup
The repository at github.com/drewwalton19216801/padserve contains the full implementation for a server and client in Go, each designed to run on a Tailscale network. Tailscale simplifies VPN setup and provides a reliable network environment to run this chat service securely. Each client and server establishes their own key pairs and shared secrets, keeping communication protected.
To start, ensure that Tailscale is installed and configured on your system, and run the server as follows:
go run ./cmd/server
BashOnce the server is started, connect a client:
go run ./cmd/client <YourID> <TailscaleServer>
BashReplace <YourID>
with a unique identifier and <TailscaleServer>
with the server’s IP or hostname within the Tailscale network.
Server Code Analysis
The server listens on the Tailscale network, automatically finding its IP address using a helper function getTailscaleIP()
. After identifying the Tailscale IP, it listens on port 12345 and manages clients’ connections.
The primary server operations are as follows:
Client Registration:
- The server allows each client to register with a unique identifier. Upon successful registration, it sends the server’s public key to the client.
Key Exchange with ECDH:
- The server generates an ECDH (Elliptic Curve Diffie-Hellman) key pair to secure communication. Using this pair, the server can compute a shared secret with each client, which is derived by combining the client and server public keys.
Message Handling and Encryption:
- Clients can send encrypted messages either to specific recipients or broadcast them to all clients. Each client can securely decrypt messages using a shared AES encryption key, derived from the shared ECDH secret.
Client List and Server Information:
- The server provides commands for clients to request the list of active clients, as well as commands to display server info and available commands.
Client Code Analysis
The client’s purpose is to securely register, exchange keys, and communicate over the server. Here’s a breakdown of the client’s key functionalities:
Connection and Registration:
- After registering with the server, the client receives the server’s public key, allowing both parties to compute a shared ECDH secret.
Message Encryption:
- For secure communication, the client uses AES encryption when broadcasting and XOR encryption for one-to-one communication. Each message includes an OTP (One-Time Pad) key for XOR, ensuring that messages can only be decrypted by the intended recipient.
Listening for Messages:
- The client continuously listens for incoming messages, automatically decrypting them using the shared key.
Security Protocols and Implementation Details
The security of this chat service relies on a combination of ECDH, AES, and XOR encryption techniques. Here’s a deeper look:
ECDH Key Exchange:
- Both client and server generate ECDH key pairs upon initialization. Using the server’s public key, each client can compute a shared secret, and both parties derive an AES encryption key from this shared secret.
- The shared secret is then hashed with SHA-256 to produce a 256-bit key suitable for AES encryption.
AES Encryption for Broadcasts:
- AES in CBC (Cipher Block Chaining) mode is used to encrypt broadcast messages. AES provides robust encryption for handling larger messages across multiple clients.
- The service encrypts messages with the shared AES key, using a randomly generated IV (Initialization Vector) to prevent ciphertext patterns from revealing information about the plaintext.
OTP XOR Encryption for Direct Messages:
- Direct messages to specific clients use OTP (One-Time Pad) XOR encryption, generating a unique key for each message. XOR ensures that only the intended recipient can decrypt the message, provided they have the matching OTP key.
Tailscale for VPN-like Security:
- Using Tailscale adds an additional layer of security by creating a private network over the public internet, ensuring that all communication occurs within a secured, authenticated channel. Tailscale handles IP management and authentication, so only trusted devices within the Tailscale network can connect.
Server Commands Overview
The server offers several commands for both clients and administrators:
- REGISTER <ID>: Registers a client with a unique ID.
- SEND <RecipientID|ALL> <Message>: Sends a message to a specified client or broadcasts it to all.
- LIST: Lists all active clients.
- INFO: Displays server IP, Tailscale IP, and active client IDs.
- SERVERHELP: Lists all available server commands.
Key Code Snippets
ECDH Key Generation
In both client and server:
serverPrivKey, _ := ecdh.P256().GenerateKey(rand.Reader)
serverPubKey := serverPrivKey.PublicKey()
GoAES Encryption and Decryption
For encryption:
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
GoFor decryption:
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(decrypted, ciphertext)
GoConclusion
The Go-based secure chat service, built to operate over Tailscale, provides strong security guarantees through its hybrid encryption model. By leveraging Tailscale, ECDH key exchange, and AES encryption, this project demonstrates how to build a secure messaging platform from the ground up.
Check out the padserve GitHub repository for the complete code and start experimenting with secure chat services yourself.