# Clavenar Customer-Controlled Secure Exchange

Protocol version 1 · tool:
`/tools/clavenar-secure-exchange.py`

## Boundary

Use this workflow only after an executed Order Form identifies both exact
recipient key commitments, a customer-controlled delivery location, permitted
content, owner, purpose, and expiry. Never put credentials or production
detail in a general form, issue, source repository, ordinary email, or chat.

The tool runs locally and performs no network request. It encrypts a bounded
directory to two distinct X25519 recipients: one key controlled by the
customer and one order-specific Clavenar key verified through an authenticated
channel. The envelope may be stored in the customer’s own object store,
managed file exchange, or equivalent system. The customer controls access,
audit, revocation, and deletion of that transport copy.

## Requirements

- Python 3.11 or later
- `cryptography` 42 or later
- the exact tool SHA-256 from
  `/schemas/customer-legal-exchange-v1.fixture.json`
- a private local directory with mode 0700 for key and output files

Install the dependency in a customer-reviewed isolated environment:

```sh
python3 -m venv .secure-exchange-venv
. .secure-exchange-venv/bin/activate
python3 -m pip install 'cryptography>=42,<46'
```

## 1. Customer creates and retains its key

```sh
umask 077
python3 clavenar-secure-exchange.py keygen \
  --private customer-exchange.key \
  --public customer-exchange.recipient.json
```

Send only the public recipient file and its displayed `keyId`. Never send the
private file. Store and back it up under customer key-management policy.

## 2. Verify the Clavenar recipient

Obtain the order-specific Clavenar public recipient through the authenticated
contact and channel in the signed Order Form. Verify its SHA-256 `keyId`
through a second authenticated method. Do not use a recipient copied from a
ticket, general website form, or unverified message. The pack intentionally
publishes no universal Clavenar recipient.

## 3. Prepare a bounded input directory

Include only the minimum files approved in the Order Form. Remove unrelated
personal data, secrets, history, logs, caches, and editor files. Symlinks are
rejected. The protocol permits at most 128 files, 8 MiB per file, and 16 MiB
aggregate plaintext.

## 4. Encrypt locally

```sh
python3 clavenar-secure-exchange.py pack \
  --input approved-input \
  --customer-recipient customer-exchange.recipient.json \
  --clavenar-recipient clavenar-order.recipient.json \
  --lifetime-hours 72 \
  --output exchange.clex.json
```

The lifetime must be from 1 through 168 hours. The output is an encrypted JSON
envelope containing only bounded metadata, SHA-256 commitments, wrapped data
keys, and AES-256-GCM ciphertext.

## 5. Inspect and deliver

```sh
python3 clavenar-secure-exchange.py inspect --input exchange.clex.json
```

Compare the bundle ID, expiry, both recipient roles and key IDs, file count,
and plaintext byte total with the approved change record. Upload only the
encrypted envelope to the customer-controlled location and grant the exact
bounded Clavenar principal. Send only the location reference and bundle ID
through the authenticated channel.

## 6. Authenticate and decrypt

An authorized recipient uses:

```sh
umask 077
python3 clavenar-secure-exchange.py unpack \
  --input exchange.clex.json \
  --private authorized-recipient.key \
  --output decrypted-once
```

Unpack rejects a wrong key, altered recipient, manifest, path, ciphertext, or
expiry. It creates a new mode-0700 directory and mode-0600 files. Review,
import, and delete the local plaintext under the Order Form’s purpose and
retention limits.

## 7. Close the exchange

Customer revokes Clavenar’s transport access and removes the transport copy
when the approved window ends. Both parties rotate any credential that might
have been exposed before encryption, delete temporary plaintext, and retain
only the minimized bundle/key commitments, outcome, owner, and deletion
evidence. A new purpose, recipient, or expired exchange requires a new
envelope and approval; never extend or mutate an existing bundle.
