Reaktor DocsSecurity and authClaude

Security and auth · Claude

Security Implementation Plan

Threat model and security hardening plan for Reaktor services and workbench operations.

Use whenUse before enabling mutating commands, deploy actions, or remote agent workflows.
SourceClaude
Route/docs/security-plan

Direction

Use Cisco MLS++ (mlspp) as the only end-to-end encryption protocol engine. Every secure conversation is an MLS group: direct chats, group chats, member changes, new devices, and key rotation all map to MLS group operations.

Expose

  • createDirectConversation(peerUserId)
  • createGroupConversation(memberUserIds)
  • encryptMessage(conversationId, plaintext)
  • processIncoming(envelope)
  • addMembers(conversationId, users)
  • removeMembers(conversationId, users)

Do Not Expose

  • Raw MLS state or private tree material
  • Raw private keys, group secrets, or nonces
  • Low-level crypto toolkit APIs
  • Server-side decryption paths
  • Signal provider abstractions

Current Repository Shape

Keep the module aligned with the rest of Reaktor: Gradle/KMP lives in the normal src/*Main layout, native code lives under cpp/, TypeScript lives under ts/, and generated Kotlin externals are produced through Karakum into ts/import.

reaktor-security/
  cpp/
    external/mlspp/
    external/json/
    external/googletest/
    rsec-mls-core/
    rsec-mls-capi/
    tests/native/
  src/
    commonMain/
    androidMain/
    iosMain/
    jsMain/
    jvmMain/
  ts/
    export/
    import/
    package.json
    karakum.config.json
  README.md
  THIRD_PARTY_LOCK.md
Documentation and schema policy: the module-level docs/ and schemas/ folders are intentionally removed. Keep this implementation plan in repository-root plan.html. Move durable wire contracts into typed Kotlin/TypeScript/C++ sources and generated artifacts rather than parallel markdown schema files.

Hard Blocker

Durable MLS state snapshots are the first serious implementation blocker. The engine must prove that a process can create a group, persist encrypted state, restart, reload state, process the next message, and send the next message deterministically.

RsecMlsStateSnapshotV1 must cover:
  cipher suite
  group id and epoch
  public and private tree state
  transcript hash
  extensions
  epoch secrets and message ratchet state
  own leaf index
  identity private key references
  external and resumption PSKs
  pending proposals and cached update

Preferred path: keep a small audited patch against vendored MLS++ that adds State::export_snapshot() and State::import_snapshot(). That is easier to review than reconstructing state through derived-class access to protected internals.

Execution Phases

P0 - Native Core and Build Hygiene

Pin MLS++, keep CMake deterministic, keep tests under cpp/tests, maintain the stable C ABI, and keep Gradle sync green across Reaktor, BestBuds, and Manna.

P1 - Durable State and Credentials

Implement encrypted MLS state snapshots, canonical device credentials, signature verification, and key-package private-material storage.

P2 - Conversation Operations

Ship direct conversations, group conversations, incoming queue processing, member add/remove, device add/remove, and epoch conflict recovery.

P3 - Platform Secret Boxes

Implement Android Keystore, Darwin Keychain, Windows DPAPI, Linux Secret Service, and WebCrypto/IndexedDB sealing paths behind one PlatformSecretBox contract.

P4 - Server Backends

Implement identical protocol behavior for Spring Boot/Postgres and Cloudflare Worker/D1/Durable Objects. Servers store and order ciphertext, credentials, key packages, welcomes, and commit metadata only.

P5 - Web, WASM, and React Native

Compile the C++ core to WASM for web, expose a TypeScript wrapper, and add a React Native JSI adapter that avoids passing long-term secrets through JavaScript.

P6 - Hardening and Release

Complete fuzzing, malformed envelope tests, replay tests, credential expiry tests, license allowlist checks, SBOM generation, and state migration tests.

Task Backlog

Task Status Scope Acceptance Signal
RSEC-001
Repository skeleton
Done Use Reaktor KMP layout, cpp/, and ts/. Consolidate planning in root plan.html. Build graph is obvious, public APIs are MLS-only, no module-local docs/schema drift.
RSEC-002
Vendor and build MLS++
Active Pin Cisco MLS++, nlohmann/json, and GoogleTest. Keep lock and license notes in THIRD_PARTY_LOCK.md. Host native tests and Gradle native def generation pass from a clean checkout.
RSEC-003
Native C ABI
Active Expose engine lifecycle, key packages, group creation, join, encrypt, decrypt, and buffer ownership through rsec.h. C tests cover create/destroy, invalid input, buffer free, and direct conversation round trip.
RSEC-004
MLS state snapshot
Next Add versioned encrypted snapshot export/import around MLS++ state. Create, persist, restart, reload, decrypt, send, add/remove all pass deterministically.
RSEC-005
Device credential encoding
Planned Canonical binary DeviceCredentialV1, auth signature verification, expiry, tenant/app scoping. Identical credentials produce identical bytes; tampering and wrong tenant/app fail.
RSEC-006
Key package generation
Planned Generate, seal private material, upload public bytes, track local claimed packages. MLS++ parses packages; reused local package is rejected; low inventory is visible.
RSEC-007
Direct conversation
Active Fetch peer devices/packages, create MLS group, emit welcomes, persist state, exchange messages. Alice and Bob both decrypt after restart; server never sees plaintext.
RSEC-008
Group conversation
Planned Claim packages for all active devices and create initial group state/welcomes. Three users with multiple devices can all join and decrypt.
RSEC-009
Incoming queue
Planned Process handshakes before application messages, queue missing epochs, dedupe replay. Out-of-order messages decrypt after missing commits arrive; replay does not advance state twice.
RSEC-010
Members and devices
Planned Add/remove members, add/remove own device, and verify membership policy proofs. Removed devices cannot decrypt future messages; stale or wrong-conversation proofs fail.
RSEC-011
Android package
Planned Kotlin facade, JNI binding, Android Keystore secret box, native library packaging. Instrumented tests cover register, key packages, create, persist/reload, encrypt/decrypt.
RSEC-012
iOS/macOS package
Active Kotlin/Native cinterop, Darwin Keychain secret box, KMP framework output. Simulator/device/macOS paths pass and default to this-device-only secret records.
RSEC-013
Desktop package
Planned JVM facade, native loader, DPAPI, Keychain, Secret Service, explicit Linux passphrase fallback. Local state survives restart and fails under wrong user or missing secret store.
RSEC-014
Web/WASM package
Planned WASM build, TypeScript wrapper, WebCrypto plus IndexedDB secret storage. Browser creates device, joins group, encrypts/decrypts, reloads state, rejects insecure context.
RSEC-015
React Native JSI
Planned C++ JSI adapter and high-level TypeScript facade. React Native app can encrypt/decrypt without JS receiving group state or private key material.
RSEC-016
Spring server
Planned Spring Boot, Postgres, migrations, OpenAPI, transactional key-package claims and commit appends. Commit conflicts are handled; all server writes are transactional; no plaintext path exists.
RSEC-017
Cloudflare server
Planned Worker service, D1 registry/key packages/welcomes, Durable Object per conversation for ordering. Conflicting commits return a typed conflict; Durable Object serializes appends.
RSEC-018
Attachments
Planned Chunked local encryption and MLS-protected content-key delivery. Object stores see ciphertext only; wrong conversation cannot decrypt attachment metadata.
RSEC-019
Verification primitives
Planned Device fingerprint, safety number/QR payload, verification state store. Changed device key warns; verification state is tenant/app/user/device scoped.
RSEC-020
Hardening
Planned Native, KMP, Android, iOS, desktop, WASM, server, fuzz, replay, migration, license, and SBOM tests. Malformed envelopes, stale proofs, expired credentials, reused packages, crashes, and conflicts are covered.

Server Protocol Surface

Spring Boot/Postgres and Cloudflare Worker/D1/Durable Objects should implement the same client-visible protocol. The client SDK should not care which backend is deployed.

POST /security/devices/register
POST /security/key-packages
POST /security/key-packages/claim
POST /security/conversations
POST /security/conversations/{id}/messages
GET  /security/conversations/{id}/messages
GET  /security/welcomes
POST /security/welcomes/{id}/consume

All server-side authorization decisions that affect membership must produce client-verifiable policy proofs. Clients must reject server-added devices or members without valid Reaktor-auth-signed credentials and membership proofs.

P0 Completion Bar

  • MLS++ native core is pinned and documented in THIRD_PARTY_LOCK.md.
  • C ABI owns stable buffer/result/error behavior and does not leak C++ exceptions.
  • Kotlin common and TypeScript APIs expose conversation operations only.
  • Karakum generates Kotlin externals from reaktor-security/ts.
  • Host C++ tests live under cpp/tests/native and pass through CTest.
  • Gradle sync succeeds when reaktor is consumed from BestBuds and Manna composite builds.

Do Not Implement

  • No Signal provider.
  • No low-level crypto API for app developers.
  • No raw key export API.
  • No server-side decrypt API.
  • No plaintext search.
  • No metadata privacy claims beyond what the implementation actually provides.
  • No silent plaintext fallback on Linux or Web.
  • No unpinned MLS++ dependency.
  • No JSON signatures for security-critical credentials or policy proofs.

References

  1. Cisco MLS++
  2. RFC 9420 - Messaging Layer Security
  3. Emscripten
  4. Android Keystore
  5. Apple Keychain Services
  6. Windows DPAPI CryptProtectData
  7. Freedesktop Secret Service API
  8. Web Crypto API
  9. Cloudflare D1
  10. Cloudflare Durable Objects