How RitChat works

RitChat is a minimal, file-based messenger with end-to-end encryption (E2EE). Encryption and decryption happen in your browser using WebCrypto. The server stores only encrypted payloads and a few unencrypted service events.

Chat identity (chat_id)

A deterministic id derived from the shared passphrase:

  • normalized = trim(passphrase).normalize('NFC')
  • chat_id = hex(SHA-256(\"ritchat:chat-id:\" + normalized)).slice(0, 32)

Key derivation (PBKDF2)

  • PBKDF2-HMAC-SHA-256
  • Salt: SHA-256(\"ritchat:kdf-salt:\" + normalized)
  • Iterations: 310000
  • Key: AES-GCM 256-bit

Message encryption (AES-GCM)

  • Random 12-byte IV per message
  • AAD: UTF-8 bytes of chat_id
  • Payload: base64(iv) + \".\" + base64(ciphertext)

Transport and polling

  • POST-only endpoints with CSRF protection
  • Polling every 3 seconds
  • Poll returns up to 200 events

Server storage

One file per chat under @runtime/ritchat:

  • {chat_id}.txt: JSON lines
  • Kinds: msg, join, cleared
  • msg includes encrypted payload p
  • t is a Unix timestamp in UTC (Greenwich)

Limitations

  • Passphrase strength matters.

Retention

If a chat is inactive for more than 7 days, the server cleanup task removes its file.