Files
stegasoo/frontends/API.md
2026-01-01 14:04:55 -05:00

29 KiB
Raw Blame History

Stegasoo REST API Documentation (v3.2.0)

Complete REST API reference for Stegasoo steganography operations.

Table of Contents


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

pip install stegasoo[api]

This automatically installs DCT dependencies (scipy) 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.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

curl http://localhost:8000/

GET /modes

Get available embedding modes and their status.

Request

GET /modes HTTP/1.1
Host: localhost:8000

Response

{
  "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

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_passphrase": 4
}

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

{
  "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):

curl -X POST http://localhost:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"use_pin": true}'

RSA only with 6-word passphrase:

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:

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

POST /encode HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
  "message": "Secret message here",
  "reference_photo_base64": "iVBORw0KGgo...",
  "carrier_image_base64": "iVBORw0KGgo...",
  "passphrase": "apple forest thunder mountain",
  "pin": "123456",
  "rsa_key_base64": null,
  "rsa_password": null,
  "embed_mode": "lsb",
  "dct_output_format": "png",
  "dct_color_mode": "grayscale"
}

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

{
  "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)

# 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)

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

POST /encode/file HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
  "file_data_base64": "JVBERi0xLjQK...",
  "filename": "secret.pdf",
  "mime_type": "application/pdf",
  "reference_photo_base64": "iVBORw0KGgo...",
  "carrier_image_base64": "iVBORw0KGgo...",
  "passphrase": "apple forest thunder mountain",
  "pin": "123456",
  "embed_mode": "lsb"
}

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/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)

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)

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)

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

POST /decode HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
  "stego_image_base64": "iVBORw0KGgo...",
  "reference_photo_base64": "iVBORw0KGgo...",
  "passphrase": "apple forest thunder mountain",
  "pin": "123456",
  "rsa_key_base64": null,
  "rsa_password": null,
  "embed_mode": "auto"
}

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)

{
  "payload_type": "text",
  "message": "Secret message here",
  "file_data_base64": null,
  "filename": null,
  "mime_type": null
}

Response (File)

{
  "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

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

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

POST /compare HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
  "carrier_image_base64": "iVBORw0KGgo...",
  "payload_size": 50000
}

Request Body

Field Type Required Description
carrier_image_base64 string Base64-encoded carrier image
payload_size integer Optional payload size to check

Response

{
  "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

POST /will-fit HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
  "carrier_image_base64": "iVBORw0KGgo...",
  "payload_size": 50000,
  "embed_mode": "lsb"
}

Response

{
  "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)

curl -X POST http://localhost:8000/image/info \
  -F "image=@carrier.png"

Response

{
  "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)

curl -X POST http://localhost:8000/extract-key-from-qr \
  -F "qr_image=@keyqr.png"

Response

{
  "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

{
  "use_pin": true,
  "use_rsa": false,
  "pin_length": 6,
  "rsa_bits": 2048,
  "words_per_passphrase": 4
}

GenerateResponse

{
  "passphrase": "word1 word2 word3 word4",
  "pin": "123456",
  "rsa_key_pem": null,
  "entropy": {"passphrase": 44, "pin": 19, "rsa": 0, "total": 63},
  "phrases": null
}

EncodeRequest

{
  "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

{
  "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

{
  "stego_image_base64": "string",
  "reference_photo_base64": "string",
  "passphrase": "string",
  "pin": "string",
  "rsa_key_base64": "string",
  "rsa_password": "string",
  "embed_mode": "auto"
}

DecodeResponse

{
  "payload_type": "text",
  "message": "string",
  "file_data_base64": null,
  "filename": null,
  "mime_type": null
}

ErrorResponse

{
  "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

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

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)

#!/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:

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:


See Also