- Add reedsolo library for RS error correction (32 symbols = 16 byte correction per 223-byte chunk) - Protect entire payload (header + data) with RS encoding - Store 3 copies of length header with majority voting for robustness - Handle RS chunking overhead (varies based on data size) - Update capacity calculation to account for RS overhead (24 bytes prefix + variable RS overhead) - Add RS to dct, web, and api optional dependencies - Update about.html with v4.1.0 Reed-Solomon feature - Update module docstring This fixes DCT decode failures with certain carrier images that have uniform areas causing unstable DCT coefficients. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
634 lines
32 KiB
HTML
634 lines
32 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}About - Stegasoo{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-10">
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-info-circle me-2"></i>About Stegasoo</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="lead">
|
|
Stegasoo hides encrypted messages and files inside images using multi-factor authentication.
|
|
</p>
|
|
|
|
<h6 class="text-primary mt-4 mb-3">Features</h6>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<ul class="list-unstyled">
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>Text & File Embedding</strong>
|
|
<br><small class="text-muted">Any file type: PDF, ZIP, documents</small>
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>Multi-Factor Security</strong>
|
|
<br><small class="text-muted">Photo + passphrase + PIN/RSA key</small>
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>AES-256-GCM Encryption</strong>
|
|
<br><small class="text-muted">Authenticated encryption with integrity check</small>
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>DCT & LSB Modes</strong>
|
|
<br><small class="text-muted">JPEG resilience (DCT) or high capacity (LSB)</small>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<ul class="list-unstyled">
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>Random Pixel Embedding</strong>
|
|
<br><small class="text-muted">Defeats statistical analysis</small>
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>Large Image Support</strong>
|
|
<br><small class="text-muted">Up to {{ max_payload_kb }} KB, tested with 14MB+ images</small>
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>Zero Server Storage</strong>
|
|
<br><small class="text-muted">Nothing saved, files auto-expire</small>
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>QR Code Keys</strong>
|
|
<br><small class="text-muted">Import/export RSA keys via QR</small>
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="bi bi-check-circle text-success me-2"></i>
|
|
<strong>Channel Keys</strong>
|
|
<span class="badge bg-info ms-1">v4.1</span>
|
|
<br><small class="text-muted">Group/deployment isolation</small>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Embedding Modes -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-cpu me-2"></i>Embedding Modes</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p>Two modes optimized for different use cases.</p>
|
|
|
|
<div class="row mt-4">
|
|
<!-- DCT Mode -->
|
|
<div class="col-md-6 mb-4">
|
|
<div class="card bg-dark h-100">
|
|
<div class="card-header">
|
|
<i class="bi bi-soundwave text-warning me-2"></i>
|
|
<strong>DCT Mode</strong>
|
|
<span class="badge bg-success ms-2">Default</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="small">
|
|
<strong>DCT (Discrete Cosine Transform)</strong> embeds data in frequency coefficients. Survives JPEG recompression.
|
|
</p>
|
|
<ul class="small mb-0">
|
|
<li><strong>Capacity:</strong> ~75 KB/MP</li>
|
|
<li><strong>Output:</strong> JPEG or PNG</li>
|
|
<li><strong>Color:</strong> Color or grayscale</li>
|
|
<li><strong>Speed:</strong> ~2s</li>
|
|
<li><strong>Error Correction:</strong> Reed-Solomon <span class="badge bg-info ms-1">v4.1</span></li>
|
|
</ul>
|
|
<hr>
|
|
<div class="small">
|
|
<i class="bi bi-check-circle text-success me-1"></i> Instagram, Facebook<br>
|
|
<i class="bi bi-check-circle text-success me-1"></i> WhatsApp, Signal, Telegram<br>
|
|
<i class="bi bi-check-circle text-success me-1"></i> Twitter/X<br>
|
|
<i class="bi bi-check-circle text-success me-1"></i> Any recompressing platform
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- LSB Mode -->
|
|
<div class="col-md-6 mb-4">
|
|
<div class="card bg-dark h-100">
|
|
<div class="card-header">
|
|
<i class="bi bi-grid-3x3-gap text-primary me-2"></i>
|
|
<strong>LSB Mode</strong>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="small">
|
|
<strong>LSB (Least Significant Bit)</strong> embeds data in the lowest bit of each color channel. Imperceptible to the eye.
|
|
</p>
|
|
<ul class="small mb-0">
|
|
<li><strong>Capacity:</strong> ~375 KB/MP</li>
|
|
<li><strong>Output:</strong> PNG (lossless)</li>
|
|
<li><strong>Color:</strong> Full color</li>
|
|
<li><strong>Speed:</strong> ~0.5s</li>
|
|
</ul>
|
|
<hr>
|
|
<div class="small">
|
|
<i class="bi bi-check-circle text-success me-1"></i> Email attachments<br>
|
|
<i class="bi bi-check-circle text-success me-1"></i> Cloud storage<br>
|
|
<i class="bi bi-check-circle text-success me-1"></i> Direct file transfer<br>
|
|
<i class="bi bi-x-circle text-danger me-1"></i> Social media
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mode Comparison Table -->
|
|
<h6 class="mt-3"><i class="bi bi-table me-2"></i>Comparison</h6>
|
|
<div class="table-responsive">
|
|
<table class="table table-dark table-sm small">
|
|
<thead>
|
|
<tr>
|
|
<th>Aspect</th>
|
|
<th>DCT Mode <span class="badge bg-success ms-1">Default</span></th>
|
|
<th>LSB Mode</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Capacity (1080p)</td>
|
|
<td class="text-warning">~50 KB</td>
|
|
<td class="text-success">~770 KB</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Survives JPEG</td>
|
|
<td class="text-success">✅ Yes</td>
|
|
<td class="text-danger">❌ No</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Social Media</td>
|
|
<td class="text-success">✅ Works</td>
|
|
<td class="text-danger">❌ Broken</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Detection Resistance</td>
|
|
<td>Better</td>
|
|
<td>Moderate</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="alert alert-info small mt-3 mb-0">
|
|
<i class="bi bi-lightbulb me-2"></i>
|
|
<strong>Auto-Detection:</strong> Mode is detected automatically when decoding.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-shield-lock me-2"></i>How Security Works</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p>Multi-factor authentication derives encryption keys:</p>
|
|
|
|
<div class="row text-center my-4">
|
|
<div class="col-6 col-lg-3 mb-3">
|
|
<div class="p-3 bg-dark rounded h-100 d-flex flex-column align-items-center">
|
|
<i class="bi bi-image text-info fs-2 d-block mb-2"></i>
|
|
<strong>Reference Photo</strong>
|
|
<div class="small text-muted mt-1">Something you have</div>
|
|
<div class="small text-success mt-auto pt-2">~80-256 bits</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-lg-3 mb-3">
|
|
<div class="p-3 bg-dark rounded h-100 d-flex flex-column align-items-center">
|
|
<i class="bi bi-chat-quote text-warning fs-2 d-block mb-2"></i>
|
|
<strong>Passphrase</strong>
|
|
<div class="small text-muted mt-1">Something you know</div>
|
|
<div class="small text-success mt-auto pt-2">~44 bits (4 words)</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-lg-3 mb-3">
|
|
<div class="p-3 bg-dark rounded h-100 d-flex flex-column align-items-center">
|
|
<i class="bi bi-123 text-danger fs-2 d-block mb-2"></i>
|
|
<strong>Static PIN</strong>
|
|
<div class="small text-muted mt-1">Something you know</div>
|
|
<div class="small text-success mt-auto pt-2">~20 bits (6 digits)</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-lg-3 mb-3">
|
|
<div class="p-3 bg-dark rounded h-100 d-flex flex-column align-items-center">
|
|
<i class="bi bi-key text-primary fs-2 d-block mb-2"></i>
|
|
<strong>RSA Key</strong>
|
|
<div class="small text-muted mt-1">Optional</div>
|
|
<div class="small text-success mt-auto pt-2">~128 bits</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-secondary">
|
|
<i class="bi bi-calculator me-2"></i>
|
|
<strong>Combined entropy:</strong> 144-424+ bits. 128 bits is infeasible to brute force.
|
|
</div>
|
|
|
|
<h6 class="mt-4">Key Derivation</h6>
|
|
<p>
|
|
{% if has_argon2 %}
|
|
<span class="badge bg-success me-1"><i class="bi bi-check"></i> Argon2id</span>
|
|
256MB memory cost. Memory-hard KDF defeats GPU/ASIC attacks.
|
|
{% else %}
|
|
<span class="badge bg-warning text-dark me-1"><i class="bi bi-exclamation-triangle"></i> Argon2 Not Available</span>
|
|
Using PBKDF2-SHA512 with 600k iterations.
|
|
Install <code>argon2-cffi</code> for stronger security.
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Channel Keys (v4.0.0) -->
|
|
<div class="card mb-4" id="channel-keys">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-broadcast me-2"></i>Channel Keys
|
|
<span class="badge bg-info ms-2">v4.1</span>
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p>
|
|
Channel keys provide <strong>deployment/group isolation</strong>. Messages encoded with one channel key
|
|
cannot be decoded with a different key, even if all other credentials match.
|
|
</p>
|
|
|
|
<div class="row mt-4">
|
|
<!-- Auto Mode -->
|
|
<div class="col-md-4 mb-3">
|
|
<div class="card bg-dark h-100">
|
|
<div class="card-header text-center">
|
|
<i class="bi bi-gear-fill text-success fs-2 d-block mb-2"></i>
|
|
<strong>Auto</strong>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="small mb-2">Uses server-configured key if available, otherwise public mode.</p>
|
|
<ul class="small mb-0">
|
|
<li>Set via <code>STEGASOO_CHANNEL_KEY</code> env var</li>
|
|
<li>Or <code>channel_key</code> in config file</li>
|
|
<li>All users share the same channel</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Public Mode -->
|
|
<div class="col-md-4 mb-3">
|
|
<div class="card bg-dark h-100">
|
|
<div class="card-header text-center">
|
|
<i class="bi bi-globe text-info fs-2 d-block mb-2"></i>
|
|
<strong>Public</strong>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="small mb-2">No channel key. Compatible with other public installations.</p>
|
|
<ul class="small mb-0">
|
|
<li>Default if no server key configured</li>
|
|
<li>Anyone can decode (with credentials)</li>
|
|
<li>Interoperable between deployments</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Custom Mode -->
|
|
<div class="col-md-4 mb-3">
|
|
<div class="card bg-dark h-100">
|
|
<div class="card-header text-center">
|
|
<i class="bi bi-key-fill text-warning fs-2 d-block mb-2"></i>
|
|
<strong>Custom</strong>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="small mb-2">Your own group key. Share with recipients.</p>
|
|
<ul class="small mb-0">
|
|
<li>Format: <code>XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX</code></li>
|
|
<li>32 chars (128 bits entropy)</li>
|
|
<li>Private group communication</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if channel_configured %}
|
|
<div class="alert alert-success mt-3 mb-3">
|
|
<i class="bi bi-shield-lock me-2"></i>
|
|
<strong>This server has a channel key configured:</strong>
|
|
<code class="ms-2">{{ channel_fingerprint }}</code>
|
|
<span class="text-muted ms-2">({{ channel_source }})</span>
|
|
</div>
|
|
{% else %}
|
|
<div class="alert alert-info mt-3 mb-3">
|
|
<i class="bi bi-info-circle me-2"></i>
|
|
This server is running in <strong>public mode</strong>.
|
|
Set <code>STEGASOO_CHANNEL_KEY</code> to enable server-wide channel isolation.
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Channel Key QR Generator -->
|
|
<div class="card bg-dark border-secondary">
|
|
<div class="card-header">
|
|
<i class="bi bi-qr-code me-2"></i>Share Channel Key via QR
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="small text-muted mb-3">Generate a QR code to share a channel key with others.</p>
|
|
<div class="row g-2 align-items-end">
|
|
<div class="col-md-8">
|
|
<label class="form-label small">Channel Key</label>
|
|
<div class="input-group">
|
|
<input type="text" class="form-control font-monospace" id="channelKeyQrInput"
|
|
placeholder="Enter or generate a key">
|
|
<button class="btn btn-outline-secondary" type="button" id="channelKeyQrGenerate"
|
|
title="Generate random key">
|
|
<i class="bi bi-shuffle"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<button class="btn btn-primary w-100" type="button" id="channelKeyQrShow">
|
|
<i class="bi bi-qr-code me-1"></i>Show QR
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="text-center mt-3 d-none" id="channelKeyQrContainer">
|
|
<canvas id="channelKeyQrCanvas" class="bg-white p-2 rounded"></canvas>
|
|
<div class="mt-2">
|
|
<button class="btn btn-sm btn-outline-secondary" type="button" id="channelKeyQrDownload">
|
|
<i class="bi bi-download me-1"></i>Download PNG
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Version History -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-clock-history me-2"></i>Version History</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-dark table-sm small">
|
|
<thead>
|
|
<tr>
|
|
<th>Version</th>
|
|
<th>Changes</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>4.1.0</strong></td>
|
|
<td>
|
|
<strong>Reed-Solomon error correction</strong> for DCT mode (corrects up to 16 byte errors per 223-byte chunk),
|
|
majority voting on length headers, improved robustness with problematic carrier images
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>4.0.0</strong></td>
|
|
<td>
|
|
<strong>Channel keys</strong> for group/deployment isolation,
|
|
DCT default, simplified auth, passphrase replaces day_phrase,
|
|
4-word default, JPEG fix, large image support, subprocess isolation, Python 3.10-3.12
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>3.2.0</td>
|
|
<td>Single passphrase, more default words</td>
|
|
</tr>
|
|
<tr>
|
|
<td>3.0.0</td>
|
|
<td>DCT mode, JPEG output, color preservation</td>
|
|
</tr>
|
|
<tr>
|
|
<td>2.2.0</td>
|
|
<td>QR code RSA key import/export</td>
|
|
</tr>
|
|
<tr>
|
|
<td>2.1.0</td>
|
|
<td>File embedding, compression</td>
|
|
</tr>
|
|
<tr>
|
|
<td>2.0.0</td>
|
|
<td>Web UI, REST API, RSA keys</td>
|
|
</tr>
|
|
<tr>
|
|
<td>1.0.0</td>
|
|
<td>Initial release, CLI only, LSB mode</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-question-circle me-2"></i>Usage Guide</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="accordion" id="usageAccordion">
|
|
<div class="accordion-item bg-dark">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button bg-dark text-light" type="button"
|
|
data-bs-toggle="collapse" data-bs-target="#setup">
|
|
<i class="bi bi-1-circle me-2"></i>Initial Setup
|
|
</button>
|
|
</h2>
|
|
<div id="setup" class="accordion-collapse collapse show" data-bs-parent="#usageAccordion">
|
|
<div class="accordion-body">
|
|
<ol>
|
|
<li>Agree on a <strong>reference photo</strong> (never transmitted)</li>
|
|
<li>Go to <a href="/generate">Generate</a> to create credentials</li>
|
|
<li>Memorize passphrase and PIN</li>
|
|
<li>If using RSA, store the key file securely</li>
|
|
<li>Share credentials via secure channel</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="accordion-item bg-dark">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed bg-dark text-light" type="button"
|
|
data-bs-toggle="collapse" data-bs-target="#encoding">
|
|
<i class="bi bi-2-circle me-2"></i>Encoding
|
|
</button>
|
|
</h2>
|
|
<div id="encoding" class="accordion-collapse collapse" data-bs-parent="#usageAccordion">
|
|
<div class="accordion-body">
|
|
<ol>
|
|
<li>Go to <a href="/encode">Encode</a></li>
|
|
<li>Upload <strong>reference photo</strong> and <strong>carrier image</strong></li>
|
|
<li>Choose mode:
|
|
<ul>
|
|
<li><strong>DCT</strong> (default): social media</li>
|
|
<li><strong>LSB</strong>: email, cloud, direct transfer</li>
|
|
</ul>
|
|
</li>
|
|
<li>Enter message or select file</li>
|
|
<li>Enter passphrase and PIN/key</li>
|
|
<li>Download stego image</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="accordion-item bg-dark">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed bg-dark text-light" type="button"
|
|
data-bs-toggle="collapse" data-bs-target="#decoding">
|
|
<i class="bi bi-3-circle me-2"></i>Decoding
|
|
</button>
|
|
</h2>
|
|
<div id="decoding" class="accordion-collapse collapse" data-bs-parent="#usageAccordion">
|
|
<div class="accordion-body">
|
|
<ol>
|
|
<li>Go to <a href="/decode">Decode</a></li>
|
|
<li>Upload <strong>reference photo</strong></li>
|
|
<li>Upload <strong>stego image</strong></li>
|
|
<li>Enter passphrase and PIN/key</li>
|
|
<li>View message or download file</li>
|
|
</ol>
|
|
<div class="alert alert-info small mt-3 mb-0">
|
|
<i class="bi bi-magic me-2"></i>
|
|
Mode is auto-detected.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-speedometer2 me-2"></i>Limits & Specs</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<table class="table table-dark table-striped small">
|
|
<tbody>
|
|
<tr>
|
|
<td><i class="bi bi-file-text me-2"></i>Max text</td>
|
|
<td><strong>2M characters</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-file-earmark me-2"></i>Max file</td>
|
|
<td><strong>{{ max_payload_kb }} KB</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-image me-2"></i>Max carrier</td>
|
|
<td><strong>24 MP</strong> (~6000x4000)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-soundwave me-2"></i>DCT capacity</td>
|
|
<td><strong>~75 KB/MP</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-grid-3x3 me-2"></i>LSB capacity</td>
|
|
<td><strong>~375 KB/MP</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-upload me-2"></i>Max upload</td>
|
|
<td><strong>30 MB</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-clock me-2"></i>File expiry</td>
|
|
<td><strong>5 min</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-key me-2"></i>PIN</td>
|
|
<td><strong>6-9 digits</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-shield me-2"></i>RSA keys</td>
|
|
<td><strong>2048, 3072, 4096 bit</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-chat-quote me-2"></i>Passphrase</td>
|
|
<td><strong>3-12 words</strong> (BIP-39)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-code me-2"></i>Python Version</td>
|
|
<td><strong>3.10-3.12</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="bi bi-box me-2"></i>Built with</td>
|
|
<td>Flask, Pillow, NumPy, SciPy, jpegio, cryptography, argon2-cffi</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<!-- QR Code library for channel key sharing -->
|
|
<script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.3/build/qrcode.min.js"></script>
|
|
<script src="{{ url_for('static', filename='js/stegasoo.js') }}"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const input = document.getElementById('channelKeyQrInput');
|
|
const generateBtn = document.getElementById('channelKeyQrGenerate');
|
|
const showBtn = document.getElementById('channelKeyQrShow');
|
|
const container = document.getElementById('channelKeyQrContainer');
|
|
const canvas = document.getElementById('channelKeyQrCanvas');
|
|
const downloadBtn = document.getElementById('channelKeyQrDownload');
|
|
|
|
// Generate random key
|
|
generateBtn?.addEventListener('click', function() {
|
|
if (input && typeof Stegasoo !== 'undefined') {
|
|
input.value = Stegasoo.generateChannelKey();
|
|
}
|
|
});
|
|
|
|
// Show QR code
|
|
showBtn?.addEventListener('click', function() {
|
|
const key = input?.value?.trim().replace(/-/g, '');
|
|
if (!key || key.length !== 32) {
|
|
alert('Please enter a valid 32-character channel key');
|
|
return;
|
|
}
|
|
|
|
// Format key with dashes for QR
|
|
const formatted = key.match(/.{4}/g)?.join('-') || key;
|
|
|
|
// Generate QR code
|
|
if (typeof QRCode !== 'undefined' && canvas) {
|
|
QRCode.toCanvas(canvas, formatted, {
|
|
width: 200,
|
|
margin: 2,
|
|
color: { dark: '#000', light: '#fff' }
|
|
}, function(error) {
|
|
if (error) {
|
|
console.error('QR generation error:', error);
|
|
return;
|
|
}
|
|
container?.classList.remove('d-none');
|
|
});
|
|
}
|
|
});
|
|
|
|
// Download QR as PNG
|
|
downloadBtn?.addEventListener('click', function() {
|
|
if (canvas) {
|
|
const link = document.createElement('a');
|
|
link.download = 'stegasoo-channel-key.png';
|
|
link.href = canvas.toDataURL('image/png');
|
|
link.click();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|