Authenticated IRC

C · Needham-Schroeder · AES-256 · Diffie-Hellman

A multi-user chat server in C where users have to authenticate before they can talk, and group conversations are end-to-end keyed between their members. I built it to implement a classic key-distribution protocol from the paper down to the sockets, rather than only reading the message diagrams.

Two services, one server

The server runs two listeners on separate ports: a key distribution centre (KDC) and the chat server itself. Each accepts connections concurrently so several clients can be served at once. Every user has a long-term symmetric key derived ahead of time with a password-based key derivation function, and that long-term key is what the authentication protocol bootstraps from.

Client long-term key Server process, two concurrent listeners KDC listener authentication port Chat server listener chat port authenticate present ticket

Needham-Schroeder authentication

Logging in follows the Needham-Schroeder scheme. A client first talks to the KDC, sending a fresh nonce along with its identity and the name of the chat server it wants to reach. The KDC mints a session key and a ticket, encrypts the reply under the user's long-term key, and sends it back. The client then presents the ticket to the chat server, which is what finally lets it in.

The nonce is the anti-replay anchor: the client checks that the value echoed back matches the one it sent, so a recorded KDC reply cannot be replayed at it later. After that handshake the client and the chat server share a session key and all further traffic rides on it.

Client KDC Chat server nonce, ID, target server session key + ticket + nonce encrypted under long-term key verify echoed nonce ticket client and chat server now share the session key

Group keys via multi-party Diffie-Hellman

Broadcasting to everyone is easy; the interesting case is a private group. When a user creates a group and invites others, the members run a multi-party Diffie-Hellman exchange so the group ends up with a shared secret that the server itself never holds. The initiator establishes a key with the first member, then folds in each additional member by passing the current shared secret encrypted under the new member's public key and mixing in their contribution. Group messages are encrypted under that derived key with AES-256, so users outside the group cannot read them.

Initiator + Member A Diffie-Hellman shared secret fold in B + Member B mix contribution group key encrypt Group messages AES-256 under key each new member is folded in the same way the secret is passed encrypted under each new member's public key; the server never holds it

Commands

What I took from it

Implementing Needham-Schroeder by hand is the clearest way to see why the nonce exchange matters, and why the protocol was later patched against replay. It is a study build, the long-term keys and the textbook handshake are not how I would ship a real chat system, but wiring up a KDC, ticket validation, and a group key agreement on top of raw sockets made the whole family of authentication protocols click.