Files
Shade/docs/archive/V3.2.md
Sterister e6fdf31b49
Some checks failed
Test / test (push) Has been cancelled
Cross-platform vectors / TypeScript vectors (bun) (push) Has been cancelled
Cross-platform vectors / Kotlin vectors (gradle) (push) Has been cancelled
Docker build and publish / docker (push) Has been cancelled
Publish / publish (push) Has been cancelled
release(v4.0.0): Shade GA — V3.x consolidation + audit prep
V3.1 → V3.12 consolidated and tagged for the first GA release. Wire
format unchanged from 0.4.x — 4.0 peers interoperate with 0.4.x peers
byte-for-byte. The version bump is semantic: audit-cycle complete,
opt-in surface fully exposed, threat model refreshed for every new
surface.

Highlights:
- All 24 @shade/* packages bumped to 4.0.0 in lockstep.
- CHANGELOG 4.0.0 section is the canonical manifest of what landed.
- THREAT-MODEL extended (§10 fingerprint gates, §11 WebRTC P2P, §12
  Web-Worker boundary) + residual-risks table refreshed.
- OpenAPI now covers all 27 routes: prekey, transfer, KT, inbox,
  bridge, observer, /metrics, /healthz, /ready.
- MIGRATION 0.3.x → 4.0 documented + smoke-tested against
  shade migrate-storage on a real SQLite DB.
- docs/audit/REVIEW-BUNDLE.md + SCOPE.md ready for external reviewer.
- scripts/soak.ts harness for the GA-stable 2-week soak window.
- All V*.md plans archived under docs/archive/ with Status: Done.
- Voice/Video carved out into V5.0; 4.0 audit focuses on the frozen
  non-realtime stack.

Tests: TS 1000/1000 + Kotlin 11/11 cross-platform vectors green.
Docker: gt.zyon.no/stian/shade-prekey:4.0.0 builds and reports
  version 4.0.0 on /health.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:35:35 +02:00

4.4 KiB
Raw Blame History

Shade V3.2 — At-Rest Storage Encryption

Status: Implementert (0.4.0) — @shade/storage-encrypted, @shade/keychain, shade migrate-storage, shade rotate-storage-key Effort: L (48 uker) Forrige: V3.1 Adresserer: V2.1 §2


Mål

Opt-in beskyttelse av sensitiv state — identity-nøkler, session-state, valgfri stream-resume-secret — med nøkler som ikke ligger i klartekst i databasen. Trusselmodellen sier i dag eksplisitt at en stjålet DB eksponerer private nøkler; dette løser det for deploys som velger å aktivere det.


Scope

Inn

  • Ny EncryptedStorageProvider-wrapper som dekorerer SQLiteStorage / PostgresStorage.
  • Per-rad AES-256-GCM på sensitive felter (identity_*, session_*, valgfritt stream_state.streamSecret).
  • KDF-pluggin (default scrypt fra @noble/hashes) for passphrase-basert master-nøkkel.
  • Tre nøkkelkilder ut av boksen:
    1. Passphrase + KDF — utvikler oppgir secret ved oppstart.
    2. OS keychain — macOS Keychain, Linux libsecret, Windows Credential Vault (Node-only).
    3. App-injected key — appens egen kode forsyner 32-byte nøkkel (mest fleksibel).
  • Migrasjons-CLI: shade migrate-storage --encrypt --key-source=....
  • Trusselmodell-oppdatering: "når enabled, hva er fortsatt udekket" — memory compromise, swap, runtime-tap.

Ut

  • Browser/IndexedDB at-rest (egen pakke, vurderes etter V3.8).
  • HSM/Secure Enclave (separate driver senere).
  • "Always-on by default" — vi flyger opt-in for å ikke bryte eksisterende deploys.

Design

Krypteringsenhet

  • Per-rad AEAD: nonce(12) || ciphertext || tag(16).
  • nonce = HKDF(rowKey, "shade-row-nonce-v1" || tableName || pk)[..12] — deterministisk per (tabell, pk) for å unngå nonce-reuse uten å lagre nonce separat. Endring av (tabell, pk) → re-encryption.
  • AAD binder tableName || columnName || pk så feltombytting blokkeres.

Nøkkelhierarki

masterKey (fra kilde — passphrase / keychain / app-injected)
   │
   ├─ HKDF("shade-storage-v1") → storageKey (32 bytes)
   │     │
   │     └─ HKDF(storageKey, table || column) → fieldKey
   │
   └─ HKDF("shade-storage-version-v1") → versjonsnøkkel (rotasjon)

Migrasjon

  1. CLI leser ukryptert DB.
  2. Skriver rad-for-rad-kryptering til ny _v2-tabell.
  3. Atomisk rename + drop gammel.
  4. Backup .bak-fil etterlatt i samme dir.

Rotasjon

  • shade rotate-storage-key --new-source=... re-krypterer med ny masterKey.
  • Online ratchet (les med gammel, skriv med ny) for store DB.

Leveranser

Pakker

  • Ny modul: @shade/storage-encrypted (re-export over SQLite/PG).
  • Utvidelse i @shade/cli: migrate-storage, rotate-storage-key.
  • Hjelpe-pakke: @shade/keychain (Node-only, valgfri peer-dep) for OS-keychain.

Tester

  • Unit: KDF-derivasjon, nonce-determinisme, AAD-binding.
  • Integration: full lifecycle på SQLite + PG; start/stopp; krasj under migrasjon.
  • Tamper: bit-flip i ciphertext / AAD / nonce → dekrypterings-feil.
  • Vector-fil: kryss-sjekk masterKey → fieldKey-derivasjon mot test-vectors/storage-encryption.json.

Dokumentasjon

  • docs/storage-encryption.md — full guide.
  • THREAT-MODEL.md — ny kolonne "with at-rest enabled".
  • Migrasjonsnotat i MIGRATION.md.

Akseptansekriterier

  • Eksisterende ukryptert deploy fortsetter uten endringer (opt-in).
  • shade migrate-storage --encrypt migrerer en levende SQLite uten datatap, verifisert med dump-diff.
  • Rotasjon kan gjøres uten downtime > 5 s for små DB.
  • Wrong passphrase / wrong key → klar feilmelding, ikke krasj.
  • Test-vectors deles med Android-implementasjonen (V3.5 forplikter at vector-filen kjøres der).

Avhengigheter

  • V3.1 — THREAT-MODEL.md skal være lenket til testene først, så vi kan utvide tabellen.

Risiko

Datatap. En migrasjon som krasjer halvveis kan etterlate korrupt DB. Mitigeres ved:

  • Atomic-rename + .bak-fil.
  • Dry-run-modus (--dry-run validerer all dekryptering før skriving).
  • Refuser å starte hvis WAL har uncommitted writes.

Nøkkeltap = totaltap. Hvis bruker mister passphrase = ingen tilgang. Dokumenter klart, og pek på V3.10 (Social Recovery) som langtidsløsning.


Migrasjon

0.3.x deploys er ukrypterte → fortsatt ukrypterte. Aktivering er én CLI-kommando. Backwards-kompatibel.