S
Store

Encryption

Envelope encryption and signed payloads for end-to-end data protection across devices.

Envelope encryption

Store uses envelope encryption to protect data at rest and in transit. Each record is encrypted with a unique data encryption key (DEK). The DEK itself is encrypted with a key-encryption key (KEK) derived from your master key. This two-layer approach means rotating the master key does not require re-encrypting every record.

Plaintext → [DEK] → Ciphertext
                DEK → [KEK] → Encrypted DEK
                        KEK ← Master Key

Enabling encryption

Set encryption requirements on the active profile. Runtime adapters then enforce or report the required posture.

import { createStore } from "@cuitty/store/client";

const store = await createStore({
  module: "secrets",
  profile: {
    id: "secure-local",
    name: "Secure Local",
    local: { adapter: "local.sqlite", path: ".cuitty/store/secrets.sqlite" },
    remotes: [],
    routes: [],
    encryption: { atRest: "required", remote: "required", p2p: "required" },
    sync: { mode: "manual" },
  },
  schema: {
    secrets: { class: "secret" },
  },
});

// Writes are encrypted transparently
await store.secret("secrets").set("api-key:stripe", {
  ref: "secret://stripe/live",
  created: Date.now(),
});

Envelope signing

P2P payload envelopes are encrypted and signed before transport. The receiving device verifies the signature before opening the payload.

import { generateKey, openEnvelope, sealEnvelope } from "@cuitty/store/crypto";

const payloadKey = generateKey("payload");
const signingKey = generateKey("signing");

const envelope = sealEnvelope({
  fromPeerId: "peer-a",
  toPeerId: "peer-b",
  workspaceId: "workspace",
  namespace: "notes",
  sequence: 1,
  payload: "hello",
}, payloadKey, signingKey);

const opened = openEnvelope(envelope, payloadKey, signingKey);
console.log(new TextDecoder().decode(opened)); // "hello"

Key management

Keys should be stored as secret references in profiles or remote target config. Do not put raw keys in committed configuration.

const profile = {
  id: "team",
  name: "Team",
  local: { adapter: "local.sqlite", path: ".cuitty/store/team.sqlite" },
  remotes: [
    { id: "vault", adapter: "vault.secret", secretRef: "secret://store/vault/token" },
  ],
  routes: [],
  encryption: { atRest: "required", remote: "required", p2p: "required" },
  sync: { mode: "manual" },
};

Key rotation re-wraps existing DEKs under a new KEK without decrypting and re-encrypting the underlying data. This operation is atomic and safe to run while the store is in use.

Threat model

Encryption protects against unauthorized access to the storage backend (a stolen device, a compromised database server). It does not protect against a compromised application process that holds the master key in memory.