-
Notifications
You must be signed in to change notification settings - Fork 14
Encrypted P2P Chat
Carter Perez edited this page Dec 9, 2025
·
1 revision
Real-time encrypted messaging application using Signal Protocol encryption with passwordless WebAuthn authentication.
A secure chat application implementing end-to-end encryption with forward secrecy and break-in recovery. Features passwordless authentication via WebAuthn/Passkeys and real-time messaging through WebSockets and SurrealDB live queries.
Status: Complete | Difficulty: Advanced
| Technology | Version | Purpose |
|---|---|---|
| FastAPI | 0.121+ | Async Python web framework |
| PostgreSQL | 16 | User auth & credentials |
| SurrealDB | 1.0 | Real-time messaging (live queries) |
| Redis | 7.1 | Challenge/session storage |
| SQLModel | 0.0.27 | SQLAlchemy + Pydantic hybrid |
| Alembic | 1.17+ | Async migrations |
| PyNaCl | 1.6 | Encryption primitives |
| liboqs-python | 0.14 | Post-quantum cryptography |
| Technology | Version | Purpose |
|---|---|---|
| SolidJS | 1.9 | Fine-grained reactivity |
| TypeScript | 5.9 | Type safety |
| Vite | 7.2 | Build tool (Node 20.19+) |
| Tailwind CSS | v4 | Styling |
| @tanstack/solid-query | 5.90 | Server state |
| nanostores | 1.1 | Lightweight state |
- Docker + Docker Compose
- Nginx reverse proxy
- Makefile automation
- Passwordless login with WebAuthn/Passkeys (FIDO2)
- Discoverable credentials (device-based)
- Multi-device support
- Signature counter verification
- Double Ratchet for message encryption
- X3DH key exchange for async messaging
- Forward secrecy
- Break-in recovery
- Out-of-order message handling
- Per-message AES-256-GCM
- WebSocket connections with management
- SurrealDB live queries
- Online/offline presence
- Typing indicators
- Read receipts
- Heartbeat keep-alive
┌─────────────────────────────────────────────────────────┐
│ Frontend (SolidJS) │
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌───────────┐ │
│ │ Auth │ │ Chat │ │ Rooms │ │ Crypto │ │
│ │ WebAuthn│ │ Messages │ │ List │ │ Service │ │
│ └────┬────┘ └────┬─────┘ └────┬────┘ └─────┬─────┘ │
└───────┼────────────┼─────────────┼─────────────┼───────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ WebSocket + REST API (Nginx) │
└─────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────┐
│ Backend (FastAPI) │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Services │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ Auth │ │ Message │ │ Presence │ │ │
│ │ │ WebAuthn │ │ Encrypt │ │ Tracking │ │ │
│ │ └──────────┘ └──────────┘ └──────────────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ Prekey │ │WebSocket │ │ Ratchet │ │ │
│ │ │ X3DH │ │ Manager │ │ State │ │ │
│ │ └──────────┘ └──────────┘ └──────────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Encryption Core │ │
│ │ double_ratchet.py | x3dh_manager.py │ │
│ └──────────────────────────────────────────────────┘ │
└────────┬──────────────────┬──────────────────┬──────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ PostgreSQL │ │ SurrealDB │ │ Redis │
│ Users/Creds │ │ Messages │ │ Sessions │
│ Keys/Prekeys│ │ Live Queries│ │ Challenges │
└─────────────┘ └─────────────┘ └─────────────┘
Alice Bob
│ │
│ 1. Fetch Bob's prekey bundle │
│ ──────────────────────────────────────────────>│
│ │
│ 2. Bundle: IdentityKey, SignedPrekey, │
│ OneTimePrekey, Signature │
│ <──────────────────────────────────────────────│
│ │
│ 3. Verify signature │
│ 4. Generate ephemeral keypair │
│ 5. Compute shared secrets (DH): │
│ DH1 = DH(IK_A, SPK_B) │
│ DH2 = DH(EK_A, IK_B) │
│ DH3 = DH(EK_A, SPK_B) │
│ DH4 = DH(EK_A, OPK_B) │
│ 6. Derive root key: HKDF(DH1||DH2||DH3||DH4) │
│ 7. Initialize Double Ratchet │
│ │
│ 8. Send initial message + EK_A public │
│ ──────────────────────────────────────────────>│
│ │
│ 9. Bob computes same secrets │
│ 10. Initializes Double Ratchet│
│ │
Each message uses a unique key derived from the ratchet state:
Root Key ─────┬─────> Chain Key 1 ──> Message Key 1
│ ──> Message Key 2
│
└─────> Chain Key 2 ──> Message Key 3
──> Message Key 4
- Symmetric ratchet: Derives new message keys
- DH ratchet: Updates root key on each reply
- Forward secrecy: Old keys deleted after use
- Break-in recovery: New DH ratchet heals compromise
cd PROJECTS/encrypted-p2p-chat
# Copy environment file
cp .env.example .env
# Start development environment
make dev
# Access at http://localhost:3000Key environment variables:
# PostgreSQL
DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/chat
# SurrealDB
SURREAL_URL=ws://localhost:8000/rpc
SURREAL_NS=chat
SURREAL_DB=messages
# Redis
REDIS_URL=redis://localhost:6379
# WebAuthn
RP_ID=localhost
RP_NAME=Encrypted Chat
RP_ORIGIN=http://localhost:3000| Model | Database | Purpose |
|---|---|---|
| User | PostgreSQL | User accounts |
| Credential | PostgreSQL | WebAuthn credentials |
| IdentityKey | PostgreSQL | Long-term identity keys |
| SignedPrekey | PostgreSQL | Signed prekeys for X3DH |
| OneTimePrekey | PostgreSQL | One-time prekeys |
| RatchetState | PostgreSQL | Double ratchet state |
| SkippedMessageKey | PostgreSQL | Out-of-order handling |
| Messages | SurrealDB | Encrypted message storage |
| Store | Purpose |
|---|---|
| authStore | Authentication state |
| messagesStore | Message state |
| roomsStore | Chat room state |
| presenceStore | Online/offline status |
| typingStore | Typing indicators |
| settingsStore | User preferences |
# Backend
make backend-lint
make backend-test
# Frontend
make frontend-lint
make frontend-build
# Both
make lint
make test- All messages encrypted client-side before transmission
- Server never sees plaintext messages
- Keys stored securely, old keys deleted
- WebAuthn prevents phishing attacks
- No passwords to steal or crack
©AngelaMos | CertGames.com | CarterPerez-dev | 2025
Progress: 3/60