IA Cloud Memory

Security model

IA Cloud Memory treats its own backend as untrusted storage. Every byte of user data — file contents, paths, manifests, commit messages — is encrypted in the browser before it ever reaches the server.

Two distinct secrets

We can recover or reset your account password (after the usual proof of email control). We cannot recover your encryption passphrase — losing it means losing your data.

How files are encrypted

Every file is stored as two separate ciphertexts:

Manifests (the path → content-hash mapping) and commits (parent links, messages) are themselves files: encrypted JSON, stored as ordinary objects.

Why two-layer wrapping?

It makes key rotation cheap. To switch master keys we only need to re-wrap the per-object CEKs (66 bytes each), not re-encrypt the content envelopes. Hashes don't change, manifests don't change, commits don't change. The full chain stays valid.

What the server stores

Object   ::= magic||v||flags||nonce||AES-GCM(content, CEK)
Wrap     ::= magic||v||flags||nonce||AES-GCM(CEK, masterKey)
Manifest ::= encrypted JSON { path → contentHash }
Commit   ::= encrypted JSON { parent, manifestHash, message }
Ref      ::= "main" → commitHash (CAS-protected via etag)
User     ::= { id, email, password_hash (scrypt), crypto_salt (public) }
Session  ::= { id (sha256(token)), user_id, expires_at }
APIKey   ::= { id, user_id, token_hash (sha256), name }

Per-user isolation is enforced by SQL. Every encrypted-data table has a user_id column, and all queries filter on it. There is no API path that can return another user's ciphertexts.

What the server CANNOT do

What the server CAN see (metadata)

Threat model — out of scope (v1)