From de17686a9b24dea33ea460d07d4035f8a0c32db5 Mon Sep 17 00:00:00 2001 From: Radek Date: Wed, 2 Sep 2026 11:52:24 +0100 Subject: [PATCH] Update README and notes for DRBG, health checks, and HTTP service Rewrite README to reflect the actual pipeline (frame -> health check -> SHA-256 -> HMAC-DRBG -> emit), document all entropy.py flags, the HTTP service endpoints and env vars, container build/run, Kubernetes notes, and the remote-consumption rngd flow. Fix the notes.md typos and align its commands with the new --out flag. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- README.md | 171 +++++++++++++++++++++++++++++++++++++----------------- notes.md | 14 +++-- 2 files changed, 125 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 61a4c74..1133f12 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,144 @@ # Entropy-RNG: Camera-Based Random Number Generator -This project uses a live video feed from an **Axis M1013** network camera to generate cryptographically secure random numbers. The camera is pointed at a high-contrast scene (e.g., ceiling and lamps) to ensure ever-changing pixel data, which is used as a source of entropy. +This project uses a live video feed from a network camera (e.g. an **Axis M1013**) to generate cryptographically secure random numbers. The camera is pointed at a high-contrast, ever-changing scene (e.g. ceiling and lamps) so the pixel data carries genuine entropy. --- ## How It Works -1. **Capture Image Frames** - The script fetches a single frame from the camera's MJPEG stream using OpenCV or manual HTTP requests. - -2. **Extract Entropy** - The pixel data from the frame is hashed using SHA-256 to generate a high-quality entropy pool. - -3. **Generate Random Numbers** - The entropy is used to seed Python's `secrets` module, which generates cryptographically secure random numbers of specified bit lengths (e.g., 128-bit, 256-bit). +1. **Capture frame** — fetch a single MJPEG frame from the camera via OpenCV. +2. **Health check** — the raw JPEG bytes are run through FIPS 140-2 continuous tests (monobit, runs, long-run). A frozen or degraded frame is rejected before use. +3. **Extract entropy** — the frame is SHA-256 hashed to a 32-byte digest. +4. **DRBG** — the digest seeds a NIST SP 800-90A HMAC-DRBG (SHA-256), which generates the output bytes. The camera genuinely contributes entropy; the output is not just relabeled OS randomness. +5. **Emit** — hex to stdout, or raw bytes to a file/FIFO (`--out`). --- ## Requirements -- Python 3.x -- OpenCV (`opencv-python`) -- Pillow (`Pillow`) -- `requests` library +- Python 3.10+ +- `opencv-python`, `fastapi`, `uvicorn`, `pytest` -Install dependencies: ```bash -pip install opencv-python Pillow requests +pip install -r requirements.txt +``` + +On Debian/Ubuntu you also need OpenCV runtime libs: `apt-get install libgl1 libglib2.0-0`. + +--- + +## Local Usage + +### Single number + +```bash +python3 entropy.py --bit 256 +``` + +### Loop, writing raw bytes to a FIFO for `rngd` + +```bash +mkfifo /tmp/entropy.fifo +python3 entropy.py --loop --bit 512 --out /tmp/entropy.fifo & +sudo rngd -f -W 90% -x rdrand -x jitter -x pkcs11 -x rtlsdr \ + -O namedpipe:path:/tmp/entropy.fifo -O namedpipe:timeout:2 +``` + +### Flags + +| Flag | Default | Description | +|---|---|---| +| `--url` | `http://192.168.0.200/mjpg/video.mjpg` | Camera MJPEG stream URL | +| `--bit` | `256` | Bit length of each random number (multiple of 8) | +| `--single N` | `1` | Generate N numbers and exit | +| `--loop` | off | Run forever | +| `--interval` | `1.0` | Seconds between iterations in `--loop` | +| `--out PATH` | stdout | Append raw bytes to a file/FIFO instead of printing hex | +| `--no-health` | off | Disable FIPS 140-2 health checks | + +`--loop` and `--single` are mutually exclusive. + +--- + +## HTTP Service (for remote systems) + +`api.py` runs the camera producer in a background thread and serves the latest entropy blob over HTTP, so other systems can pull entropy to seed their own pools. + +### Run locally + +```bash +uvicorn api:app --host 0.0.0.0 --port 8000 +``` + +### Endpoints + +| Method | Path | Auth | Returns | +|---|---|---|---| +| GET | `/` | none | service info | +| GET | `/healthz` | none | `{status: ok}` (liveness probe) | +| GET | `/entropy` | `X-API-Key` if configured | `{hex, bits, ts}` | + +### Configuration (env vars) + +| Var | Default | Description | +|---|---|---| +| `ENTROPY_CAMERA_URL` | `http://192.168.0.200/mjpg/video.mjpg` | Camera MJPEG URL | +| `ENTROPY_BITS` | `256` | Bits per blob | +| `ENTROPY_INTERVAL` | `1.0` | Seconds between frames | +| `ENTROPY_NO_HEALTH` | `0` | `1` disables health checks | +| `ENTROPY_API_KEY` | empty | Shared secret for `/entropy`; empty = no auth | + +--- + +## Container Deployment + +### Build and run + +```bash +docker build -t entropy-rng . +docker run -d -p 8000:8000 \ + -e ENTROPY_CAMERA_URL=http://192.168.0.200/mjpg/video.mjpg \ + -e ENTROPY_API_KEY=changeme \ + entropy-rng +``` + +The container has a healthcheck against `/healthz`. The camera must be reachable from the container's network. + +### Kubernetes notes + +- **Replicas: 1.** Multiple pods hitting the same camera produce correlated output. Pin to a single replica. +- **Camera reachability** is the real constraint. Schedule the pod on a node that can reach the camera (use `nodeSelector` or a labeled node), or expose the camera via a `Service`. +- Store `ENTROPY_API_KEY` in a `Secret` and mount as an env var. +- Use an `Ingress` or `Service` for TLS termination in front of uvicorn. + +--- + +## Consuming Remotely (seed another system's pool) + +A remote Linux box can pull a blob and feed its kernel RNG via `rngd`: + +```bash +curl -s -H "X-API-Key: changeme" https://entropy-svc.internal/entropy \ + | python3 -c "import sys,json; print(json.load(sys.stdin)['hex'])" \ + | xxd -r -p > /tmp/entropy.fifo +sudo rngd -f -W 90% -x rdrand -x jitter -x pkcs11 -x rtlsdr \ + -O namedpipe:path:/tmp/entropy.fifo -O namedpipe:timeout:2 ``` --- -## Usage +## Tests -### 1. OpenCV Method (Recommended) -Run the OpenCV script to fetch a frame and generate random numbers: ```bash -python3 entropy-rng-opencv.py +pytest -q ``` -**Example Output:** -``` -128-bit random number: 0x67dbaf3c5eba5a0d41429d2173a21f2f -256-bit random number: 0xe3a707c10f70f975e074633ad22ea0eaaa8b482e87c6418e3ae2380b2e647a4 -``` - -### 2. Manual HTTP Method -Run the manual script (alternative to OpenCV): -```bash -python3 entropy-rng-cam.py -``` - -**Example Output:** -``` -128-bit random number: 0x494d97b11a4b6008e4597cfc29108354 -256-bit random number: 0xd59f7f4d22ebf7507b702fb60e0f2a6ccbf2ad4b5e3ab969f9152222da8e9443 -``` - ---- - -## Output Format - -The generated random numbers are in **hexadecimal format** (e.g., `0x67dbaf3c5eba5a0d41429d2173a21f2f`). -- 128-bit numbers: 32 hex digits -- 256-bit numbers: 64 hex digits - ---- - -## Why This Approach? - -- **True Entropy Source**: The camera feed provides a dynamic, unpredictable source of entropy. -- **Cryptographically Secure**: Uses SHA-256 hashing and Python's `secrets` module. -- **No Additional Hardware**: Leverages existing network cameras. +Covers the HMAC-DRBG (determinism, reseed, length, reseed limit), health checks (random passes, frozen/all-ones/short/long-run rejected), a bit-balance smoke test, and the API endpoints including auth gating. Tests stub the camera, so they run without hardware. --- ## Notes -- Ensure the camera feed is **dynamic** (e.g., pointing at changing light patterns). -- For production use, consider adding error handling and logging. +- Point the camera at a dynamic scene. A static frame will fail health checks and be rejected. +- The DRBG is reseeded from each frame, so output changes even if the camera noise is modest. +- Auth is a single shared secret for now. When you need per-client keys, rotate to HMAC-signed blobs or mTLS — the API layer is where that plugs in. diff --git a/notes.md b/notes.md index 60f6293..07f26bf 100644 --- a/notes.md +++ b/notes.md @@ -1,10 +1,12 @@ -# In order to use this there needs to be a IP webcam with some stream availabgle to use as the randomes generating source. -# Sugest review code to see how it should be provided to the script. +# In order to use this there needs to be an IP webcam with a stream available to use as the randomness generating source. +# Suggest reviewing the code to see how it should be provided to the script. # -# generate entropy via pie fifo file. -python3 entropy.py --loop --bit 1024 | xxd -r > /tmp/entropy.fifo +# generate entropy via a pipe file +mkfifo /tmp/entropy.fifo +python3 entropy.py --loop --bit 512 --out /tmp/entropy.fifo & # -# Use the generated entropy +# Use the generated entropy sudo rngd -f -W 90% -x rdrand -x jitter -x pkcs11 -x rtlsdr -O namedpipe:path:/tmp/entropy.fifo -O namedpipe:timeout:2 # -# +# Or serve it over HTTP for remote systems (see README -> HTTP Service) +uvicorn api:app --host 0.0.0.0 --port 8000