Skip to content

Latest commit

 

History

History
162 lines (114 loc) · 5.52 KB

File metadata and controls

162 lines (114 loc) · 5.52 KB

PQC

chat-tui

Just a simple way of working with Post-Quantum Cryptography (PQC) in Go. Also makes use of OpenTUI to create, well, a TUI.

Disclaimer: not much thought was put into selecting the configurations/algorithms for these. Use at your own peril.

TUI

Commands

  • /create <room-name>: creates a new room;
  • /delete <room-name>: deletes a room - if you are the creator;
  • /join <room-name>: joins a room;
  • /leave <room-name>: leaves a room;
  • /quit, /exit, /q, :wq, :q, :wqa: quits the TUI.

Development

Installing

You need Go and Bun installed.

cd core/ && go mod tidy
cd tui/ && bun i

Note

If you use the just commands, it needs tygo to generate the TS types automatically from Go.

Running

In one terminal, start the WS server:

# With `just`
just start-server
# Manually
cd core/
go run ./cmd/server

In another terminal(s), start the client(s) with the TUI:

# With `just`
just start-tui
# Manually
# First build the go code:
cd core && go build ./cmd/client
# Now run the tui
cd tui && bun run dev

Tip

You can use multiple clients and just one server. The server will handle the data encryption from one client to another and will fanout the information to all connected clients in the room.

Architecture

graph TB
    subgraph "Go WebSocket Server"
        WS_SERVER[WebSocket Server<br/>gorilla/websocket<br/>:8080]
        HUB[Hub - Connection Manager<br/>Manages multiple clients]
        WS_SERVER --> HUB
    end

    subgraph "Go WebSocket Client"
        WS_CLIENT[WebSocket Client<br/>gorilla/websocket]
        STDIN_READER[Stdin Reader<br/>JSON commands]
        STDOUT_WRITER[Stdout Writer<br/>JSON responses]
        
        WS_CLIENT --> |HTTP/WebSocket| WS_SERVER
        STDIN_READER --> WS_CLIENT
        WS_CLIENT --> STDOUT_WRITER
    end

    subgraph "TypeScript TUI"
        TUI[TUI Application<br/>@opentui/core<br/>TypeScript/Bun]
        GO_PROCESS[Go Process Spawner<br/>child_process.spawn]
        STDIN_COMM[Stdin Communication<br/>JSON commands]
        STDOUT_COMM[Stdout Communication<br/>JSON responses]
        
        TUI --> GO_PROCESS
        GO_PROCESS --> |spawns| WS_CLIENT
        TUI --> |sends commands to| STDIN_COMM
        STDOUT_COMM --> |receives data from| TUI
    end

    %% Data flow
    TUI -.-> |user input| STDIN_COMM
    STDIN_COMM -.-> |JSON commands| STDIN_READER
    STDOUT_WRITER -.-> |JSON responses| STDOUT_COMM
    STDOUT_COMM -.-> |updates| TUI

    %% WebSocket connection
    WS_CLIENT <--> |WebSocket<br/>ws://localhost:8080/ws| WS_SERVER

    %% Styling
    classDef go fill:#00ADD8,color:#white
    classDef ts fill:#3178c6,color:#white
    classDef ws fill:#6f42c1,color:#white
    
    class WS_SERVER,HUB,WS_CLIENT,STDIN_READER,STDOUT_WRITER go
    class TUI,GO_PROCESS,STDIN_COMM,STDOUT_COMM ts
    class WS_SERVER,WS_CLIENT ws
Loading

Architecture Overview:

  • WebSocket Server (Go): Hub managing multiple client connections using gorilla/websocket
  • WebSocket Client (Go): Connects to server via HTTP/WebSocket, reads JSON commands from stdin, writes responses to stdout
  • TUI (TypeScript): Uses @opentui/core, spawns Go process, communicates via stdin/stdout with JSON messages

Key Technologies:

  • Go + gorilla/websocket for server/client
  • TypeScript + @opentui core for TUI
  • JSON communication between TUI and Go client
  • WebSocket protocol for real-time messaging

Cryptography

Explanation

  1. First step: exchange keys using ML-KEM (post quantum cryptography);

  2. Second step: make the shared key usable and more secure with KDF (Key Derivation Function);

  3. Third step: use the key from KDF (improved shared key), to encrypt the message using some symmetric-key algorithm;

  4. Fourth step: transmit the encrypted message;

  5. Fifth step: on the other side, decrypt the message using the same symmetric-key algorithm.

Key exchange

The process of key exchange is made using the post-quantum cryptography ML-KEM. This process can be described between two parties (Alice and Bob) as:

  • Alice, the person initiating the request, first generates a pair of keys: one public ("encapsulationKey") and one private ("decapsulation key");
  • Alice then sends the public key to Bob in bytes format over the wire;
  • Bob in the keyExchange gets the public key from that array of bytes and generates a ciphertext and a shared key ("sharedSecret") from it along with some random bytes from crypto/rand. This "sharedSecret" MUST stay private;
  • Bob returns to Alice the ciphertext;
  • Alice uses its own private key (the decapsulation key) to get the shared key ("sharedSecret") from that ciphertext;
  • Now both Alice and Bob have the same shared key ("sharedSecret") without ever sharing that over the wire, only sharing public information (the public key - a.k.a "encapsulationKey" - and the ciphertext).

KDF

Using a key derivation function (KDF) improves the security of the shared secret by making it more uniform, adequating its size to be used to other symmetric functions and removing possible characteristics that could make it easier for an attacker to try toguess it.

We are using HKDF.

Symmetric-key cryptography

Because each party has its own secret key, we can know use a faster and still secure way of encrypting data. We are using ChaCha20Poly1305, which is considered post-quantum secure.