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>
4.4 KiB
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 (4–8 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 dekorererSQLiteStorage/PostgresStorage. - Per-rad AES-256-GCM på sensitive felter (
identity_*,session_*, valgfrittstream_state.streamSecret). - KDF-pluggin (default
scryptfra@noble/hashes) for passphrase-basert master-nøkkel. - Tre nøkkelkilder ut av boksen:
- Passphrase + KDF — utvikler oppgir secret ved oppstart.
- OS keychain — macOS Keychain, Linux libsecret, Windows Credential Vault (Node-only).
- 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 || pkså 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
- CLI leser ukryptert DB.
- Skriver rad-for-rad-kryptering til ny
_v2-tabell. - Atomisk rename + drop gammel.
- 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 --encryptmigrerer 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.mdskal 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-runvaliderer 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.