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 <vibe@mistral.ai>
Entropy-RNG: Camera-Based Random Number Generator
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
- Capture frame — fetch a single MJPEG frame from the camera via OpenCV.
- 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.
- Extract entropy — the frame is SHA-256 hashed to a 32-byte digest.
- 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.
- Emit — hex to stdout, or raw bytes to a file/FIFO (
--out).
Requirements
- Python 3.10+
opencv-python,fastapi,uvicorn,pytest
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
python3 entropy.py --bit 256
Loop, writing raw bytes to a FIFO for rngd
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
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
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
nodeSelectoror a labeled node), or expose the camera via aService. - Store
ENTROPY_API_KEYin aSecretand mount as an env var. - Use an
IngressorServicefor 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:
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
Tests
pytest -q
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
- 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.