VMP Chat Protocol

Please feel free to check out our FAQ for the Technically Inclined.
Client developers are required to comply with the Security Guidelines.

This page describes the security and transport architecture of VMP Chat — the standards-based cryptographic stack that protects messages, calls, and media end-to-end. See also:

General Description

The VMP Chat protocol is built on industry-standard cryptography and transport primitives — the same building blocks used by every modern secure messenger. There are no custom cipher constructions and no proprietary wire formats; every layer is something a security auditor can recognize and verify against published specifications.

The architecture is subdivided into three virtually independent components:

  • Authentication layer: OAuth 2.0 with PKCE issues short-lived JWT access tokens stored in the hardware-backed iOS Keychain or Android Keystore. The OS exposes these secrets only after device unlock.
  • Real-time messaging layer: Socket.IO over TLS carries chat events, presence, typing, reactions, and read receipts in JSON. Message bodies are encrypted end-to-end with AES-256-GCM before they leave the device — the server stores ciphertext and key envelopes it cannot decrypt.
  • Media & call layer: Voice and video calls run on LiveKit (a WebRTC SFU) with DTLS-SRTP encryption end-to-end on every media stream. Image, video, voice, and document uploads are encrypted at rest server-side with AES-256-GCM.

The iOS Swift Package and Android Kotlin app share the same domain model, the same Socket.IO event contract, and the same encryption wire format. A message encrypted on iOS decrypts byte-for-byte on Android with the same room key — and vice versa. The two clients are functional 1:1 mirrors of each other.

Brief Component Summary

Authentication & Token Management

Sign-in uses OAuth 2.0 with PKCE — the modern standard for native-app authentication. The flow eliminates the entire authorization-code interception attack class that historically affected public OAuth clients.

The server issues a pair of JWTs: a short-lived access token and a longer-lived refresh token. Both are persisted in hardware-rooted secure storage on your device:

  • iOS: the native Keychain — secrets are unavailable until the device has been unlocked at least once after boot.
  • Android: hardware-backed encrypted preferences. On devices with a secure element, the master key never leaves it.

The client maintains two independent token contexts (one for chat, one for the community surface), so a token issued for one cannot accidentally authorize a request to the other.

Access tokens are refreshed proactively — the network layer refreshes them before they expire, avoiding the round-trip cost of a failed request followed by a re-attempt. Refreshes are serialized so simultaneous expired requests trigger exactly one refresh, not many.

Sign-out revokes the refresh token server-side, so a stolen device with cached tokens cannot continue to access the account once the user has signed out from anywhere else.

Real-time Messaging

Real-time delivery runs on Socket.IO with horizontally-scaled servers behind a load balancer, so a message published on one instance reaches a client connected to any other instance transparently.

The clients implement a custom reconnect handler: on disconnect, the client refreshes the auth token first, then reconnects with the fresh token. Backoff is exponential, capped at 30 seconds per attempt for up to 10 attempts.

Messages are de-duplicated client-side with a small in-memory cache of recent message IDs, so even when the server fans out for delivery guarantees, you never see duplicate bubbles in a busy group chat.

The clients share the same set of real-time events: new and updated messages, message status, typing indicators, presence, reactions, block changes, room and member updates. Both platforms observe the same vocabulary, so a feature shipped on one client behaves identically on the other.

If a corporate firewall blocks WebSockets, Socket.IO transparently degrades to long-polling — most “this app does not work on my office Wi-Fi” complaints disappear as a result.

End-to-End Encryption

Message contents are encrypted on your device before they reach the server. The cipher is AES-256-GCM — the authenticated-encryption construction defined in NIST SP 800-38D and standardized as a default cipher suite in TLS 1.3.

  • Key: a 256-bit symmetric room key, one per conversation.
  • Nonce: a fresh 96-bit value generated per message — the NIST-recommended size for GCM, with negligible collision probability at any realistic scale.
  • Authentication tag: 128 bits, appended to the ciphertext. Any tampering — by the server, a network attacker, or a forensic disk image — is detected on decrypt; the cipher refuses to return wrong plaintext silently.
  • Cross-platform compatibility: a message encrypted on iOS decrypts on Android (and vice versa) with the same room key. The two clients share the same encryption format.

Room keys are themselves wrapped under a Key Encryption Key (KEK) deterministically derived per-user, and the KEK never leaves your device. The server stores the wrapped key envelopes — so a new device can sync your history after sign-in — but cannot unwrap them. A database leak yields ciphertext only.

The encryption service refuses to encrypt at all when a key is missing — there is no silent fallback to plaintext. The server can never receive a message in the clear because of a client-side error.

Voice & Video Calls

Voice and video calls run on LiveKit, a Selective Forwarding Unit (SFU) built on WebRTC. The SFU architecture means each additional participant adds O(1) cost per client — the same architecture as Google Meet and Zoom, and substantially cheaper than a peer-to-peer mesh past four participants.

Every WebRTC media stream is encrypted end-to-end with DTLS-SRTP, as mandated by the WebRTC specification. Room access tokens are short-lived (15 minutes) and bound to a single room — a token captured in transit expires quickly and cannot be replayed elsewhere.

Each client integrates with the platform’s native call surface:

  • iOS — CallKit + PushKit: incoming calls show the system lock-screen accept/decline UI with the contact photo, integrate with the iPhone Recents app, and support the Bluetooth headset accept button. VoIP pushes wake the app before you notice a notification, so calls ring even when the app has been killed.
  • Android — phone-call foreground service: the call service survives Doze mode and aggressive OEM task-killers (Vivo, Xiaomi, Samsung all whitelist this service type). Call payloads arrive via push notification, ring through the system ringtone, and present a full-screen notification.

Audio routing detects Bluetooth and wired headsets automatically, uses the earpiece for voice calls and the speakerphone for video, and applies echo cancellation and microphone gating during the call.

Transport & TLS

Every byte that leaves the device — API call, real-time frame, or media upload — travels over TLS 1.2 or higher. The transport layer provides the standard guarantees: confidentiality, integrity, and forward secrecy of the channel itself. The application layer adds end-to-end encryption on top.

Both clients add a defense-in-depth layer above TLS:

  • Android — certificate pinning: the production certificate is pinned at the network layer, applied uniformly to every HTTP client and image loader in the app. A rogue corporate proxy or nation-state CA cannot silently intercept the connection.
  • iOS — App Transport Security: ATS enforces TLS 1.2+ with forward-secrecy cipher suites and certificate validity at the OS level for every network request.

The HTTP client distinguishes mutable from immutable resources via cache-control headers: media URLs are cached for 24 hours (they are content-addressed and immutable), user profiles for 10 minutes, and sensitive mutable state is never HTTP-cached. Room and message data is never HTTP-cached either — the local on-device store is the source of truth for those.

The real-time layer negotiates the best available transport: WebSocket where possible, HTTP long-polling as fallback. On Android, the client waits for the OS to confirm real internet reach before reconnecting, so reconnect attempts do not fire on a captive-portal Wi-Fi where the OS has not yet confirmed real internet access.

Local Storage & Offline

The app is offline-first. The chat list, message history, contacts, drafts, and unread counts open instantly on cold start — even on a plane.

  • Android: four separate on-device databases — chat, community, auth, and block-state — each with its own schema and crash domain, so corruption in one cannot take out the others. Indexed message lookups keep scrolling smooth even in rooms with tens of thousands of messages. Per-message AES-256-GCM is applied before persistence — what lives on disk is ciphertext.
  • iOS: a protocol-based storage layer designed so the host application can swap in any database engine without touching the repository protocols above it.

On the server side, state is split across the database that best fits each access pattern: a relational store for accounts, contacts, devices, and room metadata; a wide-column store for message bodies, sharded per room and ordered by recency — the same workload pattern WhatsApp and Discord use; and an in-memory cache for presence, typing, and short-lived hot data.

Uploaded media is encrypted at rest on the server with AES-256-GCM and expires after 30 days. Users may opt into Google Drive backup, in which case the encrypted file lives in the user’s own Drive — not the platform’s storage.

Summary

VMP Messenger is built on industry-standard cryptography and transport — the same building blocks used by every modern secure messenger:

  • AES-256-GCM for message encryption.
  • OAuth 2.0 with PKCE and JWT for authentication.
  • TLS 1.2+ for transport, with certificate pinning on the Android client.
  • DTLS-SRTP for voice and video media, enforced by the WebRTC layer.
  • Hardware-rooted secure storage on the device for tokens and per-room encryption keys.

Every layer maps to a published specification — there are no proprietary cipher constructions and no closed wire formats.