1229 lines
29 KiB
Markdown
1229 lines
29 KiB
Markdown
# Stegasoo REST API Documentation (v3.2.0)
|
||
|
||
Complete REST API reference for Stegasoo steganography operations.
|
||
|
||
## Table of Contents
|
||
|
||
- [Overview](#overview)
|
||
- [What's New in v3.2.0](#whats-new-in-v320)
|
||
- [Installation](#installation)
|
||
- [Authentication](#authentication)
|
||
- [Base URL](#base-url)
|
||
- [Endpoints](#endpoints)
|
||
- [GET /](#get--status)
|
||
- [GET /modes](#get-modes)
|
||
- [POST /generate](#post-generate)
|
||
- [POST /encode](#post-encode-json)
|
||
- [POST /encode/file](#post-encodefile)
|
||
- [POST /encode/multipart](#post-encodemultipart)
|
||
- [POST /decode](#post-decode-json)
|
||
- [POST /decode/multipart](#post-decodemultipart)
|
||
- [POST /compare](#post-compare)
|
||
- [POST /will-fit](#post-will-fit)
|
||
- [POST /image/info](#post-imageinfo)
|
||
- [POST /extract-key-from-qr](#post-extract-key-from-qr)
|
||
- [Embedding Modes](#embedding-modes)
|
||
- [Data Models](#data-models)
|
||
- [Error Handling](#error-handling)
|
||
- [Code Examples](#code-examples)
|
||
- [Rate Limiting](#rate-limiting)
|
||
- [Security Considerations](#security-considerations)
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
The Stegasoo REST API provides programmatic access to all steganography operations:
|
||
|
||
- **Generate** credentials (passphrase, PINs, RSA keys)
|
||
- **Encode** messages or files into images (LSB or DCT mode)
|
||
- **Decode** messages or files from images (auto-detects mode)
|
||
- **Analyze** image capacity and compare modes
|
||
|
||
The API supports both JSON (base64-encoded images) and multipart form data (direct file uploads).
|
||
|
||
---
|
||
|
||
## What's New in v3.2.0
|
||
|
||
Version 3.2.0 introduces breaking changes to simplify the API:
|
||
|
||
| Change | Before (v3.1) | After (v3.2.0) |
|
||
|--------|---------------|----------------|
|
||
| Passphrase | Daily rotation (`phrases` dict) | Single `passphrase` string |
|
||
| Date parameter | `date_str` required/optional | Removed entirely |
|
||
| Field name | `day_phrase` | `passphrase` |
|
||
| Default words | 3 words | 4 words |
|
||
|
||
**Key benefits:**
|
||
- ✅ No need to track encoding dates
|
||
- ✅ Simpler request/response models
|
||
- ✅ True asynchronous communications
|
||
- ✅ Stronger default security (4 words = ~44 bits)
|
||
|
||
**Breaking Change:** v3.2.0 cannot decode images created with v3.1.x due to different key derivation.
|
||
|
||
---
|
||
|
||
## Installation
|
||
|
||
### From PyPI
|
||
|
||
```bash
|
||
pip install stegasoo[api]
|
||
```
|
||
|
||
This automatically installs DCT dependencies (scipy) for full functionality.
|
||
|
||
### From Source
|
||
|
||
```bash
|
||
git clone https://github.com/example/stegasoo.git
|
||
cd stegasoo
|
||
pip install -e ".[api]"
|
||
```
|
||
|
||
### Running the Server
|
||
|
||
**Development:**
|
||
```bash
|
||
cd frontends/api
|
||
python main.py
|
||
```
|
||
|
||
**Production:**
|
||
```bash
|
||
cd frontends/api
|
||
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
|
||
```
|
||
|
||
**Docker:**
|
||
```bash
|
||
docker-compose up api
|
||
```
|
||
|
||
---
|
||
|
||
## Authentication
|
||
|
||
The API currently operates without authentication. For production deployments, implement authentication at the reverse proxy level (nginx, Caddy) or add API key middleware.
|
||
|
||
---
|
||
|
||
## Base URL
|
||
|
||
| Environment | URL |
|
||
|-------------|-----|
|
||
| Local Development | `http://localhost:8000` |
|
||
| Docker | `http://localhost:8000` |
|
||
| Production | Configure as needed |
|
||
|
||
---
|
||
|
||
## Endpoints
|
||
|
||
### GET / (Status)
|
||
|
||
Check API status and configuration.
|
||
|
||
#### Request
|
||
|
||
```http
|
||
GET / HTTP/1.1
|
||
Host: localhost:8000
|
||
```
|
||
|
||
#### Response
|
||
|
||
```json
|
||
{
|
||
"version": "3.2.0",
|
||
"has_argon2": true,
|
||
"has_qrcode_read": true,
|
||
"has_dct": true,
|
||
"max_payload_kb": 500,
|
||
"available_modes": ["lsb", "dct"],
|
||
"dct_features": {
|
||
"output_formats": ["png", "jpeg"],
|
||
"color_modes": ["grayscale", "color"],
|
||
"default_output_format": "png",
|
||
"default_color_mode": "grayscale"
|
||
},
|
||
"breaking_changes": {
|
||
"date_removed": "No date_str parameter needed - encode/decode anytime",
|
||
"passphrase_renamed": "day_phrase → passphrase (single passphrase, no daily rotation)",
|
||
"format_version": 4,
|
||
"backward_compatible": false
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Response Fields
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `version` | string | Stegasoo library version |
|
||
| `has_argon2` | boolean | Whether Argon2id is available |
|
||
| `has_qrcode_read` | boolean | Whether QR code reading is available |
|
||
| `has_dct` | boolean | Whether DCT mode is available (scipy) |
|
||
| `max_payload_kb` | integer | Maximum payload size in KB |
|
||
| `available_modes` | array | Available embedding modes |
|
||
| `dct_features` | object | DCT mode options (if available) |
|
||
| `breaking_changes` | object | v3.2.0 breaking changes info |
|
||
|
||
#### cURL Example
|
||
|
||
```bash
|
||
curl http://localhost:8000/
|
||
```
|
||
|
||
---
|
||
|
||
### GET /modes
|
||
|
||
Get available embedding modes and their status.
|
||
|
||
#### Request
|
||
|
||
```http
|
||
GET /modes HTTP/1.1
|
||
Host: localhost:8000
|
||
```
|
||
|
||
#### Response
|
||
|
||
```json
|
||
{
|
||
"lsb": {
|
||
"available": true,
|
||
"name": "Spatial LSB",
|
||
"description": "Embed in pixel LSBs, outputs PNG/BMP",
|
||
"output_format": "PNG (color)",
|
||
"capacity_ratio": "100%"
|
||
},
|
||
"dct": {
|
||
"available": true,
|
||
"name": "DCT Domain",
|
||
"description": "Embed in DCT coefficients, frequency domain steganography",
|
||
"output_formats": ["png", "jpeg"],
|
||
"color_modes": ["grayscale", "color"],
|
||
"capacity_ratio": "~20% of LSB",
|
||
"requires": "scipy"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### POST /generate
|
||
|
||
Generate credentials for encoding/decoding.
|
||
|
||
#### Request
|
||
|
||
```http
|
||
POST /generate HTTP/1.1
|
||
Host: localhost:8000
|
||
Content-Type: application/json
|
||
|
||
```
|
||
|
||
#### Request Body
|
||
|
||
| Field | Type | Default | Description |
|
||
|-------|------|---------|-------------|
|
||
| `use_pin` | boolean | `true` | Generate a PIN |
|
||
| `use_rsa` | boolean | `false` | Generate an RSA key |
|
||
| `pin_length` | integer | `6` | PIN length (6-9) |
|
||
| `rsa_bits` | integer | `2048` | RSA key size (2048, 3072, 4096) |
|
||
| `words_per_passphrase` | integer | `4` | Words per passphrase (3-12) |
|
||
|
||
#### Response
|
||
|
||
```json
|
||
{
|
||
"passphrase": "abandon ability able about",
|
||
"pin": "847293",
|
||
"rsa_key_pem": null,
|
||
"entropy": {
|
||
"passphrase": 44,
|
||
"pin": 19,
|
||
"rsa": 0,
|
||
"total": 63
|
||
},
|
||
"phrases": null
|
||
}
|
||
```
|
||
|
||
#### Response Fields
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `passphrase` | string | Single passphrase (v3.2.0) |
|
||
| `pin` | string\|null | Generated PIN (if requested) |
|
||
| `rsa_key_pem` | string\|null | PEM-encoded RSA key (if requested) |
|
||
| `entropy.passphrase` | integer | Entropy from passphrase (bits) |
|
||
| `entropy.pin` | integer | Entropy from PIN (bits) |
|
||
| `entropy.rsa` | integer | Entropy from RSA key (bits) |
|
||
| `entropy.total` | integer | Combined entropy (bits) |
|
||
| `phrases` | null | Deprecated field (always null in v3.2.0) |
|
||
|
||
#### cURL Examples
|
||
|
||
**Default (PIN with 4-word passphrase):**
|
||
```bash
|
||
curl -X POST http://localhost:8000/generate \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"use_pin": true}'
|
||
```
|
||
|
||
**RSA only with 6-word passphrase:**
|
||
```bash
|
||
curl -X POST http://localhost:8000/generate \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"use_pin": false, "use_rsa": true, "rsa_bits": 4096, "words_per_passphrase": 6}'
|
||
```
|
||
|
||
**Both PIN and RSA:**
|
||
```bash
|
||
curl -X POST http://localhost:8000/generate \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"use_pin": true,
|
||
"use_rsa": true,
|
||
"pin_length": 9,
|
||
"rsa_bits": 4096,
|
||
"words_per_passphrase": 6
|
||
}'
|
||
```
|
||
|
||
---
|
||
|
||
### POST /encode (JSON)
|
||
|
||
Encode a text message using base64-encoded images.
|
||
|
||
#### Request
|
||
|
||
```http
|
||
POST /encode HTTP/1.1
|
||
Host: localhost:8000
|
||
Content-Type: application/json
|
||
|
||
```
|
||
|
||
#### Request Body
|
||
|
||
| Field | Type | Required | Default | Description |
|
||
|-------|------|----------|---------|-------------|
|
||
| `message` | string | ✓ | | Message to encode |
|
||
| `reference_photo_base64` | string | ✓ | | Base64-encoded reference photo |
|
||
| `carrier_image_base64` | string | ✓ | | Base64-encoded carrier image |
|
||
| `passphrase` | string | ✓ | | Passphrase (v3.2.0) |
|
||
| `pin` | string | * | | Static PIN (6-9 digits) |
|
||
| `rsa_key_base64` | string | * | | Base64-encoded RSA key PEM |
|
||
| `rsa_password` | string | | | Password for RSA key |
|
||
| `embed_mode` | string | | `"lsb"` | `"lsb"` or `"dct"` |
|
||
| `dct_output_format` | string | | `"png"` | `"png"` or `"jpeg"` (DCT only) |
|
||
| `dct_color_mode` | string | | `"grayscale"` | `"grayscale"` or `"color"` (DCT only) |
|
||
|
||
\* At least one of `pin` or `rsa_key_base64` required.
|
||
|
||
#### Response
|
||
|
||
```json
|
||
{
|
||
"stego_image_base64": "iVBORw0KGgo...",
|
||
"filename": "a1b2c3d4.png",
|
||
"capacity_used_percent": 12.4,
|
||
"embed_mode": "lsb",
|
||
"output_format": "png",
|
||
"color_mode": "color",
|
||
"date_used": null,
|
||
"day_of_week": null
|
||
}
|
||
```
|
||
|
||
#### Response Fields
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `stego_image_base64` | string | Base64-encoded stego image |
|
||
| `filename` | string | Suggested filename |
|
||
| `capacity_used_percent` | float | Percentage of capacity used |
|
||
| `embed_mode` | string | Mode used: `"lsb"` or `"dct"` |
|
||
| `output_format` | string | Output format: `"png"` or `"jpeg"` |
|
||
| `color_mode` | string | Color mode: `"color"` or `"grayscale"` |
|
||
| `date_used` | null | Deprecated (always null in v3.2.0) |
|
||
| `day_of_week` | null | Deprecated (always null in v3.2.0) |
|
||
|
||
#### cURL Example (LSB Mode)
|
||
|
||
```bash
|
||
# Prepare base64-encoded images
|
||
REF_B64=$(base64 -w0 reference.jpg)
|
||
CARRIER_B64=$(base64 -w0 carrier.png)
|
||
|
||
curl -X POST http://localhost:8000/encode \
|
||
-H "Content-Type: application/json" \
|
||
-d "{
|
||
\"message\": \"Secret message\",
|
||
\"reference_photo_base64\": \"$REF_B64\",
|
||
\"carrier_image_base64\": \"$CARRIER_B64\",
|
||
\"passphrase\": \"apple forest thunder mountain\",
|
||
\"pin\": \"123456\"
|
||
}" | jq -r '.stego_image_base64' | base64 -d > stego.png
|
||
```
|
||
|
||
#### cURL Example (DCT Mode with JPEG)
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/encode \
|
||
-H "Content-Type: application/json" \
|
||
-d "{
|
||
\"message\": \"Secret message\",
|
||
\"reference_photo_base64\": \"$REF_B64\",
|
||
\"carrier_image_base64\": \"$CARRIER_B64\",
|
||
\"passphrase\": \"apple forest thunder mountain\",
|
||
\"pin\": \"123456\",
|
||
\"embed_mode\": \"dct\",
|
||
\"dct_output_format\": \"jpeg\",
|
||
\"dct_color_mode\": \"color\"
|
||
}" | jq -r '.stego_image_base64' | base64 -d > stego.jpg
|
||
```
|
||
|
||
---
|
||
|
||
### POST /encode/file
|
||
|
||
Encode a binary file using base64-encoded data.
|
||
|
||
#### Request
|
||
|
||
```http
|
||
POST /encode/file HTTP/1.1
|
||
Host: localhost:8000
|
||
Content-Type: application/json
|
||
|
||
```
|
||
|
||
#### Request Body
|
||
|
||
| Field | Type | Required | Description |
|
||
|-------|------|----------|-------------|
|
||
| `file_data_base64` | string | ✓ | Base64-encoded file data |
|
||
| `filename` | string | ✓ | Original filename |
|
||
| `mime_type` | string | | MIME type of file |
|
||
| `reference_photo_base64` | string | ✓ | Base64-encoded reference photo |
|
||
| `carrier_image_base64` | string | ✓ | Base64-encoded carrier image |
|
||
| `passphrase` | string | ✓ | Passphrase |
|
||
| `pin` | string | * | Static PIN |
|
||
| `rsa_key_base64` | string | * | Base64-encoded RSA key |
|
||
| `embed_mode` | string | | `"lsb"` or `"dct"` |
|
||
| `dct_output_format` | string | | `"png"` or `"jpeg"` |
|
||
| `dct_color_mode` | string | | `"grayscale"` or `"color"` |
|
||
|
||
#### Response
|
||
|
||
Same as `/encode` endpoint.
|
||
|
||
---
|
||
|
||
### POST /encode/multipart
|
||
|
||
Encode using direct file uploads. Returns the stego image directly.
|
||
|
||
#### Form Fields
|
||
|
||
| Field | Type | Required | Default | Description |
|
||
|-------|------|----------|---------|-------------|
|
||
| `passphrase` | string | ✓ | | Passphrase (v3.2.0) |
|
||
| `reference_photo` | file | ✓ | | Reference photo file |
|
||
| `carrier` | file | ✓ | | Carrier image file |
|
||
| `message` | string | * | | Text message to encode |
|
||
| `payload_file` | file | * | | Binary file to embed |
|
||
| `pin` | string | ** | | Static PIN |
|
||
| `rsa_key` | file | ** | | RSA key file (.pem) |
|
||
| `rsa_key_qr` | file | ** | | RSA key from QR code image |
|
||
| `rsa_password` | string | | | Password for RSA key |
|
||
| `embed_mode` | string | | `"lsb"` | `"lsb"` or `"dct"` |
|
||
| `dct_output_format` | string | | `"png"` | `"png"` or `"jpeg"` |
|
||
| `dct_color_mode` | string | | `"grayscale"` | `"grayscale"` or `"color"` |
|
||
|
||
\* At least one of `message` or `payload_file` required.
|
||
\*\* At least one of `pin`, `rsa_key`, or `rsa_key_qr` required.
|
||
|
||
#### Response
|
||
|
||
Returns the image directly with headers:
|
||
|
||
```http
|
||
HTTP/1.1 200 OK
|
||
Content-Type: image/png
|
||
Content-Disposition: attachment; filename="a1b2c3d4.png"
|
||
X-Stegasoo-Capacity-Percent: 12.4
|
||
X-Stegasoo-Embed-Mode: lsb
|
||
X-Stegasoo-Output-Format: png
|
||
X-Stegasoo-Color-Mode: color
|
||
X-Stegasoo-Version: 3.2.0
|
||
|
||
<binary image data>
|
||
```
|
||
|
||
#### Response Headers
|
||
|
||
| Header | Description |
|
||
|--------|-------------|
|
||
| `Content-Type` | `image/png` or `image/jpeg` |
|
||
| `Content-Disposition` | Suggested filename |
|
||
| `X-Stegasoo-Capacity-Percent` | Capacity percentage used |
|
||
| `X-Stegasoo-Embed-Mode` | `lsb` or `dct` |
|
||
| `X-Stegasoo-Output-Format` | `png` or `jpeg` |
|
||
| `X-Stegasoo-Color-Mode` | `color` or `grayscale` |
|
||
| `X-Stegasoo-Version` | API version |
|
||
|
||
#### cURL Example (LSB)
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/encode/multipart \
|
||
-F "passphrase=apple forest thunder mountain" \
|
||
-F "pin=123456" \
|
||
-F "message=Secret message" \
|
||
-F "reference_photo=@reference.jpg" \
|
||
-F "carrier=@carrier.png" \
|
||
--output stego.png
|
||
```
|
||
|
||
#### cURL Example (DCT + JPEG)
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/encode/multipart \
|
||
-F "passphrase=apple forest thunder mountain" \
|
||
-F "pin=123456" \
|
||
-F "message=Secret message for social media" \
|
||
-F "embed_mode=dct" \
|
||
-F "dct_output_format=jpeg" \
|
||
-F "dct_color_mode=color" \
|
||
-F "reference_photo=@reference.jpg" \
|
||
-F "carrier=@carrier.png" \
|
||
--output stego.jpg
|
||
```
|
||
|
||
#### cURL Example (Embed File)
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/encode/multipart \
|
||
-F "passphrase=apple forest thunder mountain" \
|
||
-F "pin=123456" \
|
||
-F "payload_file=@secret.pdf" \
|
||
-F "reference_photo=@reference.jpg" \
|
||
-F "carrier=@carrier.png" \
|
||
--output stego.png
|
||
```
|
||
|
||
---
|
||
|
||
### POST /decode (JSON)
|
||
|
||
Decode a message or file using base64-encoded images. Auto-detects embedding mode.
|
||
|
||
#### Request
|
||
|
||
```http
|
||
POST /decode HTTP/1.1
|
||
Host: localhost:8000
|
||
Content-Type: application/json
|
||
|
||
```
|
||
|
||
#### Request Body
|
||
|
||
| Field | Type | Required | Default | Description |
|
||
|-------|------|----------|---------|-------------|
|
||
| `stego_image_base64` | string | ✓ | | Base64-encoded stego image |
|
||
| `reference_photo_base64` | string | ✓ | | Base64-encoded reference photo |
|
||
| `passphrase` | string | ✓ | | Passphrase |
|
||
| `pin` | string | * | | Static PIN |
|
||
| `rsa_key_base64` | string | * | | Base64-encoded RSA key |
|
||
| `rsa_password` | string | | | Password for RSA key |
|
||
| `embed_mode` | string | | `"auto"` | `"auto"`, `"lsb"`, or `"dct"` |
|
||
|
||
\* Must match security factors used during encoding.
|
||
|
||
#### Response (Text)
|
||
|
||
```json
|
||
{
|
||
"payload_type": "text",
|
||
"message": "Secret message here",
|
||
"file_data_base64": null,
|
||
"filename": null,
|
||
"mime_type": null
|
||
}
|
||
```
|
||
|
||
#### Response (File)
|
||
|
||
```json
|
||
{
|
||
"payload_type": "file",
|
||
"message": null,
|
||
"file_data_base64": "JVBERi0xLjQK...",
|
||
"filename": "secret.pdf",
|
||
"mime_type": "application/pdf"
|
||
}
|
||
```
|
||
|
||
#### Response Fields
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `payload_type` | string | `"text"` or `"file"` |
|
||
| `message` | string\|null | Decoded message (if text) |
|
||
| `file_data_base64` | string\|null | Base64-encoded file (if file) |
|
||
| `filename` | string\|null | Original filename (if file) |
|
||
| `mime_type` | string\|null | MIME type (if file) |
|
||
|
||
#### cURL Example
|
||
|
||
```bash
|
||
STEGO_B64=$(base64 -w0 stego.png)
|
||
REF_B64=$(base64 -w0 reference.jpg)
|
||
|
||
curl -X POST http://localhost:8000/decode \
|
||
-H "Content-Type: application/json" \
|
||
-d "{
|
||
\"stego_image_base64\": \"$STEGO_B64\",
|
||
\"reference_photo_base64\": \"$REF_B64\",
|
||
\"passphrase\": \"apple forest thunder mountain\",
|
||
\"pin\": \"123456\"
|
||
}"
|
||
```
|
||
|
||
---
|
||
|
||
### POST /decode/multipart
|
||
|
||
Decode using direct file uploads. Auto-detects embedding mode.
|
||
|
||
#### Form Fields
|
||
|
||
| Field | Type | Required | Description |
|
||
|-------|------|----------|-------------|
|
||
| `passphrase` | string | ✓ | Passphrase |
|
||
| `reference_photo` | file | ✓ | Reference photo file |
|
||
| `stego_image` | file | ✓ | Stego image file |
|
||
| `pin` | string | * | Static PIN |
|
||
| `rsa_key` | file | * | RSA key file (.pem) |
|
||
| `rsa_key_qr` | file | * | RSA key from QR code image |
|
||
| `rsa_password` | string | | Password for RSA key |
|
||
| `embed_mode` | string | | `"auto"`, `"lsb"`, or `"dct"` |
|
||
|
||
#### Response
|
||
|
||
Same JSON format as `/decode` endpoint.
|
||
|
||
#### cURL Example
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/decode/multipart \
|
||
-F "passphrase=apple forest thunder mountain" \
|
||
-F "pin=123456" \
|
||
-F "reference_photo=@reference.jpg" \
|
||
-F "stego_image=@stego.png"
|
||
```
|
||
|
||
---
|
||
|
||
### POST /compare
|
||
|
||
Compare LSB and DCT embedding modes for a carrier image.
|
||
|
||
#### Request
|
||
|
||
```http
|
||
POST /compare HTTP/1.1
|
||
Host: localhost:8000
|
||
Content-Type: application/json
|
||
|
||
```
|
||
|
||
#### Request Body
|
||
|
||
| Field | Type | Required | Description |
|
||
|-------|------|----------|-------------|
|
||
| `carrier_image_base64` | string | ✓ | Base64-encoded carrier image |
|
||
| `payload_size` | integer | | Optional payload size to check |
|
||
|
||
#### Response
|
||
|
||
```json
|
||
{
|
||
"width": 1920,
|
||
"height": 1080,
|
||
"lsb": {
|
||
"capacity_bytes": 776970,
|
||
"capacity_kb": 758.8,
|
||
"available": true,
|
||
"output_format": "PNG"
|
||
},
|
||
"dct": {
|
||
"capacity_bytes": 64800,
|
||
"capacity_kb": 63.3,
|
||
"available": true,
|
||
"output_formats": ["png", "jpeg"],
|
||
"color_modes": ["grayscale", "color"],
|
||
"ratio_vs_lsb_percent": 8.3
|
||
},
|
||
"payload_check": {
|
||
"size_bytes": 50000,
|
||
"fits_lsb": true,
|
||
"fits_dct": true
|
||
},
|
||
"recommendation": "dct (payload fits, better stealth)"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### POST /will-fit
|
||
|
||
Check if a payload of given size will fit in a carrier image.
|
||
|
||
#### Request
|
||
|
||
```http
|
||
POST /will-fit HTTP/1.1
|
||
Host: localhost:8000
|
||
Content-Type: application/json
|
||
|
||
```
|
||
|
||
#### Response
|
||
|
||
```json
|
||
{
|
||
"fits": true,
|
||
"payload_size": 50000,
|
||
"capacity": 776970,
|
||
"usage_percent": 6.4,
|
||
"headroom": 726970,
|
||
"mode": "lsb"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### POST /image/info
|
||
|
||
Get image information and capacity.
|
||
|
||
#### Request (Multipart)
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/image/info \
|
||
-F "image=@carrier.png"
|
||
```
|
||
|
||
#### Response
|
||
|
||
```json
|
||
{
|
||
"width": 1920,
|
||
"height": 1080,
|
||
"pixels": 2073600,
|
||
"capacity_bytes": 776970,
|
||
"capacity_kb": 758,
|
||
"modes": {
|
||
"lsb": {
|
||
"capacity_bytes": 776970,
|
||
"capacity_kb": 758.8,
|
||
"available": true,
|
||
"output_format": "PNG"
|
||
},
|
||
"dct": {
|
||
"capacity_bytes": 64800,
|
||
"capacity_kb": 63.3,
|
||
"available": true,
|
||
"output_format": "PNG/JPEG (grayscale or color)"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### POST /extract-key-from-qr
|
||
|
||
Extract RSA key from a QR code image.
|
||
|
||
#### Request (Multipart)
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/extract-key-from-qr \
|
||
-F "qr_image=@keyqr.png"
|
||
```
|
||
|
||
#### Response
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"key_pem": "-----BEGIN PRIVATE KEY-----\n...",
|
||
"error": null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Embedding Modes
|
||
|
||
### LSB Mode (Default)
|
||
|
||
**Least Significant Bit** embedding modifies pixel values directly.
|
||
|
||
| Aspect | Details |
|
||
|--------|---------|
|
||
| **Parameter** | `"embed_mode": "lsb"` |
|
||
| **Capacity** | ~3 bits/pixel (~375 KB for 1920×1080) |
|
||
| **Output** | PNG only (lossless required) |
|
||
| **Resilience** | ❌ Destroyed by JPEG compression |
|
||
| **Best For** | Maximum capacity, controlled channels |
|
||
|
||
### DCT Mode
|
||
|
||
**Discrete Cosine Transform** embedding hides data in frequency coefficients.
|
||
|
||
| Aspect | Details |
|
||
|--------|---------|
|
||
| **Parameter** | `"embed_mode": "dct"` |
|
||
| **Capacity** | ~0.25 bits/pixel (~65 KB for 1920×1080) |
|
||
| **Output** | PNG or JPEG |
|
||
| **Resilience** | ✅ Better resistance to analysis |
|
||
| **Best For** | Stealth requirements |
|
||
|
||
### DCT Options
|
||
|
||
| Option | Values | Default | Description |
|
||
|--------|--------|---------|-------------|
|
||
| `dct_output_format` | `"png"`, `"jpeg"` | `"png"` | Output image format |
|
||
| `dct_color_mode` | `"grayscale"`, `"color"` | `"grayscale"` | Color processing mode |
|
||
|
||
### Capacity Comparison
|
||
|
||
| Mode | 1920×1080 Capacity |
|
||
|------|-------------------|
|
||
| LSB (PNG) | ~375 KB |
|
||
| DCT (PNG) | ~65 KB |
|
||
| DCT (JPEG) | ~50 KB |
|
||
|
||
---
|
||
|
||
## Data Models
|
||
|
||
### GenerateRequest
|
||
|
||
```json
|
||
{
|
||
"use_pin": true,
|
||
"use_rsa": false,
|
||
"pin_length": 6,
|
||
"rsa_bits": 2048,
|
||
"words_per_passphrase": 4
|
||
}
|
||
```
|
||
|
||
### GenerateResponse
|
||
|
||
```json
|
||
{
|
||
"passphrase": "word1 word2 word3 word4",
|
||
"pin": "123456",
|
||
"rsa_key_pem": null,
|
||
"entropy": {"passphrase": 44, "pin": 19, "rsa": 0, "total": 63},
|
||
"phrases": null
|
||
}
|
||
```
|
||
|
||
### EncodeRequest
|
||
|
||
```json
|
||
{
|
||
"message": "string",
|
||
"reference_photo_base64": "string",
|
||
"carrier_image_base64": "string",
|
||
"passphrase": "string",
|
||
"pin": "string",
|
||
"rsa_key_base64": "string",
|
||
"rsa_password": "string",
|
||
"embed_mode": "lsb",
|
||
"dct_output_format": "png",
|
||
"dct_color_mode": "grayscale"
|
||
}
|
||
```
|
||
|
||
### EncodeResponse
|
||
|
||
```json
|
||
{
|
||
"stego_image_base64": "string",
|
||
"filename": "string",
|
||
"capacity_used_percent": 12.4,
|
||
"embed_mode": "lsb",
|
||
"output_format": "png",
|
||
"color_mode": "color",
|
||
"date_used": null,
|
||
"day_of_week": null
|
||
}
|
||
```
|
||
|
||
### DecodeRequest
|
||
|
||
```json
|
||
{
|
||
"stego_image_base64": "string",
|
||
"reference_photo_base64": "string",
|
||
"passphrase": "string",
|
||
"pin": "string",
|
||
"rsa_key_base64": "string",
|
||
"rsa_password": "string",
|
||
"embed_mode": "auto"
|
||
}
|
||
```
|
||
|
||
### DecodeResponse
|
||
|
||
```json
|
||
{
|
||
"payload_type": "text",
|
||
"message": "string",
|
||
"file_data_base64": null,
|
||
"filename": null,
|
||
"mime_type": null
|
||
}
|
||
```
|
||
|
||
### ErrorResponse
|
||
|
||
```json
|
||
{
|
||
"detail": "Error message describing the problem"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Error Handling
|
||
|
||
### HTTP Status Codes
|
||
|
||
| Code | Meaning | Use Case |
|
||
|------|---------|----------|
|
||
| 200 | OK | Successful operation |
|
||
| 400 | Bad Request | Invalid input, capacity error |
|
||
| 401 | Unauthorized | Decryption failed (wrong credentials) |
|
||
| 500 | Internal Error | Unexpected server error |
|
||
| 501 | Not Implemented | Feature unavailable (e.g., QR without pyzbar) |
|
||
|
||
### Common Errors
|
||
|
||
| Status | Error | Solution |
|
||
|--------|-------|----------|
|
||
| 400 | "Must enable at least one of use_pin or use_rsa" | Set `use_pin` or `use_rsa` to true |
|
||
| 400 | "Carrier image too small" | Use larger carrier image |
|
||
| 400 | "DCT mode requires scipy" | Install scipy |
|
||
| 400 | "embed_mode must be 'lsb' or 'dct'" | Fix embed_mode value |
|
||
| 401 | "Decryption failed. Check credentials." | Verify passphrase, PIN, ref photo |
|
||
| 501 | "QR code reading not available" | Install pyzbar and libzbar |
|
||
|
||
---
|
||
|
||
## Code Examples
|
||
|
||
### Python with requests
|
||
|
||
```python
|
||
import base64
|
||
import requests
|
||
|
||
BASE_URL = "http://localhost:8000"
|
||
|
||
# Generate credentials
|
||
response = requests.post(f"{BASE_URL}/generate", json={
|
||
"use_pin": True,
|
||
"words_per_passphrase": 4
|
||
})
|
||
creds = response.json()
|
||
print(f"Passphrase: {creds['passphrase']}")
|
||
print(f"PIN: {creds['pin']}")
|
||
|
||
# Encode using multipart (LSB mode)
|
||
with open("reference.jpg", "rb") as ref, open("carrier.png", "rb") as carrier:
|
||
response = requests.post(f"{BASE_URL}/encode/multipart", files={
|
||
"reference_photo": ref,
|
||
"carrier": carrier,
|
||
}, data={
|
||
"message": "Secret message",
|
||
"passphrase": "apple forest thunder mountain",
|
||
"pin": "123456"
|
||
})
|
||
|
||
with open("stego.png", "wb") as f:
|
||
f.write(response.content)
|
||
|
||
# Encode with DCT for social media
|
||
with open("reference.jpg", "rb") as ref, open("carrier.png", "rb") as carrier:
|
||
response = requests.post(f"{BASE_URL}/encode/multipart", files={
|
||
"reference_photo": ref,
|
||
"carrier": carrier,
|
||
}, data={
|
||
"message": "Secret message for Instagram",
|
||
"passphrase": "apple forest thunder mountain",
|
||
"pin": "123456",
|
||
"embed_mode": "dct",
|
||
"dct_output_format": "jpeg",
|
||
"dct_color_mode": "color"
|
||
})
|
||
|
||
with open("stego_social.jpg", "wb") as f:
|
||
f.write(response.content)
|
||
|
||
# Decode (auto-detects mode)
|
||
with open("reference.jpg", "rb") as ref, open("stego.png", "rb") as stego:
|
||
response = requests.post(f"{BASE_URL}/decode/multipart", files={
|
||
"reference_photo": ref,
|
||
"stego_image": stego,
|
||
}, data={
|
||
"passphrase": "apple forest thunder mountain",
|
||
"pin": "123456"
|
||
})
|
||
|
||
result = response.json()
|
||
if result['payload_type'] == 'text':
|
||
print(f"Decoded: {result['message']}")
|
||
else:
|
||
# Save decoded file
|
||
file_data = base64.b64decode(result['file_data_base64'])
|
||
with open(result['filename'], 'wb') as f:
|
||
f.write(file_data)
|
||
```
|
||
|
||
### JavaScript/Node.js
|
||
|
||
```javascript
|
||
const FormData = require('form-data');
|
||
const fs = require('fs');
|
||
const axios = require('axios');
|
||
|
||
const BASE_URL = 'http://localhost:8000';
|
||
|
||
async function generate() {
|
||
const response = await axios.post(`${BASE_URL}/generate`, {
|
||
use_pin: true,
|
||
words_per_passphrase: 4
|
||
});
|
||
|
||
console.log('Passphrase:', response.data.passphrase);
|
||
console.log('PIN:', response.data.pin);
|
||
return response.data;
|
||
}
|
||
|
||
async function encode(passphrase, pin) {
|
||
const form = new FormData();
|
||
form.append('passphrase', passphrase);
|
||
form.append('pin', pin);
|
||
form.append('message', 'Secret message');
|
||
form.append('reference_photo', fs.createReadStream('reference.jpg'));
|
||
form.append('carrier', fs.createReadStream('carrier.png'));
|
||
|
||
const response = await axios.post(`${BASE_URL}/encode/multipart`, form, {
|
||
headers: form.getHeaders(),
|
||
responseType: 'arraybuffer'
|
||
});
|
||
|
||
fs.writeFileSync('stego.png', response.data);
|
||
console.log('Encoded to stego.png');
|
||
}
|
||
|
||
async function decode(passphrase, pin) {
|
||
const form = new FormData();
|
||
form.append('passphrase', passphrase);
|
||
form.append('pin', pin);
|
||
form.append('reference_photo', fs.createReadStream('reference.jpg'));
|
||
form.append('stego_image', fs.createReadStream('stego.png'));
|
||
|
||
const response = await axios.post(`${BASE_URL}/decode/multipart`, form, {
|
||
headers: form.getHeaders()
|
||
});
|
||
|
||
console.log('Decoded:', response.data.message);
|
||
}
|
||
|
||
// Usage
|
||
generate()
|
||
.then(creds => encode(creds.passphrase, creds.pin))
|
||
.then(() => decode('apple forest thunder mountain', '123456'));
|
||
```
|
||
|
||
### Shell Script (Bash)
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
BASE_URL="http://localhost:8000"
|
||
PASSPHRASE="apple forest thunder mountain"
|
||
PIN="123456"
|
||
|
||
# Generate credentials
|
||
echo "Generating credentials..."
|
||
CREDS=$(curl -s -X POST "$BASE_URL/generate" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"use_pin": true, "words_per_passphrase": 4}')
|
||
|
||
echo "Passphrase: $(echo $CREDS | jq -r '.passphrase')"
|
||
echo "PIN: $(echo $CREDS | jq -r '.pin')"
|
||
|
||
# Encode
|
||
echo "Encoding..."
|
||
curl -s -X POST "$BASE_URL/encode/multipart" \
|
||
-F "passphrase=$PASSPHRASE" \
|
||
-F "pin=$PIN" \
|
||
-F "message=Secret message" \
|
||
-F "reference_photo=@reference.jpg" \
|
||
-F "carrier=@carrier.png" \
|
||
--output stego.png
|
||
|
||
echo "Encoded to stego.png"
|
||
|
||
# Decode
|
||
echo "Decoding..."
|
||
RESULT=$(curl -s -X POST "$BASE_URL/decode/multipart" \
|
||
-F "passphrase=$PASSPHRASE" \
|
||
-F "pin=$PIN" \
|
||
-F "reference_photo=@reference.jpg" \
|
||
-F "stego_image=@stego.png")
|
||
|
||
echo "Decoded: $(echo $RESULT | jq -r '.message')"
|
||
```
|
||
|
||
---
|
||
|
||
## Rate Limiting
|
||
|
||
The API does not implement rate limiting by default. For production:
|
||
|
||
1. **Reverse Proxy**: Use nginx or Caddy rate limiting
|
||
2. **Application Level**: Add FastAPI middleware
|
||
|
||
Example nginx rate limiting:
|
||
```nginx
|
||
limit_req_zone $binary_remote_addr zone=stegasoo:10m rate=10r/s;
|
||
|
||
location /api/ {
|
||
limit_req zone=stegasoo burst=20 nodelay;
|
||
proxy_pass http://localhost:8000/;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Security Considerations
|
||
|
||
### In Transit
|
||
|
||
- Use HTTPS in production
|
||
- Configure TLS at reverse proxy level
|
||
|
||
### Memory Usage
|
||
|
||
- Argon2id requires 256MB RAM per operation
|
||
- DCT mode adds ~100MB for scipy operations
|
||
- Concurrent requests can exhaust memory
|
||
- Limit workers based on available RAM
|
||
|
||
**Worker calculation:**
|
||
```
|
||
workers = (available_RAM - 512MB) / 350MB
|
||
```
|
||
|
||
### Input Validation
|
||
|
||
The API validates:
|
||
- PIN format (6-9 digits, no leading zero)
|
||
- Passphrase presence
|
||
- Image size limits
|
||
- RSA key validity
|
||
- Embedding mode values
|
||
- Output format compatibility
|
||
|
||
### Credential Handling
|
||
|
||
- Credentials are never logged
|
||
- No persistent storage of secrets
|
||
- Memory cleared after operations
|
||
|
||
---
|
||
|
||
## Interactive Documentation
|
||
|
||
When the API is running, visit:
|
||
|
||
- **Swagger UI**: http://localhost:8000/docs
|
||
- **ReDoc**: http://localhost:8000/redoc
|
||
|
||
---
|
||
|
||
## See Also
|
||
|
||
- [CLI Documentation](CLI.md) - Command-line interface
|
||
- [Web UI Documentation](WEB_UI.md) - Browser interface
|
||
- [API Update Summary](api/API_UPDATE_SUMMARY_V3.2.0.md) - Migration guide
|
||
- [README](../README.md) - Project overview
|