# Analysis and Client Implementation for Project Colette V53 This document provides a detailed technical breakdown of the connection process to a Project Colette V53 server. It dissects the cryptographic handshake, packet structure, and message exchange logic as implemented in the `main.py` Python client. ## [*] Core Concepts The data exchange protocol is a custom protocol layered on top of standard TCP. The encryption is built using the **NaCl** cryptographic library (referenced in the C# code as `TweetNaCl`), which provides: - **Asymmetric Encryption**: `Curve25519` for key exchange via Elliptic-curve Diffie–Hellman (ECDH). - **Symmetric Encryption**: `XSalsa20-Poly1305` for stream encryption after the session is established. - **Hashing**: `Blake2b` for nonce generation. Each message (packet) in the protocol is prefixed with a 7-byte header: - **Message ID** (2 bytes): The identifier for the message type. - **Payload Length** (3 bytes): The length of the upcoming payload. - **Version** (2 bytes): The version of the message. ## [!] Step-by-Step Breakdown of the Connection Process The process from the initial connection to a fully established encrypted session involves the exchange of four key packets. --- ### **Step 1: `ClientHello` (ID: 10100)** - **Direction**: Client -> Server - **Encryption**: None This is the very first packet the client sends after establishing a TCP connection. Its sole purpose is to initiate a session on the server and signal readiness to begin the handshake. The payload of this packet is irrelevant to the cryptography and can be filled with zeros. --- ### **Step 2: `LoginMessage` (ID: 10101)** - **Direction**: Client -> Server - **Encryption**: Asymmetric (`Box`) This is the key packet from the client, where the core of the key exchange magic happens. #### **Client-Side Preparation (Before Sending):** 1. **Server's Key**: The client uses the server's static `server_public_key`, which is known beforehand (extracted from the server's source code). 2. **Client's Keys**: The client generates a new, **ephemeral (temporary)** `Curve25519` key pair—`client_public_key` and `client_private_key`. This pair will only be used for the current session. 3. **Shared Secret (`s`)**: The client immediately computes the pre-master shared secret (`shared_secret` or `s`) using its new private key and the server's public key. This is a standard ECDH operation. In `PyNaCl`, this is done with `Box.beforenm(server_public_key, client_private_key)`. This secret `s` will be needed to decrypt the server's response. 4. **Client Nonce (`RNonce`)**: The client generates 24 random bytes, the `client_nonce`. The server refers to this as the `RNonce` (Receiver's Nonce). It is a critical part of the handshake. #### **Packet Structure and Transmission:** The `10101` packet consists of two parts: 1. **Client's Public Key** (32 bytes): Sent in cleartext. 2. **Encrypted Payload**: - **Data to Encrypt**: The plaintext to be encrypted contains: 1. A temporary session key (24 bytes, generated by the client but ignored by the server). 2. The `client_nonce` (`RNonce`) (24 bytes). 3. The actual login data (account ID, client version, etc.), serialized into a bytestream. - **Nonce for Encryption**: The nonce for this operation is calculated as a hash of the public keys: `blake2b(client_public_key + server_public_key)`. - **Encryption Process**: The data above is encrypted using `Box(client_private_key, server_public_key).encrypt(...)`. --- ### **Step 3: `ServerHello` (ID: 20100)** - **Direction**: Server -> Client - **Encryption**: Asymmetric (`Box`) This is the server's response, which completes the asymmetric phase of the handshake. #### **Client-Side Decryption Process:** 1. **Nonce Calculation**: To decrypt this packet, the client must use the same `nonce` the server used. The server calculates it with the formula: `blake2b(RNonce + client_public_key + server_public_key)`. The client already has all three components: it generated `RNonce` itself, and it knows both public keys. 2. **Decryption Process**: Decryption is performed using the previously computed shared secret `s`. Formula: `Box.open_afternm(payload, nonce, shared_secret)`. #### **Contents of the Decrypted Packet:** Inside are two key elements for all future communication: 1. **Final Session Key (`session_key`)** (32 bytes): This is the symmetric key that will be used to encrypt all subsequent messages. 2. **Server Nonce (`SNonce`)** (24 bytes): This nonce will be the base for encrypting messages flowing **from the server to the client**. --- ### **Step 4: Transition to Symmetric Encryption & `LoginOk` (ID: 20104)** - **Direction**: Server -> Client - **Encryption**: Symmetric (`SecretBox`) After receiving `ServerHello`, the cryptographic session is fully established. All subsequent packets are encrypted symmetrically using `SecretBox` and the `session_key`. #### **Nonce Logic (`NextNonce`)** A key feature of the protocol is that the nonce is incremented **by 2** before every encryption or decryption operation. The `next_nonce` function in the code precisely replicates this server-side logic. #### **`LoginOk`** This is the first packet the client receives that is symmetrically encrypted. 1. **Get Nonce**: The client takes the `SNonce` it received in the previous step. 2. **Increment Nonce**: It applies the `next_nonce` logic to it (increasing it by 2). 3. **Decrypt**: It decrypts the packet using `SecretBox(session_key).decrypt(payload, nonce)`. Successfully decrypting `LoginOk` confirms that the entire process has worked correctly, and the client is now in a fully encrypted session with the server. This packet contains the details of the newly created account (ID, token, etc.).