Add FIPS 140-2 health checks on raw frames

Add health.py with monobit, runs, and long-run tests (FIPS 140-2 Annex C
thresholds for a 20000-bit sample). Wire into entropy.py so raw JPEG
bytes are tested before hashing; a frozen or degraded camera frame is
rejected and not used to seed the DRBG. Runs thresholds are doubled
because we count 0-runs and 1-runs together. Add --no-health to disable.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Radek
2026-08-31 09:42:12 +01:00
parent 239672ca63
commit 8ac9ab92eb
2 changed files with 94 additions and 1 deletions
+13 -1
View File
@@ -14,6 +14,8 @@ import time
import cv2
from health import check as health_check, HealthCheckError
sys.stdout.reconfigure(line_buffering=True)
@@ -67,6 +69,12 @@ def frame_entropy(frame):
return hashlib.sha256(img_encoded.tobytes()).digest()
def frame_raw_bytes(frame):
"""Return the raw JPEG-encoded frame bytes (for health checks)."""
_, img_encoded = cv2.imencode(".jpg", frame)
return img_encoded.tobytes()
def emit(blob, out_path):
if out_path:
with open(out_path, "ab") as f:
@@ -83,6 +91,7 @@ def main():
parser.add_argument("--loop", action="store_true", help="Run forever, generating numbers every second")
parser.add_argument("--interval", type=float, default=1.0, help="Seconds between iterations in --loop (default: 1.0)")
parser.add_argument("--out", help="Append raw bytes to this path (e.g. a FIFO) instead of printing hex")
parser.add_argument("--no-health", action="store_true", help="Disable FIPS 140-2 health checks on raw frames")
args = parser.parse_args()
if args.bit <= 0 or args.bit % 8 != 0:
@@ -96,7 +105,10 @@ def main():
def produce():
frame = fetch_frame_opencv(args.url)
entropy = frame_entropy(frame)
raw = frame_raw_bytes(frame)
if not args.no_health:
health_check(raw)
entropy = hashlib.sha256(raw).digest()
drbg = HMACDRBG(entropy)
return drbg.generate(num_bytes)