Add comprehensive documentation for v0.2.0
Some checks failed
CI / lint (push) Failing after 50s
CI / typecheck (push) Failing after 31s

- README.md: full project overview with features, install extras,
  CLI reference, web UI routes, config table, architecture diagrams,
  security model, /health API, and development setup
- CLAUDE.md: updated for monorepo — reflects inlined subpackages,
  new import patterns, pip extras, and added modules
- docs/deployment.md: practical RPi deployment guide covering
  hardware, OS setup, security hardening (swap/coredumps/firewall),
  installation, systemd service, config reference, fieldkit setup,
  key management, operational security limitations, troubleshooting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee 2026-04-01 19:55:07 -04:00
parent b9a541efdb
commit b7d4cbe286
3 changed files with 1122 additions and 33 deletions

View File

@ -1,16 +1,14 @@
# SooSeF — Claude Code Project Guide
SooSeF (Soo Security Fieldkit) is an offline-first security toolkit for journalists, NGOs,
and at-risk organizations. Part of the Soo Suite alongside Stegasoo and Verisoo.
and at-risk organizations. Monorepo consolidating Stegasoo and Verisoo as subpackages.
Version 0.1.0 · Python >=3.11 · MIT License
Version 0.2.0 · Python >=3.11 · MIT License
## Quick commands
```bash
# Development install (requires stegasoo and verisoo installed first)
pip install -e /path/to/stegasoo[web,dct,audio]
pip install -e /path/to/verisoo[cli]
# Development install (single command — stegasoo and verisoo are inlined subpackages)
pip install -e ".[dev]"
pytest # Run tests
@ -19,19 +17,75 @@ ruff check src/ tests/ frontends/ --fix # Lint
mypy src/ # Type check
```
### Pip extras
`stego-dct`, `stego-audio`, `stego-compression`, `attest`, `cli`, `web`, `api`,
`fieldkit`, `federation`, `rpi`, `all`, `dev`
## Architecture
```
src/soosef/ Core library
__init__.py Package init, __version__
_availability.py Runtime checks for optional subpackages (has_stegasoo, has_verisoo)
api.py Optional unified FastAPI app (uvicorn soosef.api:app)
audit.py Audit logging
cli.py Click CLI entry point (soosef command)
paths.py All ~/.soosef/* path constants (single source of truth)
config.py Unified config loader
exceptions.py SoosefError base exception
keystore/ Unified key management
stegasoo/ Steganography engine (inlined from stegasoo)
encode.py / decode.py Core encode/decode API
generate.py Cover image generation
crypto.py AES-256-GCM encryption
channel.py Channel key derivation
steganography.py LSB steganography core
dct_steganography.py DCT-domain JPEG steganography
spread_steganography.py MDCT spread-spectrum audio steganography
audio_steganography.py Audio stego pipeline
video_steganography.py Video stego pipeline
backends/ Pluggable stego backend registry (lsb, dct, protocol)
batch.py Batch operations
compression.py Payload compression (zstd, lz4)
steganalysis.py Detection resistance analysis
validation.py Input validation
models.py Data models
constants.py Magic bytes, version constants
cli.py Stegasoo-specific CLI commands
api.py / api_auth.py Stegasoo REST API + auth
image_utils.py / audio_utils.py / video_utils.py
keygen.py / qr_utils.py / recovery.py / debug.py / utils.py
platform_presets.py Social-media-aware encoding presets
verisoo/ Provenance attestation engine (inlined from verisoo)
attestation.py Core attestation creation
verification.py Attestation verification
crypto.py Ed25519 signing
hashing.py Perceptual + cryptographic hashing
embed.py Attestation embedding in images
merkle.py Merkle tree for batch attestation
binlog.py Binary attestation log
lmdb_store.py LMDB-backed trust store
storage.py Attestation storage abstraction
federation.py Federated attestation exchange
models.py Attestation, Verification dataclasses
exceptions.py Verisoo-specific exceptions
cli.py Verisoo-specific CLI commands
api.py Verisoo REST API
federation/ Federated attestation chain system
chain.py Hash chain construction
entropy.py Entropy source for chain seeds
models.py ChainEntry, ChainState dataclasses
serialization.py CBOR chain serialization + export
keystore/ Unified key management
manager.py Owns all key material (channel keys + Ed25519 identity)
models.py KeyBundle, IdentityBundle dataclasses
export.py Encrypted key bundle export/import
fieldkit/ Field security features
fieldkit/ Field security features
killswitch.py Emergency data destruction
deadman.py Dead man's switch
tamper.py File integrity monitoring
@ -40,27 +94,30 @@ src/soosef/ Core library
frontends/web/ Unified Flask web UI
app.py App factory (create_app())
auth.py SQLite3 multi-user auth (from stegasoo)
auth.py SQLite3 multi-user auth
temp_storage.py File-based temp storage with expiry
subprocess_stego.py Crash-safe subprocess isolation for stegasoo
stego_worker.py Background stego processing
stego_routes.py Stego route helpers
ssl_utils.py Self-signed HTTPS cert generation
blueprints/
stego.py /encode, /decode, /generate (from stegasoo)
attest.py /attest, /verify (wraps verisoo)
stego.py /encode, /decode, /generate
attest.py /attest, /verify
fieldkit.py /fieldkit/* (killswitch, deadman, status)
keys.py /keys/* (unified key management)
admin.py /admin/* (user management)
frontends/cli/ CLI entry point
main.py Click CLI wrapping stegasoo + verisoo + soosef commands
frontends/cli/ CLI package init (main entry point is src/soosef/cli.py)
```
## Dependency model
Stegasoo and Verisoo are pip dependencies, not forks:
- `import stegasoo` for steganography
- `import verisoo` for provenance attestation
- SooSeF adds: unified web UI, key management, fieldkit features
Stegasoo and Verisoo are inlined subpackages, not separate pip packages:
- `from soosef.stegasoo import encode` for steganography
- `from soosef.verisoo import Attestation` for provenance attestation
- Never `import stegasoo` or `import verisoo` directly
- `_availability.py` provides `has_stegasoo()` / `has_verisoo()` for graceful degradation
when optional extras are not installed
## Key design decisions
@ -70,7 +127,11 @@ Stegasoo and Verisoo are pip dependencies, not forks:
- **All state under ~/.soosef/** — one directory to back up, one to destroy
- **Offline-first**: All static assets vendored, no CDN. pip wheels bundled for airgap install
- **Flask blueprints**: stego, attest, fieldkit, keys, admin — clean route separation
- **Flask-WTF**: CSRF protection on all form endpoints
- **Waitress**: Production WSGI server (replaces dev-only Flask server)
- **FastAPI option**: `soosef.api` provides a REST API alternative to the Flask web UI
- **Pluggable backends**: Stego backends (LSB, DCT) registered via `backends/registry.py`
## Code conventions
Same as stegasoo: Black (100-char), Ruff, mypy, imperative commit messages.
Black (100-char), Ruff, mypy, imperative commit messages.

422
README.md
View File

@ -1,27 +1,417 @@
# SooSeF Soo Security Fieldkit
# SooSeF -- Soo Security Fieldkit
Offline-first security toolkit for journalists, NGOs, and at-risk organizations.
**Offline-first security toolkit for journalists, NGOs, and at-risk organizations.**
Part of the **Soo Suite**:
- **Stegasoo** — hide encrypted messages in media (steganography)
- **Verisoo** — prove image provenance and authenticity (attestation)
- **SooSeF** — unified fieldkit with killswitch, dead man's switch, and key management
<!-- badges -->
![Version](https://img.shields.io/badge/version-0.2.0-blue)
![Python](https://img.shields.io/badge/python-%3E%3D3.11-blue)
![License](https://img.shields.io/badge/license-MIT-green)
## Status
---
Pre-alpha. Phase 1 scaffolding complete.
## What is SooSeF?
## Install (development)
SooSeF combines steganography, provenance attestation, and field security tools into a
single package designed for airgapped and resource-constrained environments. It lets you:
```bash
pip install -e /path/to/stegasoo[web,dct,audio,cli]
pip install -e /path/to/verisoo[cli]
pip install -e ".[web,cli]"
```
- **Hide messages** in images, audio, and video using multiple steganographic techniques
- **Prove authenticity** of photos and documents with Ed25519 signatures and Merkle trees
- **Protect data in the field** with a killswitch, dead man's switch, tamper detection, USB device whitelisting, and GPS geofencing
- **Manage cryptographic keys** with identity rotation, channel key generation, and encrypted key bundle export/import
Stegasoo (steganography, v4.3.0) and Verisoo (attestation, v0.1.0) are included as
subpackages (`import soosef.stegasoo`, `import soosef.verisoo`). Everything ships as one
install: `pip install soosef`.
---
## Quick Start
```bash
soosef init # Generate identity + channel key, create ~/.soosef/
soosef serve # Start the web UI
pip install "soosef[web,cli]"
soosef init
soosef serve
```
This creates the `~/.soosef/` directory structure, generates an Ed25519 identity and
channel key, writes a default config, and starts an HTTPS web UI on
`https://127.0.0.1:5000`.
---
## Features
### Steganography (Stegasoo)
- **LSB encoding** -- bit-level message hiding in PNG images
- **DCT encoding** -- frequency-domain hiding in JPEG images (requires `stego-dct` extra)
- **Audio steganography** -- hide data in WAV/FLAC audio (requires `stego-audio` extra)
- **Video steganography** -- frame-level encoding
- AES-256-GCM encryption with Argon2id key derivation
- EXIF stripping on encode to prevent metadata leakage
- Compression support (zstandard, optional LZ4)
### Attestation (Verisoo)
- Ed25519 digital signatures for images and files
- Perceptual hashing (ImageHash) for tamper-evident photo attestation
- LMDB-backed attestation storage
- Append-only hash chain (CBOR-encoded) with Merkle tree verification
- Batch attestation for directories
### Fieldkit
- **Killswitch** -- emergency destruction of all data under `~/.soosef/`
- **Dead man's switch** -- automated purge if check-in is missed
- **Tamper detection** -- file integrity monitoring with baseline snapshots
- **USB whitelist** -- block or alert on unauthorized USB devices (Linux/pyudev)
- **Geofence** -- GPS boundary enforcement with configurable radius
### Key Management
- Two separate key domains: AES-256-GCM channel keys (stego) and Ed25519 identity keys (attestation)
- Key rotation for both identity and channel keys
- Encrypted key bundle export/import for secure backup and transfer
- QR code generation for key sharing
---
## Installation
### Basic install (core library only)
```bash
pip install soosef
```
### With extras
```bash
pip install "soosef[web,cli]" # Web UI + CLI (most common)
pip install "soosef[all]" # Everything except dev tools
pip install "soosef[dev]" # All + pytest, black, ruff, mypy
```
### Available extras
| Extra | What it adds |
|---|---|
| `stego-dct` | DCT steganography (numpy, scipy, jpeglib, reedsolo) |
| `stego-audio` | Audio steganography (pydub, soundfile, reedsolo) |
| `stego-compression` | LZ4 compression support |
| `attest` | Attestation features (imagehash, lmdb, exifread) |
| `cli` | Click CLI with rich output and QR code support |
| `web` | Flask web UI with Waitress/Gunicorn, includes attest + stego-dct |
| `api` | FastAPI REST API with uvicorn, includes stego-dct |
| `fieldkit` | Tamper monitoring (watchdog) and USB whitelist (pyudev) |
| `federation` | Peer-to-peer attestation federation (aiohttp) |
| `rpi` | Raspberry Pi deployment (web + cli + fieldkit + gpiozero) |
| `all` | All of the above |
| `dev` | All + pytest, pytest-cov, black, ruff, mypy |
### Airgapped / Raspberry Pi install
Bundle wheels on a networked machine, then install offline:
```bash
# On networked machine
pip download "soosef[rpi]" -d ./wheels
# Transfer ./wheels to target via USB
# On airgapped machine
pip install --no-index --find-links=./wheels "soosef[rpi]"
soosef init
soosef serve --host 0.0.0.0
```
---
## CLI Reference
All commands accept `--data-dir PATH` to override the default `~/.soosef` directory,
and `--json` for machine-readable output.
```
soosef [--data-dir PATH] [--json] COMMAND
```
### Core commands
| Command | Description |
|---|---|
| `soosef init` | Create directory structure, generate identity + channel key, write default config |
| `soosef serve` | Start the web UI (default: `https://127.0.0.1:5000`) |
| `soosef status` | Show instance status: identity, keys, chain, fieldkit, config |
### `soosef serve` options
| Option | Default | Description |
|---|---|---|
| `--host` | `127.0.0.1` | Bind address |
| `--port` | `5000` | Bind port |
| `--no-https` | off | Disable HTTPS (use HTTP) |
| `--debug` | off | Use Flask dev server instead of Waitress |
| `--workers` | `4` | Number of Waitress/Gunicorn worker threads |
### Steganography commands (`soosef stego`)
```bash
soosef stego encode -i cover.png -m "secret message" -o output.png
soosef stego decode -i output.png
```
### Attestation commands (`soosef attest`)
```bash
soosef attest sign -i photo.jpg # Sign a file
soosef attest verify -i photo.jpg # Verify attestation
soosef attest batch ./photos/ --caption "Field report"
```
### Fieldkit commands (`soosef fieldkit`)
```bash
soosef fieldkit status # Show fieldkit state
soosef fieldkit checkin # Reset dead man's switch timer
soosef fieldkit check-deadman # Check if deadman timer has expired
soosef fieldkit purge --confirm # Activate killswitch (destroys all data)
soosef fieldkit geofence set --lat 48.8566 --lon 2.3522 --radius 1000
soosef fieldkit geofence check --lat 48.8600 --lon 2.3500
soosef fieldkit geofence clear
soosef fieldkit usb snapshot # Snapshot current USB devices as whitelist
soosef fieldkit usb check # Check for unauthorized USB devices
```
### Key management commands (`soosef keys`)
```bash
soosef keys show # Display current key info
soosef keys export -o backup.enc # Export encrypted key bundle
soosef keys import -b backup.enc # Import key bundle
soosef keys rotate-identity # Generate new Ed25519 identity
soosef keys rotate-channel # Generate new channel key
```
### Chain commands (`soosef chain`)
```bash
soosef chain status # Show chain head, length, integrity
soosef chain verify # Verify entire chain integrity
soosef chain show INDEX # Show a specific chain record
soosef chain log --count 20 # Show recent chain entries
soosef chain backfill # Backfill existing attestations into chain
soosef chain export --start 0 --end 100 -o chain.cbor
```
---
## Web UI
Start with `soosef serve`. The web UI provides authenticated access to all features
through Flask blueprints.
### Routes
| Blueprint | Routes | Description |
|---|---|---|
| stego | `/encode`, `/decode`, `/generate` | Steganography operations |
| attest | `/attest`, `/verify` | Attestation signing and verification |
| fieldkit | `/fieldkit/*` | Killswitch, dead man's switch, status dashboard |
| keys | `/keys/*` | Key management, rotation, export/import |
| admin | `/admin/*` | User management (multi-user auth via SQLite) |
| health | `/health` | Capability reporting endpoint (see API section) |
<!-- TODO: screenshots -->
---
## Configuration
SooSeF loads configuration from `~/.soosef/config.json`. All fields have sensible defaults.
`soosef init` writes the default config file.
### Config fields
| Field | Type | Default | Description |
|---|---|---|---|
| `host` | string | `127.0.0.1` | Web UI bind address |
| `port` | int | `5000` | Web UI bind port |
| `https_enabled` | bool | `true` | Enable HTTPS with self-signed cert |
| `auth_enabled` | bool | `true` | Require login for web UI |
| `max_upload_mb` | int | `50` | Maximum upload size in MB |
| `session_timeout_minutes` | int | `15` | Session expiry |
| `login_lockout_attempts` | int | `5` | Failed logins before lockout |
| `login_lockout_minutes` | int | `15` | Lockout duration |
| `default_embed_mode` | string | `auto` | Stegasoo encoding mode |
| `killswitch_enabled` | bool | `false` | Enable killswitch functionality |
| `deadman_enabled` | bool | `false` | Enable dead man's switch |
| `deadman_interval_hours` | int | `24` | Check-in interval |
| `deadman_grace_hours` | int | `2` | Grace period after missed check-in |
| `deadman_warning_webhook` | string | `""` | URL to POST warning before auto-purge |
| `usb_monitoring_enabled` | bool | `false` | Enable USB device whitelist enforcement |
| `tamper_monitoring_enabled` | bool | `false` | Enable file integrity monitoring |
| `chain_enabled` | bool | `true` | Enable attestation hash chain |
| `chain_auto_wrap` | bool | `true` | Auto-wrap attestations in chain records |
| `backup_reminder_days` | int | `7` | Days before backup reminder |
| `gpio_killswitch_pin` | int | `17` | Raspberry Pi GPIO pin for hardware killswitch |
| `gpio_killswitch_hold_seconds` | float | `5.0` | Hold duration to trigger hardware killswitch |
### Environment variables
| Variable | Description |
|---|---|
| `SOOSEF_DATA_DIR` | Override the data directory (default: `~/.soosef`) |
---
## Architecture
### Source layout
```
src/soosef/
__init__.py Package init, __version__
cli.py Click CLI (entry point: soosef)
paths.py All path constants (single source of truth)
config.py Unified config loader (dataclass + JSON)
exceptions.py SoosefError base exception
stegasoo/ Steganography engine (subpackage)
verisoo/ Attestation engine (subpackage)
keystore/
manager.py Key material management (channel + identity)
models.py KeyBundle, IdentityBundle dataclasses
export.py Encrypted key bundle export/import
fieldkit/
killswitch.py Emergency data destruction
deadman.py Dead man's switch
tamper.py File integrity monitoring
usb_monitor.py USB device whitelist (Linux/pyudev)
geofence.py GPS boundary enforcement
frontends/web/
app.py Flask app factory (create_app())
auth.py SQLite3 multi-user auth
temp_storage.py File-based temp storage with expiry
subprocess_stego.py Crash-safe subprocess isolation
ssl_utils.py Self-signed HTTPS cert generation
blueprints/
stego.py /encode, /decode, /generate
attest.py /attest, /verify
fieldkit.py /fieldkit/*
keys.py /keys/*
admin.py /admin/*
```
### Data directory (`~/.soosef/`)
```
~/.soosef/
config.json Unified configuration
audit.jsonl Append-only audit trail
identity/ Ed25519 keypair (private.pem, public.pem, identity.meta.json)
stegasoo/ Channel key (channel.key)
attestations/ Verisoo attestation store (log.bin, index/, peers.json)
chain/ Hash chain (chain.bin, state.cbor)
auth/ Web UI auth database (soosef.db)
certs/ Self-signed TLS certificates
fieldkit/ Fieldkit state (deadman.json, tamper/, usb/, geofence.json)
temp/ Ephemeral file storage
instance/ Flask instance (sessions, secret key)
```
Sensitive directories (`identity/`, `auth/`, `certs/`, and the root) are created with
`0700` permissions.
---
## Security Model
**Two key domains, never merged.** Stegasoo uses AES-256-GCM with keys derived via
Argon2id from user-supplied factors. Verisoo uses Ed25519 for signing. These serve
different security purposes and are kept strictly separate.
**Killswitch priority.** The killswitch destroys all data under `~/.soosef/`, including
the audit log. This is intentional -- in a field compromise scenario, data destruction
takes precedence over audit trail preservation.
**Offline-first.** All static assets are vendored (no CDN calls). Pip wheels can be
bundled for fully airgapped installation. No network access is required for any core
functionality.
**Web UI hardening:**
- CSRF protection via Flask-WTF
- Session timeout (default: 15 minutes)
- Login rate limiting with lockout (5 attempts, 15-minute lockout)
- HTTPS by default with auto-generated self-signed certificates
- EXIF stripping on steganographic encode to prevent metadata leakage
**Subprocess isolation.** Steganographic operations run in a subprocess boundary
(`subprocess_stego.py`) to contain crashes and prevent memory corruption from affecting
the main web server process.
---
## API
### `/health` endpoint
The web UI exposes a `/health` endpoint that reports installed capabilities:
```json
{
"status": "ok",
"version": "0.2.0",
"capabilities": ["stego-lsb", "stego-dct", "attest", "fieldkit", "chain"]
}
```
Useful for monitoring and for clients to discover which extras are installed.
### FastAPI (optional)
Install the `api` extra for a standalone FastAPI REST interface:
```bash
pip install "soosef[api]"
```
This provides `soosef.api` with a FastAPI application served by uvicorn, suitable for
programmatic integration.
---
## Development
### Setup
```bash
git clone https://github.com/alee/soosef.git
cd soosef
pip install -e ".[dev]"
```
### Commands
```bash
pytest # Run tests with coverage
black src/ tests/ frontends/ # Format (100-char line length)
ruff check src/ tests/ frontends/ --fix # Lint
mypy src/ # Type check
```
### Code style
- Black with 100-character line length
- Ruff with E, F, I, N, W, UP rule sets
- mypy strict mode with missing imports ignored
- Imperative commit messages (e.g., "Add killswitch purge confirmation")
### Python support
Python 3.11, 3.12, 3.13, and 3.14.
---
## License
MIT License. See [LICENSE](LICENSE) for details.

638
docs/deployment.md Normal file
View File

@ -0,0 +1,638 @@
# SooSeF Deployment Guide
Deploying SooSeF on a Raspberry Pi for airgapped LAN use.
This guide is for field deployers: IT staff at NGOs, technically competent journalists,
and anyone setting up a shared SooSeF instance on a local network with no internet access.
---
## 1. Hardware Requirements
**Minimum:**
- Raspberry Pi 4 Model B, 2 GB RAM (4 GB recommended)
- 32 GB microSD card (Class 10 / A2 recommended)
- USB-C power supply (5V 3A, official RPi PSU recommended)
- Ethernet cable or pre-configured Wi-Fi for LAN
**Optional:**
- USB GPS module (e.g., VK-162) for geofencing
- Momentary push button + 10k pull-down resistor on GPIO pin 17 for hardware killswitch
- USB drive for airgap package transfer and key backups
- Case with passive cooling (no fan noise in sensitive environments)
If you plan to use the hardware killswitch button, wire it between GPIO 17 and 3.3V with
a 10k pull-down to GND. The default requires a 5-second hold to trigger (configurable via
`gpio_killswitch_hold_seconds` in config).
---
## 2. OS Setup
Install **Raspberry Pi OS Lite (64-bit, Bookworm or later)**. The desktop environment is
unnecessary and wastes resources.
After first boot:
```bash
# Set hostname
sudo hostnamectl set-hostname soosef-node
# Create a dedicated service user
sudo useradd -m -s /bin/bash soosef
sudo passwd soosef
# Enable SSH (if not already)
sudo systemctl enable --now ssh
# Update system packages (do this before going airgapped)
sudo apt update && sudo apt upgrade -y
```
Set a strong password. If possible, use SSH key authentication and disable password login
in `/etc/ssh/sshd_config` (`PasswordAuthentication no`).
---
## 3. Security Hardening
### 3.1 Disable or encrypt swap
Python does not zero memory when objects are garbage-collected. Cryptographic keys,
passwords, and plaintext can persist in swap long after the process exits. On an SD card,
this data may survive even after the swap file is deleted (wear leveling).
**Option A: Disable swap entirely (recommended if you have 4 GB+ RAM)**
```bash
sudo dphys-swapfile swapoff
sudo systemctl disable dphys-swapfile
sudo rm /var/swap
```
**Option B: Encrypted swap (if you need swap on 2 GB models)**
```bash
sudo dphys-swapfile swapoff
sudo systemctl disable dphys-swapfile
# Use dm-crypt with a random key (regenerated each boot)
echo "swap /dev/mmcblk0p3 /dev/urandom swap,cipher=aes-xts-plain64,size=256" | sudo tee -a /etc/crypttab
echo "/dev/mapper/swap none swap sw 0 0" | sudo tee -a /etc/fstab
```
Adjust the device path to match your partition layout.
### 3.2 Disable core dumps
A core dump from the SooSeF process would contain key material in plaintext.
```bash
echo "* hard core 0" | sudo tee -a /etc/security/limits.conf
echo "kernel.core_pattern=/dev/null" | sudo tee -a /etc/sysctl.d/99-soosef.conf
sudo sysctl -p /etc/sysctl.d/99-soosef.conf
```
### 3.3 Firewall
```bash
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 5000/tcp # SooSeF web UI
sudo ufw enable
```
If running fully airgapped, also deny outgoing:
```bash
sudo ufw default deny outgoing
```
### 3.4 Disable unnecessary services
```bash
sudo systemctl disable bluetooth
sudo systemctl disable avahi-daemon
sudo systemctl disable triggerhappy
```
---
## 4. Installation
### 4.1 System dependencies
```bash
sudo apt install -y \
python3 python3-pip python3-venv python3-dev \
libjpeg-dev libjpeg62-turbo-dev zlib1g-dev \
libffi-dev libssl-dev \
shred coreutils
```
`libjpeg-dev` is required for Pillow and jpeglib (DCT steganography). `libffi-dev` is
required for argon2-cffi.
### 4.2 Create virtual environment
```bash
sudo -u soosef -i # Switch to the soosef user
python3 -m venv ~/soosef-env
source ~/soosef-env/bin/activate
pip install --upgrade pip wheel
```
### 4.3 Install SooSeF
**If the Pi has internet access (pre-deployment):**
```bash
pip install "soosef[web,cli,fieldkit]"
```
For hardware killswitch support via GPIO:
```bash
pip install "soosef[rpi]"
```
The `rpi` extra includes `web`, `cli`, `fieldkit`, and `gpiozero`.
**For airgapped install (no internet on the Pi):**
On an internet-connected machine with the same architecture (aarch64 for RPi 4):
```bash
mkdir soosef-wheels
pip download "soosef[rpi]" -d soosef-wheels/
```
Copy the `soosef-wheels/` directory to a USB drive, then on the Pi:
```bash
pip install --no-index --find-links /media/usb/soosef-wheels/ "soosef[rpi]"
```
### 4.4 Verify installation
```bash
soosef --version
```
---
## 5. Initial Setup
### 5.1 Initialize SooSeF
```bash
soosef init
```
This creates the `~/.soosef/` directory structure:
```
~/.soosef/
config.json Unified configuration
identity/ Ed25519 signing keypair (verisoo)
private.pem
public.pem
identity.meta.json
stegasoo/ Stegasoo state
channel.key AES-256-GCM channel key
attestations/ Verisoo attestation log and index
chain/ Hash chain data
auth/ Web UI user database (SQLite)
certs/ Self-signed TLS certificates
fieldkit/ Killswitch, deadman, tamper, USB, geofence state
temp/ Ephemeral upload/processing files
instance/ Flask session data
audit.jsonl Append-only audit trail
```
The `identity/` and `auth/` directories are created with mode 0700.
`soosef init` generates:
- An Ed25519 identity keypair (for signing attestations)
- A channel key (for steganographic encoding)
- A default `config.json`
### 5.2 First user setup
Start the server and create the first admin user through the web UI:
```bash
soosef serve --host 0.0.0.0 --no-https
```
Navigate to `http://<pi-ip>:5000` from a device on the same LAN. The web UI will prompt
you to create the first user account.
After creating the admin account, stop the server (Ctrl+C) and restart with HTTPS
(see Section 6).
---
## 6. Running
### 6.1 Basic usage
```bash
# LAN-only, no HTTPS (acceptable if the network is physically isolated)
soosef serve --host 0.0.0.0 --no-https
# With self-signed HTTPS (recommended)
soosef serve --host 0.0.0.0
# Custom port
soosef serve --host 0.0.0.0 --port 8443
```
On first HTTPS start, SooSeF auto-generates a self-signed certificate at
`~/.soosef/certs/cert.pem`. Browsers will show a certificate warning -- this is expected
for self-signed certs. Instruct users to accept the warning or distribute the cert file
to client devices.
SooSeF uses Waitress (pure Python, no C dependencies) as its production server with 4
worker threads by default. Adjust with `--workers`.
### 6.2 systemd service
Create `/etc/systemd/system/soosef.service`:
```ini
[Unit]
Description=SooSeF Security Fieldkit
After=network.target
[Service]
Type=simple
User=soosef
Group=soosef
WorkingDirectory=/home/soosef
Environment="PATH=/home/soosef/soosef-env/bin:/usr/bin"
ExecStart=/home/soosef/soosef-env/bin/soosef serve --host 0.0.0.0 --workers 4
Restart=on-failure
RestartSec=5
# Hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/soosef/.soosef
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
```
Enable and start:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now soosef
sudo journalctl -u soosef -f # Watch logs
```
Add `--no-https` to `ExecStart` if running on a physically isolated LAN where TLS is
unnecessary.
---
## 7. Configuration
Configuration lives at `~/.soosef/config.json`. Edit it directly or use the web admin
panel. All fields have sensible defaults -- you only need to set what you want to change.
| Field | Default | Description |
|---|---|---|
| `host` | `127.0.0.1` | Bind address. Set to `0.0.0.0` for LAN access. |
| `port` | `5000` | TCP port for the web UI. |
| `https_enabled` | `true` | Enable self-signed HTTPS. |
| `auth_enabled` | `true` | Require login. Do not disable this. |
| `max_upload_mb` | `50` | Maximum file upload size in MB. |
| `session_timeout_minutes` | `15` | Idle session expiry. Lower is safer. |
| `login_lockout_attempts` | `5` | Failed logins before lockout. |
| `login_lockout_minutes` | `15` | Lockout duration. |
| `killswitch_enabled` | `false` | Enable software killswitch. |
| `deadman_enabled` | `false` | Enable dead man's switch. |
| `deadman_interval_hours` | `24` | Hours between required check-ins. |
| `deadman_grace_hours` | `2` | Grace period after missed check-in before purge. |
| `deadman_warning_webhook` | `""` | URL to POST a JSON warning when check-in is overdue. Must be a public URL (SSRF protection blocks private IPs). |
| `usb_monitoring_enabled` | `false` | Monitor for unauthorized USB devices. |
| `tamper_monitoring_enabled` | `false` | File integrity monitoring. |
| `chain_enabled` | `true` | Wrap attestations in a hash chain. |
| `chain_auto_wrap` | `true` | Automatically chain verisoo attestations. |
| `backup_reminder_days` | `7` | Warn if no backup in this many days. |
| `gpio_killswitch_pin` | `17` | GPIO pin for hardware killswitch button. |
| `gpio_killswitch_hold_seconds` | `5.0` | Required hold time to trigger hardware killswitch. |
Example minimal config for a field deployment:
```json
{
"host": "0.0.0.0",
"port": 5000,
"https_enabled": true,
"session_timeout_minutes": 10,
"deadman_enabled": true,
"deadman_interval_hours": 12,
"deadman_grace_hours": 1,
"killswitch_enabled": true,
"backup_reminder_days": 3
}
```
---
## 8. Fieldkit Setup
### 8.1 Dead man's switch
The dead man's switch requires periodic check-ins. If you miss a check-in, SooSeF sends
a warning during the grace period. If the grace period expires without a check-in, the
killswitch fires automatically and destroys all key material and data.
Arm it:
```bash
soosef fieldkit deadman arm --interval 12 --grace 1
```
This requires a check-in every 12 hours, with a 1-hour grace period.
Check in:
```bash
soosef fieldkit checkin
```
You can also check in through the web UI at `/fieldkit`.
Check status:
```bash
soosef status
```
The dead man's switch enforcement loop runs as a background thread inside `soosef serve`,
checking every 60 seconds. It will send a webhook warning (if configured) during the grace
period, then execute a full purge if the grace period expires.
Disarm:
```bash
soosef fieldkit deadman disarm
```
### 8.2 Geofence
If you have a USB GPS module, you can set a geographic boundary. SooSeF will trigger the
killswitch if the device moves outside the fence.
```bash
soosef fieldkit geofence set --lat 50.4501 --lon 30.5234 --radius 5000
```
Coordinates are in decimal degrees, radius in meters.
### 8.3 USB whitelist
Record currently connected USB devices as the trusted baseline:
```bash
soosef fieldkit usb learn
```
When monitoring is enabled, SooSeF will alert (or trigger killswitch, depending on config)
if an unknown USB device is connected.
### 8.4 Tamper baseline
Record file integrity baselines for critical files:
```bash
soosef fieldkit tamper baseline
```
SooSeF monitors for unexpected changes to tracked files when tamper monitoring is enabled.
---
## 9. Key Management
SooSeF manages two separate key domains:
- **Ed25519 identity key** (`~/.soosef/identity/`) -- used for signing attestations.
This is your provenance identity.
- **AES-256-GCM channel key** (`~/.soosef/stegasoo/channel.key`) -- used for
steganographic encoding/decoding. Shared with anyone who needs to read your
stego messages.
These are separate security concerns and are never merged.
### 9.1 Backup
Back up keys regularly. SooSeF warns if no backup has been taken within the
`backup_reminder_days` window (default: 7 days).
```bash
soosef keys backup --output /media/usb/soosef-backup.enc
```
This creates an encrypted bundle. You will be prompted for a passphrase. Store the USB
drive physically separate from the Pi.
### 9.2 Restore
```bash
soosef keys restore --input /media/usb/soosef-backup.enc
```
### 9.3 Key rotation
Generate a new channel key (the old one is overwritten):
```bash
soosef init --no-identity
```
Generate a new identity (the old one is overwritten -- all previous attestations will
reference the old fingerprint):
```bash
soosef init --no-channel
```
After rotating keys, take a fresh backup immediately.
### 9.4 Trusting collaborator keys
Import a collaborator's public key so you can verify their attestations:
```bash
soosef keys trust --import /media/usb/collaborator-pubkey.pem
```
Verify the fingerprint out-of-band (in person, over a secure channel) before trusting.
---
## 10. Operational Security Notes
SooSeF is a tool, not a shield. Understand what it cannot do.
### What SooSeF does not protect against
- **Physical coercion.** If someone forces you to unlock the device or reveal passwords,
no software can help. The killswitch is for situations where you can act before
interception, not during.
- **Social engineering.** SooSeF cannot prevent users from being tricked into revealing
credentials or disabling security features.
- **Leaving the browser open.** The session timeout helps, but if someone walks up to an
unlocked browser session, they have access. Train users to close the browser or lock the
screen.
- **Compromised client devices.** SooSeF secures the server. If a user's laptop has
malware, their browser session is compromised regardless of what the server does.
### Shred limitations on flash storage
The killswitch uses `shred` on Linux (3-pass overwrite + zero). On spinning disks, this
is effective. On SD cards and SSDs, **it is not reliable** because:
- Flash translation layers remap physical blocks. Overwritten data may persist on
remapped blocks.
- Wear leveling distributes writes across the flash, meaning the original block may be
preserved.
SooSeF's defense against this is **cryptographic erasure**: destroy the keys first, then
the data. Even if fragments of encrypted data survive on flash, they are useless without
the keys. The killswitch destroys keys before anything else, and keys are small enough to
fit in a single flash block.
This is why full-disk encryption matters -- see below.
### Full-disk encryption (LUKS)
For serious deployments, encrypt the entire SD card (or at least the data partition) with
LUKS. This way, even if the SD card is physically seized:
- All data at rest is encrypted
- Shred limitations are irrelevant because the underlying storage is encrypted
- Power-off = data inaccessible (assuming the LUKS passphrase is strong)
Setting up LUKS on Raspberry Pi OS is beyond the scope of this guide, but the short
version is: create an encrypted partition, mount it at `/home/soosef/.soosef`, and
configure auto-unlock via a keyfile on a separate USB (remove the USB after boot in
hostile environments).
### Memory considerations
Python does not securely zero memory. Key material, passwords, and plaintext may persist
in process memory and swap. The mitigations in Section 3 (disable swap, disable core
dumps) reduce the window, but a memory dump of the running process would expose secrets.
This is a fundamental limitation of Python-based security tools.
---
## 11. Troubleshooting
### Health check
SooSeF exposes a `/health` endpoint on the web UI. Hit it from the LAN to verify the
server is running:
```bash
curl -k https://<pi-ip>:5000/health
```
The `-k` flag skips certificate verification for self-signed certs.
### System status
```bash
soosef status
```
This checks identity key, channel key, trusted keys, dead man's switch state, geofence,
chain status, and backup status.
### Common issues
**scipy fails to build on Raspberry Pi**
scipy requires Fortran and BLAS libraries. On Raspberry Pi OS:
```bash
sudo apt install -y gfortran libopenblas-dev
```
If the build still fails (common on low-memory Pis), increase swap temporarily during
install, then disable it again:
```bash
sudo dphys-swapfile swapon
pip install scipy
sudo dphys-swapfile swapoff
```
Or use pre-built wheels:
```bash
pip install --prefer-binary scipy
```
**Argon2 OOM on low-memory Pi (2 GB)**
Argon2 password hashing is memory-intensive by design. If the server crashes during login
on a 2 GB Pi with other services running, either:
- Free memory by disabling unnecessary services
- Reduce Argon2 memory cost (not recommended -- weakens password hashing)
The default Argon2 parameters use ~64 MB per hash operation. With 2 GB total RAM and a
running server, this is tight but workable if nothing else is competing for memory.
**Web UI unreachable from LAN**
1. Check that `host` is set to `0.0.0.0` in config, not `127.0.0.1`
2. Check firewall: `sudo ufw status` -- port 5000 must be allowed
3. Check the service is running: `sudo systemctl status soosef`
4. Check the Pi's IP: `ip addr show`
**Certificate warnings in browser**
Expected with self-signed certificates. Users must click through the warning. To avoid
this, distribute `~/.soosef/certs/cert.pem` to client devices and install it as a
trusted certificate.
**Dead man's switch fires unexpectedly**
The switch checks every 60 seconds. If the Pi loses power or the service crashes and
does not restart within `interval_hours + grace_hours`, the switch will fire on the next
start. Make sure the systemd service is set to `Restart=on-failure` and the Pi has
reliable power.
If you need to perform maintenance, disarm the switch first:
```bash
soosef fieldkit deadman disarm
```
Re-arm when maintenance is complete.
**Permission errors on ~/.soosef/**
The `identity/`, `auth/`, and `certs/` directories are mode 0700. If running under a
different user than the one who ran `soosef init`, you will get permission denied errors.
Always run SooSeF as the same user.
```bash
ls -la ~/.soosef/
```