Files
stegasoo/frontends/API.md

27 KiB
Raw Blame History

Stegasoo REST API Documentation

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 (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:

  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)
  • 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:


See Also