BSDecrypter-Colette/README-en.md
2025-06-20 23:19:45 +03:00

92 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 DiffieHellman (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.).