# Sharing and Encryption Guide

## How E2E Encryption Works in AnyFS

### The Problem

Agent state (memory, session history, learned skills) is sensitive. When stored in the
cloud, it must be encrypted so the server cannot read it. But the user must still be able
to share specific pieces with collaborators.

### AnyFS Solution

All encryption and decryption happens on the user's device. The server only stores
ciphertext. Sharing uses a "re-wrapping" technique: the DEK (Data Encryption Key) is
re-encrypted with a password-derived key, so the recipient can decrypt without the
original root key.

## Encryption Flow (Step by Step)

### 1. Initialize Identity and Keys

```bash
anyfs init
```

What happens:
- Generate `user_id` (e.g., `usr_4ad51f4a4687`)
- Generate `device_id` (e.g., `dev_3f2d95fda79e`)
- Derive wrap key: `SHA256("usr_4ad51f4a4687:dev_3f2d95fda79e")` (32 bytes)
- Generate root key: `os.urandom(32)` (256-bit random)
- Encrypt root key with wrap key using AES-256-GCM
- Store encrypted root key in `~/.anyfs/keys/rootkey.enc`
- Export recovery bundle to `~/.anyfs/keys/recovery.anyfs`

The wrap key is never stored. It is re-derived from identity whenever needed.

### 2. Create Encrypted Snapshot

```bash
anyfs capture claude-code -w .
anyfs snapshot create -w .
```

For each private namespace (memory, skills, soul, process):
1. Generate a new DEK: `os.urandom(32)` (unique per namespace per snapshot)
2. Encrypt payload with DEK: `AES-256-GCM(dek, plaintext)`
3. Wrap DEK with root key: `AES-256-GCM(root_key, dek, aad=namespace)`
4. Write envelope: `{wrapped_dek, encrypted_payload, namespace}`

The AAD (Additional Authenticated Data) binding means an envelope copied to a
different namespace will fail to decrypt.

### 3. Share with Password

```bash
anyfs share namespace memory -w . -p MyPassword
```

What happens:
1. Load root key from `~/.anyfs/keys/rootkey.enc`
2. Unwrap DEK: `AES-256-GCM_decrypt(root_key, wrapped_dek, aad=namespace)`
3. Derive share key: `SHA256("MyPassword:memory")` (32 bytes)
4. Re-wrap DEK: `AES-256-GCM_encrypt(share_key, dek, aad=namespace)`
5. Write share envelope: `{wrapped_dek(new), payload(unchanged), share_mode: "password"}`

The actual encrypted payload is NOT re-encrypted. Only the DEK wrapper changes.
This is efficient and secure.

### 4. Recipient Decrypts

```bash
anyfs share open /path/to/share.json -p MyPassword
```

What happens:
1. Load share envelope from file
2. Check `share_mode == "password"`
3. Derive share key: `SHA256("MyPassword:memory")`
4. Unwrap DEK: `AES-256-GCM_decrypt(share_key, wrapped_dek, aad=namespace)`
5. Decrypt payload: `AES-256-GCM_decrypt(dek, encrypted_payload)`
6. Write decrypted JSON to output file

No root key, no identity, no account needed. Just the password.

## Uploading via the Storage Gateway

When `storage_gateway_url` is configured, share files are uploaded to the storage gateway:

```
Client                    Storage Gateway                    GCS
  |                              |                              |
  |-- POST /blobs/upload ------->|                              |
  |   {bytes: base64, type}      |                              |
  |                              |-- put(blobs/<cid>) --------->|
  |                              |                              |
  |                              |<----- object stored ---------|
  |                              |                              |
  |<-- {cid, gateway_url} ------|                              |
```

The CID is a content-addressed identifier. Anyone with the share URL can download the
encrypted file from the public raw endpoint such as
`https://storage.anyfs.ai/raw/<cid>`, but cannot decrypt it without the password.

## Security Properties

| Property | Guarantee |
|----------|-----------|
| **Confidentiality** | Server and storage backend only see ciphertext |
| **Integrity** | GCM authentication tag detects tampering |
| **Namespace isolation** | AAD binding prevents cross-namespace attacks |
| **Forward secrecy** | Each snapshot uses fresh DEKs |
| **Share isolation** | Password-derived key is namespace-specific |
| **No root key exposure** | Sharing never reveals the root key |

## Recovery

If the device is lost:

1. Obtain `recovery.anyfs` bundle (should be backed up securely)
2. On new device: `anyfs import-recovery /path/to/recovery.anyfs`
3. This restores identity + encrypted root key
4. All previous snapshots can be decrypted again

If recovery bundle is also lost, all encrypted data is permanently inaccessible.

## Quick-Share Workflow (Complete)

The `quick-share` command combines all steps:

```bash
anyfs quick-share -w /path/to/project -p SharedPassword
```

Internal steps:
1. `init()` - Ensure identity + root key exist
2. `register_agent()` - Register workspace agent if not already done
3. `agent_create_remote()` - Register on API if possible
4. `capture()` - Extract agent state via adapter
5. `snapshot_create()` - Encrypt into snapshot with fresh DEKs
6. For each namespace:
   - `share_namespace()` - Re-wrap DEK with password
   - `_upload_to_storage_gateway()` - Upload to the storage gateway, get CID
7. Return `{snapshot_id, password, shares: {ns: {cid, gateway_url}}}`

Recipient workflow:
```bash
pip install anyfs-cli
anyfs init
anyfs share open https://storage.anyfs.ai/raw/<cid> -p SharedPassword
```
