Version 3.0.2 full expirimental DCT support, jpegio for better jpg manipulation, etc.

This commit is contained in:
Aaron D. Lee
2025-12-31 15:43:29 -05:00
parent 4eefc946c4
commit 34376b2dfe
19 changed files with 2954 additions and 2200 deletions

View File

@@ -16,6 +16,7 @@ Complete REST API reference for Stegasoo steganography operations.
- [POST /decode](#post-decode-json)
- [POST /decode/multipart](#post-decodemultipart)
- [POST /image/info](#post-imageinfo)
- [Embedding Modes](#embedding-modes)
- [Data Models](#data-models)
- [Error Handling](#error-handling)
- [Code Examples](#code-examples)
@@ -29,12 +30,19 @@ Complete REST API reference for Stegasoo steganography operations.
The Stegasoo REST API provides programmatic access to all steganography operations:
- **Generate** credentials (phrases, PINs, RSA keys)
- **Encode** messages into images
- **Decode** messages from images
- **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
@@ -45,6 +53,8 @@ The API supports both JSON (base64-encoded images) and multipart form data (dire
pip install stegasoo[api]
```
This automatically installs DCT dependencies (scipy, jpegio) for full functionality.
### From Source
```bash
@@ -107,8 +117,10 @@ Host: localhost:8000
```json
{
"version": "2.0.1",
"version": "3.0.2",
"has_argon2": true,
"has_dct": true,
"has_jpegio": true,
"day_names": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
}
```
@@ -119,6 +131,8 @@ Host: localhost:8000
|-------|------|-------------|
| `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
@@ -245,22 +259,28 @@ Content-Type: application/json
| `rsa_password` | string | | | Password for RSA key |
| `date_str` | string | | | Date override (YYYY-MM-DD) |
| `embedding_mode` | string | | `"lsb"` | `"lsb"` or `"dct"` |
\* At least one of `pin` or `rsa_key_base64` required.
| `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
```json
{
"stego_image_base64": "iVBORw0KGgo...",
"filename": "a1b2c3d4_20251227.png",
"capacity_used_percent": 12.4,
"date_used": "2025-12-27",
"day_of_week": "Saturday"
}
```
#### Response Fields
"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 |
@@ -272,7 +292,10 @@ Content-Type: application/json
| `output_format` | string | Output format: `"png"` or `"jpeg"` |
| `color_mode` | string\|null | Color mode (DCT only): `"color"` or `"grayscale"` |
# Prepare base64-encoded images
#### cURL Example (LSB Mode - Default)
```bash
# Prepare base64-encoded images
REF_B64=$(base64 -w0 reference.jpg)
CARRIER_B64=$(base64 -w0 carrier.png)
@@ -280,13 +303,16 @@ Content-Type: application/json
-H "Content-Type: application/json" \
-d "{
\"message\": \"Secret message\",
\"reference_photo_base64\": \"$REF_B64\",
\"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)
```bash
curl -X POST http://localhost:8000/encode \
-H "Content-Type: application/json" \
-d "{
@@ -304,6 +330,23 @@ curl -X POST http://localhost:8000/encode \
---
### POST /encode/multipart
Encode a message using direct file uploads. Returns the stego image directly.
#### Request
```http
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"
@@ -330,6 +373,18 @@ Content-Disposition: form-data; name="pin"
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 |
@@ -344,83 +399,72 @@ Content-Type: image/png
Returns the image directly with headers:
- `Content-Disposition: attachment; filename=<generated_filename>.png`
- `X-Stegasoo-Date: 2025-12-27` (date used for encoding)
- `X-Stegasoo-Day: Saturday` (day of week for passphrase rotation)
- `X-Stegasoo-Capacity-Percent: 12.4` (capacity used)
#### cURL Examples
**With PIN:**
```bash
curl -X POST http://localhost:8000/encode/multipart \
```http
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` |
--output stego.png
```
**With RSA key:**
```bash
curl -X POST http://localhost:8000/encode/multipart \
| `Content-Disposition` | Suggested filename |
| `X-Stegasoo-Date` | Encoding date |
-F "day_phrase=apple forest thunder" \
| `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)
```bash
curl -X POST http://localhost:8000/encode/multipart \
-F "rsa_password=keypassword" \
-F "reference_photo=@reference.jpg" \
-F "carrier=@carrier.png" \
--output stego.png
```
**With both PIN and RSA:**
```bash
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 "pin=123456" \
-F "rsa_key=@mykey.pem" \
-F "rsa_password=keypassword" \
-F "reference_photo=@reference.jpg" \
-F "carrier=@carrier.png" \
--output stego.png
```
**With custom date:**
```bash
curl -X POST http://localhost:8000/encode/multipart \
-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
-F "day_phrase=monday phrase here" \
```http
-F "reference_photo=@reference.jpg" \
POST /decode HTTP/1.1
Host: localhost:8000
Content-Type: application/json
```
```
#### Request Body
### POST /decode (JSON)
Decode a message using base64-encoded images.
#### Request
```http
POST /decode HTTP/1.1
Host: localhost:8000
Content-Type: application/json
```
| 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 |
| `day_phrase` | string | | Passphrase for encoding day |
| `rsa_password` | string | | Password for RSA key |
\* Must match security factors used during encoding.
@@ -450,20 +494,27 @@ Content-Type: application/json
-H "Content-Type: application/json" \
-d "{
\"stego_image_base64\": \"$STEGO_B64\",
```
\"reference_photo_base64\": \"$REF_B64\",
\"day_phrase\": \"apple forest thunder\",
\"pin\": \"123456\"
}"
```
Decode a message using direct file uploads.
---
### 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) |
Content-Type: multipart/form-data
| `rsa_password` | string | | Password for RSA key |
#### Response
@@ -481,15 +532,7 @@ curl -X POST http://localhost:8000/decode \
curl -X POST http://localhost:8000/decode/multipart \
-F "day_phrase=apple forest thunder" \
-F "pin=123456" \
"message": "Secret message here"
}
```
#### cURL Examples
**With PIN:**
```bash
curl -X POST http://localhost:8000/decode/multipart \
-F "reference_photo=@reference.jpg" \
-F "stego_image=@stego.png"
```
@@ -499,20 +542,20 @@ Content-Type: multipart/form-data
Get image information and capacity for both LSB and DCT modes.
-F "day_phrase=apple forest thunder" \
#### Request (JSON)
```http
POST /image/info HTTP/1.1
Host: localhost:8000
Content-Type: application/json
---
```
#### Request (Multipart)
```bash
Get information about an image's capacity.
curl -X POST http://localhost:8000/image/info \
-F "image=@carrier.png"
#### Request
```
#### Response
@@ -521,35 +564,30 @@ curl -X POST http://localhost:8000/decode/multipart \
{
"width": 1920,
"height": 1080,
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `image` | file | ✓ | Image file to analyze |
#### Response
```json
{
"width": 1920,
"pixels": 2073600,
"format": "PNG",
"mode": "RGB",
"capacity": {
}
"lsb": {
"bytes": 776970,
"kb": 758
},
"dct": {
"bytes": 64800,
"kb": 63,
| `width` | integer | Image width in pixels |
"note": "Approximate - actual capacity depends on image content"
}
}
}
```
#### Response Fields
| `capacity_bytes` | integer | Maximum message capacity (bytes) |
| Field | Type | Description |
#### cURL Example
|-------|------|-------------|
| `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 |
@@ -558,8 +596,19 @@ Content-Type: multipart/form-data
| `capacity.dct.kb` | integer | Estimated DCT capacity in KB |
| `capacity.dct.note` | string | Capacity estimation note |
### GenerateRequest
---
## 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 |
@@ -570,15 +619,58 @@ Content-Type: multipart/form-data
| Aspect | Details |
|--------|---------|
| **Parameter** | `"embedding_mode": "dct"` |
### GenerateResponse
| **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
```json
| Option | Values | Default | Description |
"phrases": {"Monday": "...", "Tuesday": "...", ...},
"pin": "123456",
"rsa_key_pem": "-----BEGIN PRIVATE KEY-----...",
"entropy": {"phrase": 33, "pin": 19, "rsa": 0, "total": 52}
|--------|--------|---------|-------------|
| `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
```json
{
"use_pin": true,
"use_rsa": false,
"pin_length": 6,
"rsa_bits": 2048,
"words_per_phrase": 3
}
```
### GenerateResponse
```json
{
"phrases": {"Monday": "...", "Tuesday": "...", ...},
"pin": "123456",
"rsa_key_pem": "-----BEGIN PRIVATE KEY-----...",
"entropy": {"phrase": 33, "pin": 19, "rsa": 0, "total": 52}
}
```
### EncodeRequest
```json
{
"message": "string",
"reference_photo_base64": "string",
@@ -618,7 +710,10 @@ curl -X POST http://localhost:8000/image/info \
"day_phrase": "string",
"pin": "string",
"rsa_key_base64": "string",
"rsa_password": "string"
"rsa_password": "string"
}
```
### DecodeResponse
```json
@@ -630,7 +725,10 @@ curl -X POST http://localhost:8000/image/info \
### ImageInfoResponse
### ImageInfoResponse
```json
{
"width": 1920,
"height": 1080,
"pixels": 2073600,
"format": "PNG",
"mode": "RGB",
@@ -651,7 +749,8 @@ curl -X POST http://localhost:8000/image/info \
```
---
---
## Error Handling
### HTTP Status Codes
@@ -662,8 +761,12 @@ curl -X POST http://localhost:8000/image/info \
| 401 | Unauthorized | Decryption failed (wrong credentials) |
| 500 | Internal Error | Unexpected server error |
| 500 | Internal Error | Unexpected server error |
### Error Response Format
```json
{
"detail": "Error message describing the problem"
}
```
### Common Errors
@@ -705,8 +808,11 @@ curl -X POST http://localhost:8000/image/info \
# 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",
with open("reference.jpg", "rb") as ref, open("carrier.png", "rb") as carrier:
"day_phrase": "apple forest thunder",
"pin": "123456"
})
@@ -730,7 +836,7 @@ creds = response.json()
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,
@@ -744,7 +850,24 @@ with open("reference.jpg", "rb") as ref, open("carrier.png", "rb") as carrier:
print(f"Decoded: {result['message']}")
print(f"Mode detected: {result['embedding_mode_detected']}")
```
form.append('day_phrase', 'apple forest thunder');
### 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 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'));
@@ -754,7 +877,9 @@ with open("reference.jpg", "rb") as ref, open("stego.png", "rb") as stego:
});
fs.writeFileSync('stego.jpg', response.data);
fs.writeFileSync('stego.png', 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();
@@ -766,11 +891,14 @@ const axios = require('axios');
const response = await axios.post(`${BASE_URL}/decode/multipart`, form, {
headers: form.getHeaders()
});
headers: form.getHeaders()
console.log('Decoded:', response.data.message);
console.log('Mode detected:', response.data.embedding_mode_detected);
}
encodeDCT().then(decode);
```
### Go
```go
@@ -779,8 +907,9 @@ async function encode() {
import (
"bytes"
"encoding/json"
import (
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
@@ -788,16 +917,17 @@ async function decode() {
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")
writer.WriteField("pin", "123456")
refPart, _ := writer.CreateFormFile("reference_photo", "reference.jpg")
io.Copy(refPart, ref)
ref.Close()
@@ -816,13 +946,16 @@ import (
// 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)
```bash
@@ -842,12 +975,15 @@ func main() {
-F "day_phrase=$PHRASE" \
-F "pin=$PIN" \
-F "reference_photo=@$REF_PHOTO" \
-F "day_phrase=$PHRASE" \
-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" \
@@ -863,27 +999,43 @@ PHRASE="apple forest thunder"
echo "Decoding..."
RESULT=$(curl -s -X POST "$BASE_URL/decode/multipart" \
-F "day_phrase=$PHRASE" \
## Rate Limiting
-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')"
```
```nginx
---
## Rate Limiting
limit_req zone=stegasoo burst=20 nodelay;
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
@@ -917,9 +1069,15 @@ location /api/ {
|------|--------------|
| 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
@@ -927,6 +1085,8 @@ The API validates:
## See Also
- [CLI Documentation](CLI.md) - Command-line interface
- [Web UI Documentation](WEB_UI.md) - Browser interface
- [README](README.md) - Project overview
### Credential Handling
@@ -934,6 +1094,15 @@ The API validates:
- 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