FieldWitness -- an attestation and chain of custody toolkit.
Go to file
Aaron D. Lee f557cac45a
Some checks failed
CI / lint (push) Failing after 56s
CI / typecheck (push) Failing after 29s
Implement 6 evidence lifecycle features
1. Client-side SHA-256 in drop box: browser computes and displays
   file fingerprints via SubtleCrypto before upload. Receipt codes
   are HMAC-derived from file hash so source can verify
   correspondence. Source sees hash before submitting.

2. Drop box token persistence: replaced in-memory dict with SQLite
   (dropbox.db). Tokens and receipts survive server restarts.
   Receipt verification now returns filename, SHA-256, and timestamp.

3. RFC 3161 trusted timestamps + manual anchors: new
   federation/anchors.py with get_chain_head_anchor(),
   submit_rfc3161(), save_anchor(), and manual export format.
   CLI: `soosef chain anchor [--tsa URL]`. A single anchor
   implicitly timestamps every preceding chain record.

4. Derived work lineage: attestation metadata supports
   derived_from (parent record ID) and derivation_type
   (crop, redact, brightness, etc.) for tracking edits
   through the chain of custody.

5. Self-contained evidence package: new soosef.evidence module
   with export_evidence_package() producing a ZIP with images,
   attestation records, chain data, public key, standalone
   verify.py script, and README.

6. Cold archive export: new soosef.archive module with
   export_cold_archive() bundling chain.bin, verisoo log,
   LMDB index, keys, anchors, trusted keys, ALGORITHMS.txt
   documenting all crypto, and verification instructions.
   Designed for OAIS (ISO 14721) alignment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 21:04:20 -04:00
.gitea/workflows Disable test job in CI until stegasoo/verisoo are migrated 2026-04-01 18:38:14 -04:00
docker Fix Docker healthcheck hanging gunicorn workers 2026-03-31 19:46:04 -04:00
docs Add comprehensive documentation for v0.2.0 2026-04-01 19:55:07 -04:00
frontends Implement 6 evidence lifecycle features 2026-04-01 21:04:20 -04:00
src/soosef Implement 6 evidence lifecycle features 2026-04-01 21:04:20 -04:00
test_data Consolidate stegasoo and verisoo into soosef monorepo 2026-04-01 19:06:14 -04:00
tests Implement 14 power-user feature requests for field deployment 2026-04-01 19:35:36 -04:00
.gitignore Add vendor assets, fix CLI imports, make web UI bootable 2026-03-31 14:48:18 -04:00
CLAUDE.md Add comprehensive documentation for v0.2.0 2026-04-01 19:55:07 -04:00
pyproject.toml Bump version to 0.2.0 2026-04-01 19:49:54 -04:00
README.md Fix stego CLI examples in README with accurate syntax 2026-04-01 20:03:24 -04:00

SooSeF -- Soo Security Fieldkit

Offline-first security toolkit for journalists, NGOs, and at-risk organizations.

Version Python License


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

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)

pip install soosef

With extras

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:

# 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.

# 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)

# 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)

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)

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)

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)

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:

{
  "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:

pip install "soosef[api]"

This provides soosef.api with a FastAPI application served by uvicorn, suitable for programmatic integration.


Development

Setup

git clone https://github.com/alee/soosef.git
cd soosef
pip install -e ".[dev]"

Commands

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 for details.