The stego examples used nonexistent -i flags. Replace with actual CLI syntax: positional CARRIER argument, -r/--reference for shared photo, -m/--message for text, -f/--file for file payload. Add comprehensive examples covering encode, decode, dry-run, DCT mode, audio stego, credential generation, and channel key management. Also fix attest examples to match actual CLI commands. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
472 lines
16 KiB
Markdown
472 lines
16 KiB
Markdown
# SooSeF -- Soo Security Fieldkit
|
|
|
|
**Offline-first security toolkit for journalists, NGOs, and at-risk organizations.**
|
|
|
|
<!-- badges -->
|
|

|
|

|
|

|
|
|
|
---
|
|
|
|
## What is SooSeF?
|
|
|
|
SooSeF combines steganography, provenance attestation, and field security tools into a
|
|
single package designed for airgapped and resource-constrained environments. It lets you:
|
|
|
|
- **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
|
|
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`)
|
|
|
|
Stegasoo uses multi-factor authentication: a **reference photo** (shared image both
|
|
parties have), a **passphrase** (4+ words), and a **PIN** (6-9 digits). All three are
|
|
required to encode or decode. The passphrase and PIN are prompted interactively
|
|
(hidden input) if not provided via options.
|
|
|
|
```bash
|
|
# Encode a text message into an image
|
|
# CARRIER is the image to hide data in, -r is the shared reference photo
|
|
soosef stego encode cover.png -r shared_photo.jpg -m "Secret message"
|
|
# Passphrase: **** (prompted, hidden)
|
|
# PIN: **** (prompted, hidden)
|
|
# -> writes encoded PNG to current directory
|
|
|
|
# Encode with explicit output path
|
|
soosef stego encode cover.png -r shared_photo.jpg -m "Secret" -o stego_output.png
|
|
|
|
# Encode a file instead of text
|
|
soosef stego encode cover.png -r shared_photo.jpg -f document.pdf
|
|
|
|
# Dry run — check capacity without encoding
|
|
soosef stego encode cover.png -r shared_photo.jpg -m "Secret" --dry-run
|
|
|
|
# Decode a message from a stego image (same reference + passphrase + PIN)
|
|
soosef stego decode stego_output.png -r shared_photo.jpg
|
|
# Passphrase: ****
|
|
# PIN: ****
|
|
# -> prints decoded message or saves decoded file
|
|
|
|
# Decode and save file payload to specific path
|
|
soosef stego decode stego_output.png -r shared_photo.jpg -o recovered.pdf
|
|
|
|
# DCT mode for JPEG (survives social media compression)
|
|
soosef stego encode cover.jpg -r shared_photo.jpg -m "Secret" --platform telegram
|
|
|
|
# Audio steganography
|
|
soosef stego audio-encode audio.wav -r shared_photo.jpg -m "Hidden in audio"
|
|
soosef stego audio-decode stego.wav -r shared_photo.jpg
|
|
|
|
# Generate credentials
|
|
soosef stego generate # Generate passphrase + PIN
|
|
soosef stego generate --pin-length 8 # Longer PIN
|
|
|
|
# Channel key management
|
|
soosef stego channel status # Show current channel key
|
|
soosef stego channel generate # Generate new channel key
|
|
|
|
# Image info and capacity
|
|
soosef stego info cover.png # Image details + LSB/DCT capacity
|
|
```
|
|
|
|
### Attestation commands (`soosef attest`)
|
|
|
|
```bash
|
|
# Attest an image (sign with Ed25519 identity)
|
|
soosef attest IMAGE photo.jpg
|
|
soosef attest IMAGE photo.jpg --caption "Field report" --location "Istanbul"
|
|
|
|
# Batch attest a directory
|
|
soosef attest batch ./photos/ --caption "Field report"
|
|
|
|
# Verify an image against the attestation log
|
|
soosef attest verify photo.jpg
|
|
|
|
# View attestation log
|
|
soosef attest log --limit 20
|
|
```
|
|
|
|
### 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.
|