Documentation

KSMP (Kemet Secure Messaging Protocol)

Transparency-first protocol spec in a developer template format. This document is concrete about cryptographic/session/message behavior and explicit about what is intentionally withheld for adversarial safety.

0. Scope & Claims

Guarantees claimed

  • End-to-end confidentiality for message and attachment plaintext.
  • Cryptographic sender authentication at identity/device level.
  • Forward secrecy for previously delivered messages.
  • Post-compromise recovery after new clean ratchet traffic.
  • Replay resistance via dedupe + ratchet state checks.
  • Idempotent convergence for delivery/read transitions.

Explicitly not guaranteed

  • Perfect metadata privacy (timing/routing metadata still exists).
  • Protection against compromised endpoints with active malware.
  • Undetectable communication patterns under global traffic analysis.

Assumptions

  • Client honesty: compliant clients follow session persistence and no-downgrade rules.
  • Server behavior: server may be curious or malicious but cannot forge valid ciphertext auth tags.
  • Network: packets may be delayed, dropped, replayed, and reordered.

1. System Model

1.1 Entities

type IdentityId = string;           // stable account id
type DeviceId = string;             // per install (UUIDv4)
type ConversationId = string;       // deterministic from participant set + scope

Identity:
  - Long-lived identity keypair + account binding.
  - Lifecycle: created at enrollment, revoked/rotated by policy event.

Device:
  - One installation + one device key domain.
  - Unique by DeviceId and device public key fingerprint.

Conversation:
  - Logical thread binding participants and message sequence namespace.
  - conversationId = H(canonicalParticipantSet || domain || version).

Server role: stateful message store + relay. It is not trusted for plaintext integrity or confidentiality, but is authoritative for queue persistence and fan-out scheduling.

1.2 Trust boundaries

  • Server can see: envelope routing IDs, timestamps, message type markers, encrypted object refs, size classes.
  • Server can modify: delivery timing/order/drop/replay behavior, but not valid ciphertext content.
  • If server is malicious: availability and ordering degrade; confidentiality/integrity still hold if clients enforce protocol checks.

2. Key & Identity Model

2.1 Identity keys

  • Identity signing keypair: Ed25519 (long-lived).
  • Identity agreement keypair: X25519 (long-lived).
  • Stored in OS secure keystore (Secure Enclave / Android Keystore).
  • Rotation allowed only via explicit rebind flow; old fingerprints remain auditable.

2.2 Device keys

  • Per-device signing keypair and per-device agreement keypair.
  • Generated locally from CSPRNG at device enrollment.
  • Linked to identity via identity-signed device attestation record.

2.3 Prekeys

  • Generated in batches of 100 signed one-time prekeys.
  • Replenish when inventory < 25.
  • Hard failure on depletion (no insecure fallback); sender retries after replenish.

2.4 Recovery / restore

  • Restore on new device creates new DeviceId + new device key domain.
  • Old sessions do not transfer unless encrypted session backup is explicitly restored.
  • Peers observe a new device event and must establish fresh sessions.

3. Session Lifecycle

3.1 Session state object

type SessionState = {
  sessionId: string;
  conversationId: string;
  localDeviceId: string;
  remoteDeviceId: string;
  rootKey: string;                 // persisted
  sendChainKey: string;            // persisted
  recvChainKey: string;            // persisted
  sendIndex: number;               // persisted
  recvIndex: number;               // persisted
  previousChainLength: number;     // persisted
  skippedKeys: Record<string,string>; // persisted bounded map
  remoteIdentityFingerprint: string;  // persisted
  status: "NEW"|"ACTIVE"|"DESYNCED"|"EXPIRED"|"REKEY_REQUIRED";
  updatedAtMs: number;
};

3.2 Session creation

Inputs:
  - remote identity bundle
  - remote device bundle
  - one-time prekey + signed prekey
  - local identity/device keys

API:
  GET /ksmp/prekeys/:identityId/:deviceId
  POST /ksmp/envelopes

Failure behavior:
  - missing prekeys -> queue retryable error PREKEY_UNAVAILABLE
  - identity mismatch -> hard fail IDENTITY_VERIFICATION_FAILED
  - network failure mid-init -> keep local draft, retry init idempotently

3.3 Session states + transitions

NEW -> ACTIVE (first successful decrypt/ack)
ACTIVE -> DESYNCED (ratchet/header mismatch threshold exceeded)
DESYNCED -> ACTIVE (successful rekey and decrypt)
ACTIVE -> EXPIRED (ttl or explicit peer rekey event)
EXPIRED -> REKEY_REQUIRED (send attempt or receive re-init trigger)
REKEY_REQUIRED -> ACTIVE (new bootstrap success)

3.4 Session breakage handling

  • Repeated decrypt failure (>= 5 consecutive): move to `DESYNCED`, request rekey.
  • Invalid header schema/signature: reject envelope, security-log event, no state advance.
  • Ratchet mismatch beyond skipped-key window: hold message pending re-establishment.

4. Message Model

4.1 Message object (wire shape)

type KsmpMessage = {
  version: "2.x";
  messageId: string;               // ULID
  dedupeId: string;                // BLAKE3(conversationId|senderDeviceId|sendIndex|ciphertextHash)
  conversationId: string;
  senderIdentityId: string;
  senderDeviceId: string;
  recipientIdentityId: string;
  recipientDeviceId?: string;
  type: "text"|"media"|"system"|"receipt";
  ratchetHeader: {
    dhPub: string;
    pn: number;
    n: number;
  };
  ciphertext: string;              // base64url
  attachments?: AttachmentRef[];
  sentAtMs: number;
};

Limits:
  text plaintext <= 16 KiB
  total encrypted envelope <= 64 KiB

4.2 Encryption flow

  • Encrypted: message body, attachment metadata, app-level semantic fields.
  • Plaintext: routing identifiers, protocol version, ratchet header, dedupe/materialized IDs.
  • Authenticated (AEAD AD): immutable envelope header + version + conversationId.

4.3 Dedupe / replay

  • `dedupeId` is deterministic from ratchet position and ciphertext digest context.
  • Stored in local replay cache and durable message index.
  • Retention: 30 days active cache + persisted historical index keyed by messageId.

5. Send Pipeline

onSend(userInput):
  1) create local draft message object
  2) assign messageId (ULID)
  3) resolve session (or bootstrap)
  4) encrypt payload + build envelope + dedupeId
  5) persist encrypted outbound record (PENDING_SEND)
  6) enqueue transport job
  7) POST envelope
  8) on 2xx mark SENT and emit delivery wait state

Crash behavior by stage

  • Crash before persist: message is lost unless UI draft persisted separately.
  • Crash after persist before send: job resumes from outbound queue on restart.
  • Crash after send before ack apply: idempotent resend using same `messageId` + `dedupeId`.

6. Receive Pipeline

onEnvelope(env):
  1) schema validate envelope
  2) dedupe check (fast cache then durable index)
  3) resolve session by (conversationId, senderDeviceId)
  4) derive receive key from ratchetHeader
  5) decrypt + authenticate
  6) begin transaction
  7) apply message + advance ratchet + store dedupe marker
  8) commit
  9) emit receipt if policy allows

Failure behavior

  • Cannot decrypt: quarantine envelope + trigger rekey path.
  • Session missing: attempt bootstrap-from-inbound, else hold pending.
  • Duplicate message: no-op, may re-emit ack idempotently.
  • Corrupted payload: drop, log tamper event, never render.

7. Ordering & Consistency

Ordering guarantee: no global strict order guarantee. KSMP guarantees causal-safe processing with out-of-order tolerance.

For arrival `5 -> 2 -> 4 -> 3 -> 1`: receiver applies decryptable messages, buffers missing ratchet positions within skipped-key bound, and converges once missing links arrive or rekey path completes.

8. Multi-Device Model

8.1 Fan-out

Encryption is per recipient device, not once per user.

8.2 Sync

  • Messages sync by envelope fan-out queue and per-device acks.
  • Read/delivery state sync by monotonic receipt events keyed by messageId.
  • Receipts are idempotent and causally bounded.

8.3 Conflicts

  • Concurrent read markers: highest monotonic `readAtMs` wins.
  • Simultaneous sends: both accepted; display order uses server receive timestamp + tiebreak messageId.

9. Receipts

Delivered:
  emitter: recipient device
  trigger: message decrypted + committed locally
  reference: messageId + senderDeviceId

Read:
  emitter: recipient device
  trigger: user-visible read transition
  reference: messageId (or up-to watermark by conversation)

Idempotency:
  receiptKey = H(type|messageId|deviceId)
  duplicate receiptKey => no-op

10. Attachments

Upload

  • File encrypted client-side before upload.
  • Attachment content key encrypted inside message plaintext metadata.
  • Envelope references objectRef + digest + byteLength + mime.

Download

  • Client fetches encrypted object, decrypts locally, verifies digest/size.
  • Digest mismatch => reject render, mark attachment integrity failure.

Limits

  • Max attachment size: 25 MiB per item.
  • Max attachments per message: 8.
  • Default media URL expiry: 15 minutes per signed access token.

11. Storage Model

Client must store

  • Identity keys, device keys, and trust/fingerprint records.
  • Session states and skipped-key cache.
  • Outbound pending queue and dedupe cache.
  • Message index + receipt state + attachment integrity metadata.

If lost

  • Without keys/session state: historical undecryptable messages remain opaque.
  • Recovery path is new-device enrollment + new session establishment.

12. Retries & Delivery

  • Retry on network/5xx/timeout with exponential backoff + jitter.
  • Schedule: 1s, 2s, 4s, 8s, 16s ... capped at 15m between attempts.
  • Max retry attempts per message: 50 before terminal `DELIVERY_EXPIRED`.
  • Undelivered TTL: 7 days default for pending outbound records.

13. Versioning

  • Version stored in every envelope (`version` field).
  • Newer unsupported major: reject + emit `UNSUPPORTED_PROTOCOL_VERSION`.
  • Older but allowed minor/patch: accept in compatibility mode.

14. Protocol Limits

maxMessagePlaintextBytes = 16384
maxEnvelopeBytes = 65536
maxAttachmentsPerMessage = 8
maxAttachmentBytes = 25 * 1024 * 1024
maxDevicesPerIdentity = 10
maxSkippedKeys = 2000
maxRetryAttempts = 50

15. Security Edge Cases

  • Device compromised: mark device untrusted, revoke device keys, force re-establish with new device material.
  • Keys leaked: rotate affected key domain, invalidate sessions, require peer trust revalidation.
  • Server replay: dedupe + ratchet window prevents state rollback or duplicate render.
  • Flooding: envelope queue guards and bounded processing; anti-abuse internals intentionally not disclosed here.

16. Real Flows

Case 1: First message ever

A gets B prekeys -> A bootstraps session -> A sends encrypted envelope
B decrypts, initializes session, commits message, sends delivered receipt

Case 2: Receiver offline 3 days

Server queues envelopes -> B reconnects -> pulls backlog -> dedupe/decrypt/apply in order-safe loop
receipts emitted idempotently for committed messages

Case 3: Out-of-order arrival

Receive n+4 first -> skipped-key handling attempts bounded derivation
buffer until missing links arrive or rekey path resolves

Case 4: Device restored

New device enrolled -> new DeviceId + keys
peers fan-out to new device after trust update; old non-backed-up sessions do not transfer

Case 5: Session broken mid-conversation

Consecutive decrypt failures -> DESYNCED
trigger rekey bootstrap -> mark failed envelopes pending -> resume ACTIVE after successful decrypt

17. Implementation Checklist (Strict)

  • If client does not persist ratchet state atomically, it is broken.
  • If client allows insecure fallback when prekeys are absent, it is broken.
  • If client does not dedupe before apply, it is broken.
  • If client accepts protocol downgrade weakening guarantees, it is broken.
  • If client cannot recover from crash without duplicate sends/applies, it is broken.
  • If client renders attachments without digest verification, it is broken.

Disclosure Line (Deliberate)

This spec publishes the cryptographic and state-machine contract. It does not publish anti-abuse scoring internals, exploit-sensitive thresholds, or operational topology details that directly improve attacker optimization.

Status: KSMP transparency spec draft v2. Built for technical humans and implementers-in-waiting, without publishing attacker-optimization internals.

← Back to docs home