diff --git a/README.md b/README.md index 17a5f4c..61a4c74 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,81 @@ -# entropy +# Entropy-RNG: Camera-Based Random Number Generator -Generate entropy from a MJPEG stream \ No newline at end of file +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. + +--- + +## 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). + +--- + +## Requirements + +- Python 3.x +- OpenCV (`opencv-python`) +- Pillow (`Pillow`) +- `requests` library + +Install dependencies: +```bash +pip install opencv-python Pillow requests +``` + +--- + +## Usage + +### 1. OpenCV Method (Recommended) +Run the OpenCV script to fetch a frame and generate random numbers: +```bash +python3 entropy-rng-opencv.py +``` + +**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. + +--- + +## Notes + +- Ensure the camera feed is **dynamic** (e.g., pointing at changing light patterns). +- For production use, consider adding error handling and logging. diff --git a/entropy-rng-cam.py b/entropy-rng-cam.py new file mode 100644 index 0000000..d0cce55 --- /dev/null +++ b/entropy-rng-cam.py @@ -0,0 +1,47 @@ +import hashlib +import requests +from io import BytesIO +from PIL import Image +import secrets + +def fetch_single_frame(url): + response = requests.get(url, stream=True) + boundary = b'--myboundary' + data = b'' + in_frame = False + frame_data = b'' + for chunk in response.iter_content(chunk_size=1024): + data += chunk + if not in_frame and boundary in data: + in_frame = True + data = data.split(boundary, 1)[1] + if in_frame and b'Content-Type: image/jpeg' in data: + parts = data.split(b'\r\n\r\n', 1) + if len(parts) > 1: + frame_part = parts[1] + if b'\r\n--myboundary' in frame_part: + frame_data = frame_part.split(b'\r\n--myboundary', 1)[0] + try: + return Image.open(BytesIO(frame_data)) + except Exception as e: + print(f"Error processing frame: {e}") + return None + raise ValueError("No valid frame found in the stream.") + +def generate_random_numbers(frame, bit_lengths=[16, 32, 64, 128, 256]): + img_bytes = frame.resize((100, 100)).tobytes() + entropy = hashlib.sha256(img_bytes).digest() + # Use secrets.randbits directly + return {length: secrets.randbits(length) for length in bit_lengths} + +url = "http://192.168.0.200/mjpg/video.mjpg" +try: + frame = fetch_single_frame(url) + if frame: + random_numbers = generate_random_numbers(frame) + for length, number in random_numbers.items(): + print(f"{length}-bit random number: {hex(number)}") + else: + print("Failed to extract a valid frame.") +except Exception as e: + print(f"Error: {e}") diff --git a/entropy-rng-opencv.py b/entropy-rng-opencv.py new file mode 100644 index 0000000..139bc1c --- /dev/null +++ b/entropy-rng-opencv.py @@ -0,0 +1,27 @@ +import cv2 +import hashlib +import secrets + +def fetch_frame_opencv(url): + cap = cv2.VideoCapture(url) + ret, frame = cap.read() + cap.release() + if not ret: + raise ValueError("Failed to fetch frame.") + return frame + +def generate_random_numbers(frame, bit_lengths=[16, 32, 64, 128, 256]): + _, img_encoded = cv2.imencode('.jpg', frame) + img_bytes = img_encoded.tobytes() + entropy = hashlib.sha256(img_bytes).digest() + # Use secrets.randbits directly + return {length: secrets.randbits(length) for length in bit_lengths} + +url = "http://192.168.0.200/mjpg/video.mjpg" +try: + frame = fetch_frame_opencv(url) + random_numbers = generate_random_numbers(frame) + for length, number in random_numbers.items(): + print(f"{length}-bit random number: {hex(number)}") +except Exception as e: + print(f"Error: {e}")