{
  "slug": "store/encryption",
  "title": "End-to-End Encryption",
  "description": "Enable P2P encryption and zero-knowledge data protection in Store stores.",
  "url": "https://cuitty.com/docs/store/encryption",
  "markdown_url": "https://cuitty.com/docs/store/encryption.md",
  "json_url": "https://cuitty.com/docs/store/encryption.json",
  "frontmatter": {
    "title": "End-to-End Encryption",
    "description": "Enable P2P encryption and zero-knowledge data protection in Store stores.",
    "order": 4,
    "section": "Store",
    "updatedAt": "2026-05-12"
  },
  "headings": [
    {
      "depth": 1,
      "slug": "end-to-end-encryption",
      "text": "End-to-End Encryption"
    },
    {
      "depth": 2,
      "slug": "enable-encryption",
      "text": "Enable encryption"
    },
    {
      "depth": 2,
      "slug": "how-it-works",
      "text": "How it works"
    },
    {
      "depth": 2,
      "slug": "key-management",
      "text": "Key management"
    },
    {
      "depth": 3,
      "slug": "device-keys",
      "text": "Device keys"
    },
    {
      "depth": 3,
      "slug": "key-rotation",
      "text": "Key rotation"
    },
    {
      "depth": 2,
      "slug": "encrypted-sync",
      "text": "Encrypted sync"
    },
    {
      "depth": 3,
      "slug": "sharing-keys-between-peers",
      "text": "Sharing keys between peers"
    },
    {
      "depth": 2,
      "slug": "zero-knowledge-architecture",
      "text": "Zero-knowledge architecture"
    }
  ],
  "body_markdown": "# End-to-End Encryption\n\n## Enable encryption\n\n```ts\nimport { createStore } from \"@cuitty/store\";\n\nconst store = await createStore({\n  name: \"my-app\",\n  adapter: \"sqlite\",\n  path: \"./data/my-app.db\",\n  encrypt: true,\n});\n```\n\nWhen `encrypt: true` is set, all data is encrypted on the device before it is written to disk or sent over the network. The sync server, storage backend, and any intermediary never see plaintext.\n\n## How it works\n\nStore generates a 256-bit device key on first run and stores it in the OS keychain (or a local keyfile as fallback). Every record is encrypted with AES-256-GCM using a per-record nonce derived from the key and the record's path.\n\n```\nplaintext --> AES-256-GCM encrypt --> ciphertext --> store / sync\n```\n\nReads reverse the process transparently. Application code works with plain objects -- encryption and decryption are invisible to the caller.\n\n## Key management\n\n### Device keys\n\nEach device generates its own key on first use. The key never leaves the device unless explicitly exported.\n\n```ts\n// Export the device key (for backup or migration)\nconst exportedKey = await store.crypto.exportKey();\n\n// Import a key on a new device\nconst store = await createStore({\n  name: \"my-app\",\n  adapter: \"sqlite\",\n  path: \"./data/my-app.db\",\n  encrypt: true,\n  key: exportedKey,\n});\n```\n\n### Key rotation\n\nRotate the encryption key without downtime. Store re-encrypts existing records in the background.\n\n```ts\nawait store.crypto.rotateKey();\n```\n\nAfter rotation the old key is kept in a sealed keyring so previously-synced peers can still decrypt historical data until they receive the new key.\n\n## Encrypted sync\n\nWhen encryption and sync are both enabled, peers exchange ciphertext. Decryption happens only on the receiving device using a shared key.\n\n```ts\nconst store = await createStore({\n  name: \"my-app\",\n  adapter: \"sqlite\",\n  path: \"./data/my-app.db\",\n  encrypt: true,\n  sync: {\n    remote: \"postgres\",\n    strategy: \"last-write-wins\",\n  },\n});\n```\n\n### Sharing keys between peers\n\nPeers use a Diffie-Hellman key exchange to establish a shared secret. No key material is transmitted in the clear.\n\n```ts\n// On device A: generate an invite\nconst invite = await store.crypto.createInvite();\n// --> send `invite.code` to device B out-of-band\n\n// On device B: accept the invite\nawait store.crypto.acceptInvite(invite.code);\n```\n\nOnce paired, both devices derive the same data key and can decrypt each other's records.\n\n## Zero-knowledge architecture\n\nThe sync server stores only ciphertext and opaque metadata (record size, sync timestamps). It cannot:\n\n- Read record contents\n- Identify record types or schemas\n- Correlate records across stores (keys are encrypted too)\n\nEven if the server is compromised, an attacker gains no usable data without the device keys.",
  "links_out": []
}