27 KiB
Stegasoo REST API Documentation
Complete REST API reference for Stegasoo steganography operations.
Table of Contents
- Overview
- Installation
- Authentication
- Base URL
- Endpoints
- Embedding Modes
- Data Models
- Error Handling
- Code Examples
- Rate Limiting
- Security Considerations
Overview
The Stegasoo REST API provides programmatic access to all steganography operations:
- Generate credentials (phrases, PINs, RSA keys)
- Encode messages into images (LSB or DCT mode)
- Decode messages from images (auto-detects mode)
- Analyze image capacity
The API supports both JSON (base64-encoded images) and multipart form data (direct file uploads).
What's New in v3.0.2
- DCT Steganography Mode - JPEG-resilient embedding
- Output Format Selection - PNG or JPEG output
- Color Mode Selection - Color or grayscale processing
- jpegio Integration - Proper JPEG coefficient manipulation
Installation
From PyPI
pip install stegasoo[api]
This automatically installs DCT dependencies (scipy, jpegio) for full functionality.
From Source
git clone https://github.com/example/stegasoo.git
cd stegasoo
pip install -e ".[api]"
Running the Server
Development:
cd frontends/api
python main.py
Production:
cd frontends/api
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
Docker:
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
GET / HTTP/1.1
Host: localhost:8000
Response
{
"version": "3.0.2",
"has_argon2": true,
"has_dct": true,
"has_jpegio": true,
"day_names": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
}
Response Fields
| Field | Type | Description |
|---|---|---|
version |
string | Stegasoo library version |
has_argon2 |
boolean | Whether Argon2id is available |
has_dct |
boolean | Whether DCT mode is available (scipy) |
has_jpegio |
boolean | Whether native JPEG DCT is available |
day_names |
array | Day names for phrase mapping |
cURL Example
curl http://localhost:8000/
POST /generate
Generate credentials for encoding/decoding.
Request
POST /generate HTTP/1.1
Host: localhost:8000
Content-Type: application/json
{
"use_pin": true,
"use_rsa": false,
"pin_length": 6,
"rsa_bits": 2048,
"words_per_phrase": 3
}
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_phrase |
integer | 3 |
Words per phrase (3-12) |
Response
{
"phrases": {
"Monday": "abandon ability able",
"Tuesday": "actor actress actual",
"Wednesday": "advice aerobic affair",
"Thursday": "afraid again age",
"Friday": "agree ahead aim",
"Saturday": "airport aisle alarm",
"Sunday": "album alcohol alert"
},
"pin": "847293",
"rsa_key_pem": null,
"entropy": {
"phrase": 33,
"pin": 19,
"rsa": 0,
"total": 52
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
phrases |
object | Day-to-phrase mapping |
pin |
string|null | Generated PIN (if requested) |
rsa_key_pem |
string|null | PEM-encoded RSA key (if requested) |
entropy.phrase |
integer | Entropy from phrases (bits) |
entropy.pin |
integer | Entropy from PIN (bits) |
entropy.rsa |
integer | Entropy from RSA key (bits) |
entropy.total |
integer | Combined entropy (bits) |
cURL Examples
PIN only:
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-d '{"use_pin": true, "use_rsa": false}'
RSA only:
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-d '{"use_pin": false, "use_rsa": true, "rsa_bits": 4096}'
Both with custom settings:
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_phrase": 6
}'
POST /encode (JSON)
Encode a message using base64-encoded images.
Request
POST /encode HTTP/1.1
Host: localhost:8000
Content-Type: application/json
{
"message": "Secret message here",
"reference_photo_base64": "iVBORw0KGgo...",
"carrier_image_base64": "iVBORw0KGgo...",
"day_phrase": "apple forest thunder",
"pin": "123456",
"rsa_key_base64": null,
"rsa_password": null,
"date_str": null,
"embedding_mode": "lsb",
"output_format": "png",
"color_mode": "color"
}
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 | |
day_phrase |
string | ✓ | Today's passphrase | |
pin |
string | * | Static PIN (6-9 digits) | |
rsa_key_base64 |
string | * | Base64-encoded RSA key PEM | |
rsa_password |
string | Password for RSA key | ||
date_str |
string | Date override (YYYY-MM-DD) | ||
embedding_mode |
string | "lsb" |
"lsb" or "dct" |
|
output_format |
string | "png" |
"png" or "jpeg" (DCT only) |
|
color_mode |
string | "color" |
"color" or "grayscale" (DCT only) |
* At least one of pin or rsa_key_base64 required.
Response
{
"stego_image_base64": "iVBORw0KGgo...",
"filename": "a1b2c3d4_20251227.png",
"capacity_used_percent": 12.4,
"date_used": "2025-12-27",
"day_of_week": "Saturday",
"embedding_mode": "lsb",
"output_format": "png",
"color_mode": 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 |
date_used |
string | Date embedded in image (YYYY-MM-DD) |
day_of_week |
string | Day name for passphrase rotation |
embedding_mode |
string | Mode used: "lsb" or "dct" |
output_format |
string | Output format: "png" or "jpeg" |
color_mode |
string|null | Color mode (DCT only): "color" or "grayscale" |
cURL Example (LSB Mode - Default)
# 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\",
\"day_phrase\": \"apple forest thunder\",
\"pin\": \"123456\"
}" | jq -r '.stego_image_base64' | base64 -d > stego.png
cURL Example (DCT Mode with JPEG Output)
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\",
\"day_phrase\": \"apple forest thunder\",
\"pin\": \"123456\",
\"embedding_mode\": \"dct\",
\"output_format\": \"jpeg\",
\"color_mode\": \"color\"
}" | jq -r '.stego_image_base64' | base64 -d > stego.jpg
POST /encode/multipart
Encode a message using direct file uploads. Returns the stego image directly.
Request
POST /encode/multipart HTTP/1.1
Host: localhost:8000
Content-Type: multipart/form-data; boundary=----FormBoundary
------FormBoundary
Content-Disposition: form-data; name="message"
Secret message here
------FormBoundary
Content-Disposition: form-data; name="day_phrase"
apple forest thunder
------FormBoundary
Content-Disposition: form-data; name="pin"
123456
------FormBoundary
Content-Disposition: form-data; name="embedding_mode"
dct
------FormBoundary
Content-Disposition: form-data; name="output_format"
jpeg
------FormBoundary
Content-Disposition: form-data; name="color_mode"
color
------FormBoundary
Content-Disposition: form-data; name="reference_photo"; filename="ref.jpg"
Content-Type: image/jpeg
<binary image data>
------FormBoundary
Content-Disposition: form-data; name="carrier"; filename="carrier.png"
Content-Type: image/png
<binary image data>
------FormBoundary--
Form Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
message |
string | ✓ | Message to encode | |
reference_photo |
file | ✓ | Reference photo file | |
carrier |
file | ✓ | Carrier image file | |
day_phrase |
string | ✓ | Today's passphrase | |
pin |
string | * | Static PIN | |
rsa_key |
file | * | RSA key file (.pem) | |
rsa_password |
string | Password for RSA key | ||
date_str |
string | Date override (YYYY-MM-DD) | ||
embedding_mode |
string | "lsb" |
"lsb" or "dct" |
|
output_format |
string | "png" |
"png" or "jpeg" (DCT only) |
|
color_mode |
string | "color" |
"color" or "grayscale" (DCT only) |
* At least one of pin or rsa_key required.
Response
Returns the image directly with headers:
HTTP/1.1 200 OK
Content-Type: image/png
Content-Disposition: attachment; filename="a1b2c3d4_20251227.png"
X-Stegasoo-Date: 2025-12-27
X-Stegasoo-Day: Saturday
X-Stegasoo-Capacity-Used: 12.4
X-Stegasoo-Embedding-Mode: lsb
X-Stegasoo-Output-Format: png
<binary image data>
Response Headers
| Header | Description |
|---|---|
Content-Type |
image/png or image/jpeg |
Content-Disposition |
Suggested filename |
X-Stegasoo-Date |
Encoding date |
X-Stegasoo-Day |
Day of week |
X-Stegasoo-Capacity-Used |
Capacity percentage |
X-Stegasoo-Embedding-Mode |
lsb or dct |
X-Stegasoo-Output-Format |
png or jpeg |
X-Stegasoo-Color-Mode |
color or grayscale (DCT only) |
cURL Example (DCT + JPEG)
curl -X POST http://localhost:8000/encode/multipart \
-F "message=Secret message for social media" \
-F "day_phrase=apple forest thunder" \
-F "pin=123456" \
-F "embedding_mode=dct" \
-F "output_format=jpeg" \
-F "color_mode=color" \
-F "reference_photo=@reference.jpg" \
-F "carrier=@carrier.png" \
--output stego.jpg
POST /decode (JSON)
Decode a message using base64-encoded images. Auto-detects embedding mode.
Request
POST /decode HTTP/1.1
Host: localhost:8000
Content-Type: application/json
{
"stego_image_base64": "iVBORw0KGgo...",
"reference_photo_base64": "iVBORw0KGgo...",
"day_phrase": "apple forest thunder",
"pin": "123456",
"rsa_key_base64": null,
"rsa_password": null
}
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
stego_image_base64 |
string | ✓ | Base64-encoded stego image |
reference_photo_base64 |
string | ✓ | Base64-encoded reference photo |
day_phrase |
string | ✓ | Passphrase for encoding day |
pin |
string | * | Static PIN |
rsa_key_base64 |
string | * | Base64-encoded RSA key |
rsa_password |
string | Password for RSA key |
* Must match security factors used during encoding.
Response
{
"message": "Secret message here",
"embedding_mode_detected": "dct"
}
Response Fields
| Field | Type | Description |
|---|---|---|
message |
string | Decoded message |
embedding_mode_detected |
string | Detected mode: "lsb" or "dct" |
cURL Example
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\",
\"day_phrase\": \"apple forest thunder\",
\"pin\": \"123456\"
}"
POST /decode/multipart
Decode using direct file uploads. Auto-detects embedding mode.
Form Fields
| Field | Type | Required | Description |
|---|---|---|---|
stego_image |
file | ✓ | Stego image file |
reference_photo |
file | ✓ | Reference photo file |
day_phrase |
string | ✓ | Passphrase for encoding day |
pin |
string | * | Static PIN |
rsa_key |
file | * | RSA key file (.pem) |
rsa_password |
string | Password for RSA key |
Response
{
"message": "Secret message here",
"embedding_mode_detected": "lsb"
}
cURL Example
curl -X POST http://localhost:8000/decode/multipart \
-F "day_phrase=apple forest thunder" \
-F "pin=123456" \
-F "reference_photo=@reference.jpg" \
-F "stego_image=@stego.png"
POST /image/info
Get image information and capacity for both LSB and DCT modes.
Request (JSON)
POST /image/info HTTP/1.1
Host: localhost:8000
Content-Type: application/json
{
"image_base64": "iVBORw0KGgo..."
}
Request (Multipart)
curl -X POST http://localhost:8000/image/info \
-F "image=@carrier.png"
Response
{
"width": 1920,
"height": 1080,
"pixels": 2073600,
"format": "PNG",
"mode": "RGB",
"capacity": {
"lsb": {
"bytes": 776970,
"kb": 758
},
"dct": {
"bytes": 64800,
"kb": 63,
"note": "Approximate - actual capacity depends on image content"
}
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
width |
integer | Image width in pixels |
height |
integer | Image height in pixels |
pixels |
integer | Total pixel count |
format |
string | Image format (PNG, JPEG, etc.) |
mode |
string | Color mode (RGB, L, etc.) |
capacity.lsb.bytes |
integer | LSB capacity in bytes |
capacity.lsb.kb |
integer | LSB capacity in KB |
capacity.dct.bytes |
integer | Estimated DCT capacity in bytes |
capacity.dct.kb |
integer | Estimated DCT capacity in KB |
capacity.dct.note |
string | Capacity estimation note |
Embedding Modes
LSB Mode (Default)
Least Significant Bit embedding modifies pixel values directly.
| Aspect | Details |
|---|---|
| Parameter | "embedding_mode": "lsb" |
| Capacity | ~3 bits/pixel (~770 KB for 1920×1080) |
| Output | PNG only (lossless required) |
| Resilience | ❌ Destroyed by JPEG compression |
| Best For | Maximum capacity, controlled channels |
DCT Mode (Experimental)
Discrete Cosine Transform embedding hides data in frequency coefficients.
| Aspect | Details |
|---|---|
| Parameter | "embedding_mode": "dct" |
| Capacity | ~0.25 bits/pixel (~65 KB for 1920×1080) |
| Output | PNG or JPEG |
| Resilience | ✅ Survives JPEG compression |
| Best For | Social media, messaging apps |
⚠️ Experimental: DCT mode may have edge cases. Test with your workflow.
DCT Options
| Option | Values | Default | Description |
|---|---|---|---|
output_format |
"png", "jpeg" |
"png" |
Output image format |
color_mode |
"color", "grayscale" |
"color" |
Color processing mode |
Capacity Comparison
| Mode | 1920×1080 Capacity |
|---|---|
| LSB (PNG) | ~770 KB |
| DCT (PNG) | ~65 KB |
| DCT (JPEG) | ~30-50 KB |
Data Models
GenerateRequest
{
"use_pin": true,
"use_rsa": false,
"pin_length": 6,
"rsa_bits": 2048,
"words_per_phrase": 3
}
GenerateResponse
{
"phrases": {"Monday": "...", "Tuesday": "...", ...},
"pin": "123456",
"rsa_key_pem": "-----BEGIN PRIVATE KEY-----...",
"entropy": {"phrase": 33, "pin": 19, "rsa": 0, "total": 52}
}
EncodeRequest
{
"message": "string",
"reference_photo_base64": "string",
"carrier_image_base64": "string",
"day_phrase": "string",
"pin": "string",
"rsa_key_base64": "string",
"rsa_password": "string",
"date_str": "YYYY-MM-DD",
"embedding_mode": "lsb",
"output_format": "png",
"color_mode": "color"
}
EncodeResponse
{
"stego_image_base64": "string",
"filename": "string",
"capacity_used_percent": 12.4,
"date_used": "YYYY-MM-DD",
"day_of_week": "Saturday",
"embedding_mode": "lsb",
"output_format": "png",
"color_mode": null
}
DecodeRequest
{
"stego_image_base64": "string",
"reference_photo_base64": "string",
"day_phrase": "string",
"pin": "string",
"rsa_key_base64": "string",
"rsa_password": "string"
}
DecodeResponse
{
"message": "string",
"embedding_mode_detected": "lsb"
}
ImageInfoResponse
{
"width": 1920,
"height": 1080,
"pixels": 2073600,
"format": "PNG",
"mode": "RGB",
"capacity": {
"lsb": {"bytes": 776970, "kb": 758},
"dct": {"bytes": 64800, "kb": 63, "note": "..."}
}
}
ErrorResponse
{
"error": "ErrorType",
"detail": "Error description"
}
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 |
Error Response Format
{
"detail": "Error message describing the problem"
}
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 | "rsa_bits must be one of [2048, 3072, 4096]" | Use valid RSA key size |
| 400 | "Carrier image too small" | Use larger carrier image |
| 400 | "PIN must be 6-9 digits" | Fix PIN format |
| 400 | "Invalid embedding_mode" | Use "lsb" or "dct" |
| 400 | "output_format 'jpeg' requires embedding_mode 'dct'" | Use DCT mode for JPEG |
| 400 | "Message too long for DCT capacity" | Reduce message or use LSB |
| 401 | "Decryption failed. Check credentials." | Verify phrase, PIN, ref photo |
| 401 | "Invalid or missing Stegasoo header" | Wrong mode or corrupted image |
Code Examples
Python with requests
import base64
import requests
BASE_URL = "http://localhost:8000"
# Generate credentials
response = requests.post(f"{BASE_URL}/generate", json={
"use_pin": True,
"use_rsa": False,
"words_per_phrase": 3
})
creds = response.json()
print(f"PIN: {creds['pin']}")
print(f"Monday phrase: {creds['phrases']['Monday']}")
# Encode using multipart (LSB mode - default)
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",
"day_phrase": "apple forest thunder",
"pin": "123456"
})
with open("stego.png", "wb") as f:
f.write(response.content)
# Encode using DCT mode 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",
"day_phrase": "apple forest thunder",
"pin": "123456",
"embedding_mode": "dct",
"output_format": "jpeg",
"color_mode": "color"
})
with open("stego_social.jpg", "wb") as f:
f.write(response.content)
# Decode using multipart (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={
"day_phrase": "apple forest thunder",
"pin": "123456"
})
result = response.json()
print(f"Decoded: {result['message']}")
print(f"Mode detected: {result['embedding_mode_detected']}")
JavaScript/Node.js
const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');
const BASE_URL = 'http://localhost:8000';
async function encodeDCT() {
const form = new FormData();
form.append('message', 'Secret message for social media');
form.append('day_phrase', 'apple forest thunder');
form.append('pin', '123456');
form.append('embedding_mode', 'dct');
form.append('output_format', 'jpeg');
form.append('color_mode', 'color');
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.jpg', response.data);
console.log('Encoded with DCT mode');
console.log('Embedding mode:', response.headers['x-stegasoo-embedding-mode']);
}
async function decode() {
const form = new FormData();
form.append('day_phrase', 'apple forest thunder');
form.append('pin', '123456');
form.append('reference_photo', fs.createReadStream('reference.jpg'));
form.append('stego_image', fs.createReadStream('stego.jpg'));
const response = await axios.post(`${BASE_URL}/decode/multipart`, form, {
headers: form.getHeaders()
});
console.log('Decoded:', response.data.message);
console.log('Mode detected:', response.data.embedding_mode_detected);
}
encodeDCT().then(decode);
Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
func main() {
// Encode with DCT mode
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
writer.WriteField("message", "Secret message")
writer.WriteField("day_phrase", "apple forest thunder")
writer.WriteField("pin", "123456")
writer.WriteField("embedding_mode", "dct")
writer.WriteField("output_format", "jpeg")
writer.WriteField("color_mode", "color")
ref, _ := os.Open("reference.jpg")
refPart, _ := writer.CreateFormFile("reference_photo", "reference.jpg")
io.Copy(refPart, ref)
ref.Close()
carrier, _ := os.Open("carrier.png")
carrierPart, _ := writer.CreateFormFile("carrier", "carrier.png")
io.Copy(carrierPart, carrier)
carrier.Close()
writer.Close()
resp, _ := http.Post(
"http://localhost:8000/encode/multipart",
writer.FormDataContentType(),
body,
)
// Check embedding mode from header
fmt.Println("Embedding mode:", resp.Header.Get("X-Stegasoo-Embedding-Mode"))
stego, _ := os.Create("stego.jpg")
io.Copy(stego, resp.Body)
stego.Close()
resp.Body.Close()
fmt.Println("Encoded successfully with DCT mode")
}
Shell Script (Bash)
#!/bin/bash
BASE_URL="http://localhost:8000"
REF_PHOTO="reference.jpg"
CARRIER="carrier.png"
PHRASE="apple forest thunder"
PIN="123456"
MESSAGE="Secret message"
# Encode with LSB (default)
echo "Encoding with LSB mode..."
curl -s -X POST "$BASE_URL/encode/multipart" \
-F "message=$MESSAGE" \
-F "day_phrase=$PHRASE" \
-F "pin=$PIN" \
-F "reference_photo=@$REF_PHOTO" \
-F "carrier=@$CARRIER" \
--output stego_lsb.png
echo "Encoded to stego_lsb.png"
# Encode with DCT for social media
echo "Encoding with DCT mode..."
curl -s -X POST "$BASE_URL/encode/multipart" \
-F "message=$MESSAGE" \
-F "day_phrase=$PHRASE" \
-F "pin=$PIN" \
-F "embedding_mode=dct" \
-F "output_format=jpeg" \
-F "color_mode=color" \
-F "reference_photo=@$REF_PHOTO" \
-F "carrier=@$CARRIER" \
--output stego_dct.jpg
echo "Encoded to stego_dct.jpg"
# Decode (auto-detects mode)
echo "Decoding..."
RESULT=$(curl -s -X POST "$BASE_URL/decode/multipart" \
-F "day_phrase=$PHRASE" \
-F "pin=$PIN" \
-F "reference_photo=@$REF_PHOTO" \
-F "stego_image=@stego_dct.jpg")
echo "Decoded message: $(echo $RESULT | jq -r '.message')"
echo "Mode detected: $(echo $RESULT | jq -r '.embedding_mode_detected')"
Rate Limiting
The API does not implement rate limiting by default. For production:
- Reverse Proxy: Use nginx or Caddy rate limiting
- Application Level: Add FastAPI middleware
Example nginx rate limiting:
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)
- Message size (max 50KB)
- Image size (max 5MB file, ~4MP dimensions)
- RSA key validity
- Embedding mode values
- Output format compatibility
Credential Handling
- Credentials are never logged
- No persistent storage of secrets
- Memory cleared after operations
Embedding Mode Security
| Mode | Consideration |
|---|---|
| LSB | Maximum capacity but fragile |
| DCT | Lower capacity but survives recompression |
Both modes use identical encryption (AES-256-GCM with Argon2id).
Interactive Documentation
When the API is running, visit:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
See Also
- CLI Documentation - Command-line interface
- Web UI Documentation - Browser interface
- README - Project overview