https://github.com/double-k-3033/cmd-chat-cpp/raw/refs/heads/main/ScreenRecorderProject5.mp4
A command-line group chat application written in C++17. Users connect to a shared server and exchange end-to-end encrypted messages in real time. Authentication is handled with SRP-6a (Secure Remote Password), and every message is encrypted with a Fernet-compatible scheme (AES-128-CBC + HMAC-SHA256) derived from the shared SRP session key.
- Zero-knowledge password authentication — SRP-6a ensures the server never sees the plaintext password, and the shared secret is proved on both sides before any message is accepted.
- End-to-end message encryption — messages are encrypted client-side with a per-session Fernet token (AES-128-CBC, random IV, HMAC-SHA256) and decrypted by the receiving clients.
- Room key derivation — a room-wide key is derived via HKDF-SHA256 from the SRP session key and a server-supplied salt, so all authenticated clients share the same symmetric key.
- Multi-client support — the server handles each connection in its own thread.
- Online user list — the client UI shows the current roster of connected users alongside the chat history.
- Cross-platform — builds on Windows (Winsock2) and Linux/macOS (POSIX sockets) from the same source.
cmd_chat_cpp/
├── CMakeLists.txt # Build configuration
├── client/
│ ├── main.cpp # Client entry point
│ ├── client.hpp # Client class declaration
│ └── client.cpp # Client implementation (SRP auth, send/recv, UI)
├── server/
│ ├── main.cpp # Server entry point
│ ├── server.hpp/.cpp # ChatServer: accepts connections, dispatches threads
│ ├── srp_auth.hpp/.cpp # SRPAuthManager wrapping csrp
│ ├── stores.hpp/.cpp # In-memory message and session stores
│ ├── managers.hpp/.cpp # Connection manager
│ └── models.hpp # Message and UserSession structs
└── common/
├── crypto.hpp # HKDF-SHA256, Fernet encrypt/decrypt (header-only)
├── base64.hpp # URL-safe Base64 encode/decode (header-only)
├── json_io.hpp # JSON framing over raw sockets (header-only)
└── uuid.hpp # UUID v4 generator (header-only)
| Library | Version | Fetched via |
|---|---|---|
| nlohmann/json | v3.11.3 | CMake FetchContent |
| csrp | commit 15d6bd7 |
CMake FetchContent |
| OpenSSL | system (≥ 1.1) | find_package |
| C++ standard library | C++17 | — |
OpenSSL must be installed separately. On Windows the build script looks for OpenSSL in C:\Program Files\OpenSSL-Win64 by default (the Shining Light installer default).
- CMake ≥ 3.20
- A C++17 compiler (MSVC 2019+, GCC 10+, Clang 12+)
- OpenSSL development libraries
- Git (required by FetchContent)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config ReleaseExecutables are placed in build\Release\:
cmd_chat_server.execmd_chat_client.exe
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)Executables are placed in build/:
cmd_chat_servercmd_chat_client
If OpenSSL is installed in a non-standard location, pass -DOPENSSL_ROOT_DIR=/path/to/openssl to the first CMake command.
cmd_chat_server serve <ip> <port> --password <room-password>
Example:
./cmd_chat_server serve 0.0.0.0 9000 --password mysecretroomThe <room-password> is the shared secret that all clients must supply to authenticate. The server derives an SRP verifier from it and a random salt at startup.
cmd_chat_client connect <ip> <port> <username> <password>
Example:
./cmd_chat_client connect 127.0.0.1 9000 alice mysecretroomMultiple clients can connect simultaneously with different usernames but the same room password. Once connected, type a message and press Enter to send. Press Ctrl-C to disconnect.
Client Server
| |
|--- SRP step 1: username + A ------>|
|<-- SRP step 2: salt + B -----------|
|--- SRP step 3: client proof M ---->|
|<-- SRP step 4: server proof H_AMK -|
| |
| (both sides now hold session_key) |
| |
| room_key = HKDF(session_key, |
| room_salt, |
| "room_key") |
| |
|--- Fernet(room_key, plaintext) --->|
| (broadcast) |
|<-- Fernet(room_key, plaintext) ----|
- SRP-6a (via csrp) performs mutual authentication. Neither side learns the password; only a shared high-entropy session key is produced.
- HKDF-SHA256 derives a deterministic 32-byte room key from the session key and a server-generated salt, so every authenticated client ends up with the same key.
- Fernet (AES-128-CBC + HMAC-SHA256 with a random IV per message) provides authenticated encryption for every chat message. The server relays ciphertext it cannot read.