Skip to content

Security Model


Encryption Scheme

Layered Encryption

LayerSchemePurpose
TransportWSS (TLS 1.3)Prevent eavesdropping, protect metadata
ApplicationAES-256-GCMEnd-to-end message content encryption

Encryption Parameters

ParameterValueDescription
AlgorithmAES-256-GCMAEAD authenticated encryption
Key length256 bits (32 bytes)2^256 key space
IV length96 bits (12 bytes)GCM recommended length
Auth tag128 bitsGCM default
Key generationcrypto.subtle.generateKey()Browser CSPRNG
IV generationcrypto.getRandomValues()Random per message

Trust Model

┌─────────────────────────────────────────────┐
│ Trust Boundary │
├─────────────────────────────────────────────┤
│ │
│ Trusted: │
│ ✅ Browser environment (Web Crypto API) │
│ ✅ User shares key via secure channel │
│ ✅ User device is not compromised │
│ │
│ Not Trusted: │
│ ❌ Server (zero-knowledge design) │
│ ❌ Network transport (TLS protected) │
│ ❌ Third-party observers │
│ │
└─────────────────────────────────────────────┘

Encryption Flow

Key Generation and Distribution

Creator:
1. crypto.subtle.generateKey(AES-256-GCM) → roomKey
2. crypto.subtle.exportKey('raw', roomKey) → 32 bytes
3. base64url(rawKey) → 43 character encoding
4. Construct share code: {roomId}:{base64url(roomKey)}
5. Share with peers via secure channel
Joiner:
1. Parse share code → extract roomId and keyEncoded
2. base64url.decode(keyEncoded) → 32 bytes
3. crypto.subtle.importKey('raw', ...) → roomKey
4. Send JoinRoom{roomId} to server (roomKey NOT included)

Message Encryption

Sending:
1. plaintext → TextEncoder.encode() → UTF-8 bytes
2. iv = crypto.getRandomValues(12 bytes)
3. crypto.subtle.encrypt({AES-GCM, iv}, roomKey, bytes) → ciphertext
4. Send {iv: base64url(iv), ciphertext: base64url(ciphertext)}
Receiving:
1. base64url.decode(iv) → iv bytes
2. base64url.decode(ciphertext) → ciphertext bytes
3. crypto.subtle.decrypt({AES-GCM, iv}, roomKey, ciphertext) → plaintext bytes
4. TextDecoder.decode(plaintext) → plaintext string

Threat Analysis

ThreatRiskMitigation
Network eavesdroppingLowWSS (TLS 1.3) transport encryption
Server reading messagesNoneE2EE, server only sees ciphertext
Key leak (in transit)NoneKey never passes through server
Replay attackLowRandom 96-bit IV per message
Message tamperingNoneAES-GCM authentication tag (AEAD)
Brute force keyExtremely lowAES-256, 2^256 key space
Share code leakMediumDepends on user sharing securely
Server impersonating membersLowCannot decrypt messages, but can inject
Metadata analysisMediumServer can see who/when/typing

Known Security Limitations

LimitationDescriptionRisk LevelMitigation
Share code non-revocableAnyone with the code can joinMediumAll members leaving destroys room
No Perfect Forward SecrecyroomKey leak decrypts all messagesLowMessages are not persisted
Typing status unencryptedServer can see who is typingLowDoes not contain message content
No message persistenceMessages lost during disconnectionMediumUsers are clearly informed
No identity verificationAnyone can use any nicknameLowAcceptable for ephemeral chat
NanoID collision21-char collision probability ~10^-36Extremely lowNegligible

Server-Visible Metadata

Even with encrypted message content, the server can observe:

MetadataVisibleNotes
Room IDRequired for routing
Member IDConnection identifier
Member nicknameProvided at join time
Message timestampAppended by server
Message sizeCiphertext length visible
Typing statusUnencrypted
Online statusConnection state
Message plaintextEnd-to-end encrypted
Room keyOnly held by clients

Comparison with Other Solutions

FeatureArthasSignalTelegram (Secret)
E2EE✅ AES-256-GCM✅ Double Ratchet✅ MTProto
Forward Secrecy
Server Zero-KnowledgePartial
Message Persistence✅ (local)
Identity Verification✅ (phone number)✅ (phone number)
Open SourcePartial
No Signup Required

Security Best Practices

For Users

  1. Share keys via secure channels — In person, encrypted IM (e.g., Signal)
  2. Do not post share codes publicly — Anyone can join
  3. Leave the room after sensitive conversations — Room destruction removes ciphertext
  4. Use a modern browser — Ensures correct Web Crypto API implementation

For Deployers

  1. Enable WSS (TLS) — Protect the transport layer
  2. Do not log message content — Code ensures this, but verify log configuration
  3. Restrict CORS — Only allow your frontend domain
  4. Update dependencies regularly — Fix known vulnerabilities

Implemented Security Enhancements

  • Ed25519 message signatures (implemented in v1.1.0)
  • Member authentication (password-protected rooms, implemented in v1.0.0)

Future Security Enhancements (Roadmap)

  • Double Ratchet protocol (forward secrecy)
  • Encrypted typing status
  • Kick member functionality (key rotation)

Next Steps