# Manifest Seal (Tamper Evidence)

Census creates an HMAC-SHA256 seal of the manifest database file to detect
offline tampering before trusting it. This follows the Tripwire/AIDE pattern
of signing the integrity database itself.

The seal is stored as a JSON sidecar file (`.seal`) alongside the manifest.
Only SHA-256 hashes of the manifest content are involved — the key never
leaves the client, and is never stored in the seal file.

## Creating a seal

```bash
# Generate a 256-bit HMAC key
census key-gen

# Create a seal after a scan
census seal manifest.db --key <hex64>

# Machine-readable output
census seal manifest.db --key <hex64> --json
```

## Verifying a seal

```bash
# Verify manifest integrity
census verify-seal manifest.db --key <hex64>

# Exit code: 0 = valid, 1 = invalid or error
census verify-seal manifest.db --key <hex64> && echo "intact" || echo "tampered"

# JSON output
census verify-seal manifest.db --key <hex64> --json
```

## Typical workflow

```bash
# 1. Generate a key (store securely)
KEY=$(census key-gen)

# 2. Scan and seal
census scan /data/sensitive --manifest inventory.db
census seal inventory.db --key "$KEY"

# 3. Before trusting the manifest (e.g. for --resume or integrity check)
census verify-seal inventory.db --key "$KEY"
census integrity inventory.db
```

## Seal file format

The `.seal` sidecar is a JSON file:

```json
{
  "algorithm": "HMAC-SHA256",
  "manifest": "inventory.db",
  "hmac": "a1b2c3d4...64 hex chars...",
  "created_at": "2026-03-18T14:30:00Z",
  "census_version": "1.1.0"
}
```

| Field | Description |
|-------|-------------|
| `algorithm` | Always `HMAC-SHA256` |
| `manifest` | Filename only (no directory path) |
| `hmac` | HMAC-SHA256 hex digest of the manifest file |
| `created_at` | UTC timestamp of seal creation |
| `census_version` | Census version that created the seal |

The key material is never stored in the seal file.

## Key management

- Keys must be exactly 64 hex characters (256 bits).
- Generate with `census key-gen` (cryptographically secure random).
- Store the key separately from the manifest (e.g. secrets manager, env var).
- Passing `--key` on the command line exposes the key in shell history and
  process listings. For automated workflows, use `--key "$ENV_VAR"`.

## Manifest self-attestation

Complementary to sealing, `census scan --attest-manifest` attests the
manifest's own SHA-256 hash via the CertiSigma API after scanning:

```bash
census scan /data --manifest inventory.db --attest-manifest
```

This creates a T0/T1/T2 timestamp anchor proving the manifest existed in
a specific state at scan time. The two mechanisms are complementary:

| Mechanism | Proves | Requires |
|-----------|--------|----------|
| `seal` / `verify-seal` | Manifest not modified since sealed | HMAC key |
| `--attest-manifest` | Manifest existed at scan time | API key |

## Security properties

- **Constant-time comparison**: uses `hmac.compare_digest()` (timing-attack
  resistant).
- **Streamed hashing**: manifest is read in 8 KB chunks (constant memory,
  safe for large manifests).
- **Strict key validation**: rejects whitespace, non-hex characters, and
  wrong-length keys via regex before `bytes.fromhex()`.
- **Graceful error handling**: `verify_seal()` returns a `SealResult`
  dataclass on all failure paths (never raises on runtime errors).

## Exit codes

| Code | Meaning |
|------|---------|
| `0` | Seal valid — manifest integrity verified |
| `1` | Seal invalid, missing, or error |

## Comparison with similar tools

| Tool | Mechanism | Scope |
|------|-----------|-------|
| Census seal | HMAC-SHA256 sidecar | Manifest file |
| AIDE | SHA-256 database | System files |
| Tripwire | Signed policy/database | System files |
| dm-verity | Merkle tree | Block device |
