{"id":50486928,"url":"https://github.com/systemslibrarian/snow2","last_synced_at":"2026-06-01T23:02:55.275Z","repository":{"id":341091350,"uuid":"1168829222","full_name":"systemslibrarian/snow2","owner":"systemslibrarian","description":"A modern Rust reimplementation of SNOW with strong 2026 cryptography.","archived":false,"fork":false,"pushed_at":"2026-03-13T04:00:55.000Z","size":61113,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-13T10:54:29.806Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/systemslibrarian.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-27T21:05:22.000Z","updated_at":"2026-03-13T04:00:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/systemslibrarian/snow2","commit_stats":null,"previous_names":["systemslibrarian/snow2"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/systemslibrarian/snow2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2Fsnow2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2Fsnow2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2Fsnow2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2Fsnow2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/systemslibrarian","download_url":"https://codeload.github.com/systemslibrarian/snow2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/systemslibrarian%2Fsnow2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33797128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-01T02:00:06.963Z","response_time":115,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-01T23:02:54.414Z","updated_at":"2026-06-01T23:02:55.263Z","avatar_url":"https://github.com/systemslibrarian.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SNOW2 ❄️  \n*A modern Rust tribute to Matthew Kwan's SNOW steganography tool.*\n\n**[Try the live demo →](https://systemslibrarian.github.io/snow2/)**\n\nSNOW2 is a clean, modern reimplementation inspired by the original **SNOW** program by **Matthew Kwan** — a classic late-1990s tool that demonstrated how encrypted messages could be hidden inside ordinary-looking text using whitespace.\n\nThis project preserves the elegance and educational value of the original while upgrading the cryptography, safety, and engineering for today.\n\n---\n\n## Philosophy\n\nThe original SNOW was brilliant because it taught two powerful concepts quickly:\n\n1. **Encryption** protects meaning.\n2. **Steganography** hides existence.\n\nSNOW2 keeps that same spirit:\n\n- Small\n- Understandable\n- Educational\n- Respectful of the original design\n\nBut cryptographically modern.\n\n---\n\n## What SNOW2 Does\n\nSNOW2 hides an encrypted payload inside a text \"carrier\" using whitespace-based steganography.\n\nYou provide:\n\n- A message or file\n- A password\n- Optional second secret (pepper / \"Signal Key\")\n\nSNOW2 produces:\n\n- A modified text file that looks normal\n- A recoverable encrypted payload embedded invisibly\n- Embedded data that is statistically indistinguishable from random noise (v4 hardened pipeline)\n\nExtraction requires the correct secrets. Tampering causes authenticated failure.\n\n---\n\n## Modern Cryptography\n\nSNOW2 upgrades the crypto model completely.\n\n### AEAD Encryption\n- **XChaCha20-Poly1305**\n  - Large nonce space\n  - Misuse-resistant\n  - Authenticated encryption (confidentiality + integrity)\n\n### Key Derivation (Domain-Separated)\n- **Argon2id** → master secret, then **HKDF-SHA256** expansion with domain labels\n  - Memory-hard, GPU-resistant\n  - Tunable parameters (`--kdf-mib`, `--kdf-iters`, `--kdf-par`)\n  - Domain labels: `snow2/aead-key`, `snow2/pepper-binding`\n  - Pepper bound via HKDF salt — no concatenation ambiguity\n\n### Extraction-Side KDF Bounds\n- Untrusted container headers are validated **before** any expensive KDF work\n- Hard limits reject absurd memory/time cost values from hostile containers\n- Bounds: max 512 MiB memory, max 64 iterations, max 16 parallelism, min 8 MiB memory\n- Both embedding and extraction validate KDF params — you can't create un-extractable containers\n\n### Hardened Profile\n- `KdfParams::hardened()` — 256 MiB / t=4 / p=1 for high-value secrets\n- `EmbedSecurityOptions::hardened()` — hardened KDF + mandatory pepper\n\n### Optional Pepper (\"Signal Key\")\n- A second secret never stored in the carrier\n- Cryptographically bound via HKDF domain separation (not concatenation)\n- If missing or incorrect → decryption fails\n- Not required, but strongly encouraged\n\n### Pepper-required policy\nSNOW2 can *require* a pepper for decryption.\n\nIf enabled at embed time, the container is marked **pepper_required=true** (authenticated in the header).  \nExtraction will fail if the pepper is not provided — even if the password is correct.\n\nThis is useful when you want \"password + something else you know\" by policy.\n\n### Secure Memory\n- **SecureVec**: mlock'd, dual-guard-paged, zeroize-on-drop memory buffers (native targets)\n  - Leading and trailing guard pages (PROT_NONE) catch underflows and overflows\n  - `MADV_DONTDUMP` (Linux) excludes secure buffers from core dumps\n  - Optional `enable_paranoid_memory()` calls `mlockall` to pin all process pages\n- Intermediate plaintext from AEAD decryption is zeroized after copy to SecureVec\n- Decompression temporaries are explicitly zeroized before drop\n- Passwords zeroized from memory after use\n- On WASM targets, falls back to zeroize-on-drop Vec wrappers (no mlock available)\n\n### Bitstream Integrity\n- **V4 containers**: Outer AEAD (XChaCha20-Poly1305 with Argon2-derived key) provides cryptographic integrity over the entire embedded bitstream — no CRC framing needed\n- **Legacy containers (v1/v3)**: CRC-32 framing catches carrier corruption (whitespace stripping, copy-paste mangling) before the container parser or AEAD sees it\n\n### Steganalysis Resistance (V4 Hardened Pipeline)\nSNOW2 v4 implements six layers of steg resistance that make embedded data virtually undetectable:\n\n1. **Random carrier padding** — every non-empty line in the carrier gets steganographic content (real data OR random padding), eliminating the statistical boundary between \"message lines\" and \"clean lines\"\n2. **Outer AEAD encryption** — the entire embedded bitstream is encrypted with an Argon2-derived key + XChaCha20-Poly1305, making it indistinguishable from uniform random noise\n3. **Constant-size containers** — payloads are padded to fixed-size buckets (multiples of 64 bytes), masking the actual message length\n4. **Plaintext compression** — deflate compression before encryption reduces the data footprint\n5. **Stripped wire format** — no magic bytes or header length on the wire (saves 9 bytes, removes ASCII signatures)\n6. **Packed binary header** — 49-byte binary header with log2-encoded KDF params (was 266-byte JSON)\n\n**Verified resistance metrics:**\n- 100% carrier line coverage (all lines carry ZW/whitespace content)\n- 256/256 unique byte values in embedded data\n- Chi-squared ≈ 255 (indistinguishable from uniform random; theoretical optimum = 255)\n- No detectable boundary between message data and carrier padding\n\n---\n\n## Post-Quantum Cryptography (Optional)\n\nSNOW2 supports **hybrid post-quantum encryption** via the optional `pqc` feature flag.\n\nWhen enabled, containers use a **Version 2** format with:\n\n- **Kyber1024** (ML-KEM) — NIST-standardized lattice-based key encapsulation\n- **Dilithium5** (ML-DSA) — NIST-standardized lattice-based digital signatures\n- **Hybrid encryption** — Kyber KEM shared secret → HKDF → XChaCha20-Poly1305\n- **Authenticated containers** — every PQC container is signed with Dilithium5\n- **Encrypted key storage** — secret keys can be encrypted at rest with password-derived AEAD\n  - Versioned format (`SNOW2EK\\0` magic + version byte) for future evolution\n  - Version byte authenticated as AEAD AAD to prevent downgrade attacks\n- **Hardened file permissions** — secret key files written with 0o600 (Unix) via atomic rename\n\nPQC mode does not use passwords. Instead, you generate a keypair and use key files.\n\n### Build with PQC support\n```bash\ncargo build --release --features pqc\n```\n\n### Generate a PQC keypair\n```bash\nsnow2 pqc-keygen --pk-out key.pk --sk-out key.sk\n# With encrypted secret key:\nsnow2 pqc-keygen --pk-out key.pk --sk-out key.sk --sk-password \"my password\"\n```\n\n### Embed with PQC\n```bash\nsnow2 embed \\\n  --mode classic-trailing \\\n  --carrier carrier.txt \\\n  --out out.txt \\\n  --input secret.txt \\\n  --pqc-pk key.pk\n```\n\n### Extract with PQC\n```bash\nsnow2 extract \\\n  --mode classic-trailing \\\n  --carrier out.txt \\\n  --out recovered.txt \\\n  --pqc-sk key.sk\n# If key is encrypted:\nsnow2 extract \\\n  --mode classic-trailing \\\n  --carrier out.txt \\\n  --out recovered.txt \\\n  --pqc-sk key.sk \\\n  --pqc-sk-password \"my password\"\n```\n\n\u003e **Note:** PQC containers are significantly larger than password-based containers (~10 KB overhead for Kyber ciphertext + Dilithium signature). Ensure your carrier has enough lines.\n\n---\n\n## Steganography Modes\n\nSNOW2 supports multiple embedding strategies.\n\n\u003e **Recommendation:** For reliable day-to-day use, prefer **`websafe-zw`** mode or work with **file-based carriers** that won't be processed by editors, mail clients, or CI tools. Reserve `classic-trailing` for educational purposes, controlled environments, or when faithfulness to the original SNOW is desired.\n\n### `classic-trailing`\n- Trailing spaces and tabs encode bits at the end of each line\n- Direct homage to original SNOW\n- Most elegant\n- **Most fragile** — trailing whitespace is silently stripped by most text editors, Git hooks, linters, formatters, email systems, and CI pipelines. If the carrier passes through *any* of these, the payload is destroyed.\n\n### `websafe-zw` *(recommended)*\n- Zero-width Unicode character embedding (U+200B, U+200C)\n- **8 bits per line** — each carrier line can hold a full byte, dramatically reducing carrier size\n- Survives copy/paste, most editors, and many messaging apps\n- Better suited for browser/WASM usage\n- Some platforms may strip zero-width characters (Unicode normalization, clipboard sanitizers)\n\n---\n\n## Important Limitations\n\nWhitespace steganography is inherently fragile. **However, SNOW2\\u2019s v4 hardened pipeline makes the embedded data statistically undetectable in single-file analysis.**\n\n### Trailing whitespace (`classic-trailing` mode)\n- Most text editors have \"trim trailing whitespace on save\" enabled **by default** — VS Code, JetBrains, Vim, and others will silently destroy the payload on save\n- Git can be configured to strip trailing whitespace (`core.whitespace`)\n- Linters, formatters, CI tools, and email systems routinely normalize whitespace\n- This is the most fragile mode, but also the most faithful to the original SNOW\n- **For reliability, use `websafe-zw` mode or exchange carriers as untouched files**\n\n### Zero-width characters (`websafe-zw` mode)\n- More tolerant of copy/paste than trailing whitespace\n- Survives in many browsers, rich-text editors, and messaging apps\n- Can still be stripped by: Unicode normalization (NFKC/NFKD), some messaging platforms, clipboard sanitizers, or HTML rendering\n- Not \"bulletproof\" — just \"more resilient\"\n\n### General\n- If the carrier changes in any way, extraction will fail — this is by design (integrity is mandatory via AEAD)\n- File modification metadata (timestamps, sizes) may reveal that a file has been altered\n- A forensic analyst comparing the original carrier to the modified carrier can detect embedding\n\nUse the `scan` command to check a carrier before embedding. It reports:\n- Stego capacity (raw bits and estimated payload max after container overhead)\n- Line ending format (LF vs CRLF vs mixed)\n- Tab character warnings (editor auto-expansion risk)\n- Existing trailing whitespace or zero-width characters\n- Consecutive marker run detection (signs of existing embedded data)\n- CRLF normalization risk warnings\n- Per-mode fragility notes\n\n---\n\n## Quick Start (CLI)\n\n### 1) Build\n```bash\ncargo build --release\n./target/release/snow2 --help\n```\n\n### 2) Generate a carrier (recommended for demos)\n`classic-trailing` embeds **1 bit per non-empty line**; `websafe-zw` embeds **8 bits per line** (a full byte), so it needs far fewer lines.\n\nA helper script is included:\n\n```bash\nchmod +x scripts/make_carrier.sh\n./scripts/make_carrier.sh 6000 carrier.txt\n```\n\n### 3) Embed a message\n```bash\nsnow2 embed \\\n  --mode websafe-zw \\\n  --carrier carrier.txt \\\n  --out out.txt \\\n  --message \"hello snow2\" \\\n  --password \"pw\"\n```\n\n\u003e **Tip:** `websafe-zw` is recommended for most use cases — it survives copy/paste and editor saves far better than `classic-trailing`. Use `classic-trailing` when you want exact fidelity to the original SNOW behaviour.\n\n### 4) Extract\n```bash\nsnow2 extract \\\n  --mode websafe-zw \\\n  --carrier out.txt \\\n  --out recovered.bin \\\n  --password \"pw\"\n\ncat recovered.bin\n```\n\n### 5) Scan a carrier\nInspect a carrier file for capacity, existing embedded data, or corruption risks:\n\n```bash\nsnow2 scan --carrier carrier.txt\n```\n\n### 6) Best-effort file shredding\nOverwrite and remove a file (see caveats below):\n\n```bash\nsnow2 shred --path sensitive.txt --passes 3\n```\n\n\u003e **Note:** File shredding is best-effort. On SSDs with wear-leveling, CoW filesystems (btrfs, ZFS), or journaling filesystems, overwritten data may persist in spare blocks, snapshots, or journals. For high-assurance deletion, use full-disk encryption and destroy the key.\n\n### Quick-Reference Cheat Sheet\n\n```bash\n# Embed (websafe-zw, recommended)\nsnow2 embed -m websafe-zw -c carrier.txt -o out.txt --message \"secret\" --password \"pw\"\n\n# Embed from file\nsnow2 embed -m websafe-zw -c carrier.txt -o out.txt --input secret.bin --password \"pw\"\n\n# Embed with pepper + policy\nsnow2 embed -m websafe-zw -c carrier.txt -o out.txt --message \"secret\" \\\n  --password \"pw\" --pepper \"signal\" --pepper-required\n\n# Extract\nsnow2 extract -m websafe-zw -c out.txt -o recovered.bin --password \"pw\"\n\n# Extract with pepper\nsnow2 extract -m websafe-zw -c out.txt -o recovered.bin --password \"pw\" --pepper \"signal\"\n\n# Scan carrier for capacity \u0026 risks\nsnow2 scan --carrier carrier.txt\n\n# Classic-trailing mode\nsnow2 embed -m classic-trailing -c carrier.txt -o out.txt --message \"secret\" --password \"pw\"\nsnow2 extract -m classic-trailing -c out.txt -o recovered.bin --password \"pw\"\n```\n\n---\n\n## Security Options (CLI)\n\n### Pepper / Signal Key\nUse a second secret:\n\n```bash\nsnow2 embed \\\n  --mode classic-trailing \\\n  --carrier carrier.txt \\\n  --out out.txt \\\n  --message \"hello\" \\\n  --password \"pw\" \\\n  --pepper \"signal key\"\n```\n\nExtract must include the same pepper:\n\n```bash\nsnow2 extract \\\n  --mode classic-trailing \\\n  --carrier out.txt \\\n  --out recovered.bin \\\n  --password \"pw\" \\\n  --pepper \"signal key\"\n```\n\n### Require pepper by policy\nThis forces \"password + pepper\" for anyone who tries to decrypt later:\n\n```bash\nsnow2 embed \\\n  --mode classic-trailing \\\n  --carrier carrier.txt \\\n  --out out.txt \\\n  --message \"hello\" \\\n  --password \"pw\" \\\n  --pepper \"signal key\" \\\n  --pepper-required\n```\n\nIf someone tries to extract without the pepper, it will fail.\n\n### Tune Argon2id (KDF)\nDefaults are reasonable for interactive use, but you can harden:\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `--kdf-mib` | 64 | Memory cost in MiB (min 8, max 512) |\n| `--kdf-iters` | 3 | Iterations / time cost (min 1, max 64) |\n| `--kdf-par` | 1 | Parallelism (min 1, max 16) |\n\nExample:\n\n```bash\nsnow2 embed \\\n  --mode classic-trailing \\\n  --carrier carrier.txt \\\n  --out out.txt \\\n  --message \"hello\" \\\n  --password \"pw\" \\\n  --pepper \"signal key\" \\\n  --pepper-required \\\n  --kdf-mib 128 \\\n  --kdf-iters 4 \\\n  --kdf-par 1\n```\n\n---\n\n## Container Format\n\nSNOW2 supports multiple container versions. The default is now **Version 4** (hardened).\n\n### Version 4 (hardened, default)\n\nStripped wire format — no magic bytes or header length on the wire:\n\n```\n[VERSION=4 (1)] [BINARY_HEADER (49)] [CIPHERTEXT]\n```\n\nThe 49-byte binary header contains:\n```\n[flags (1)] [m_cost_log2 (1)] [t_cost u16 LE (2)] [p_cost (1)] [salt (16)] [nonce (24)] [plaintext_len u32 LE (4)]\n```\n\nFlags byte: `bit 0` = pepper_required, `bit 1` = compressed, `bits 2-3` = mode, `bits 4-5` = AEAD algorithm, `bits 6-7` = reserved (must be zero).\n\nThe header is authenticated as AEAD additional data (AAD). Plaintext is optionally deflate-compressed before encryption.\n\nThe v4 embed pipeline wraps this further:\n```\ncontainer → [real_len u32 LE (4)][container][random_padding] → constant-size bucket\n→ outer AEAD (Argon2-derived key + XChaCha20-Poly1305) → raw bits → embed + random-fill ALL lines\n```\n\n### Version 1 (legacy classic)\n\n```\n[MAGIC \"SNOW2\" (5)] [VERSION=1 (1)] [HEADER_LEN u32 LE (4)] [HEADER_JSON] [CIPHERTEXT]\n```\n\nPassword-based, Argon2id → HKDF → XChaCha20-Poly1305 AEAD. Header JSON authenticated as AAD.\n\n### Version 3 (compact binary)\n\n```\n[MAGIC \"SNOW2\" (5)] [VERSION=3 (1)] [HEADER_LEN u32 LE (4)] [BINARY_HEADER (57)] [CIPHERTEXT]\n```\n\nSame crypto as v1, but uses a 57-byte binary header instead of JSON. Deflate-compressed on wire.\n\n### Version 2 (PQC)\n\n```\n[MAGIC] [VERSION=2] [HEADER_LEN] [HEADER_JSON] [SIG_LEN u16 LE] [SIGNATURE] [CIPHERTEXT]\n```\n\nHybrid Kyber1024 + XChaCha20-Poly1305, signed with Dilithium5.\n\n### Encrypted Secret Key Format (PQC)\n\n```\n[SNOW2EK\\0 (8)] [VERSION (1)] [SALT (16)] [NONCE (24)] [AEAD CIPHERTEXT]\n```\n\nVersion byte is authenticated as AEAD AAD alongside the magic, preventing downgrade attacks.\n\n### Backward Compatibility\n\nExtraction automatically detects the container version. V4 outer decryption is tried first; if it fails, the legacy CRC-framed path handles v1/v3 containers.\n\n---\n\n## Security Model\n\n### What SNOW2 protects against\n- **Passive observers**: Carrier text looks normal; payload is invisible\n- **Statistical analysis (v4)**: Embedded data is indistinguishable from uniform random noise (chi-squared ≈ 255); all carrier lines carry content — no detectable message boundary\n- **Wrong password/pepper**: AEAD authentication fails — no partial decryption\n- **Carrier tampering**: Outer + inner AEAD catch any modification; legacy CRC-32 catches stego corruption in old containers\n- **Header tampering**: Binary header is AEAD AAD — any modification causes auth failure\n- **Message length analysis (v4)**: Constant-size padding masks actual payload size\n- **KDF bounds**: Extraction-side bounds reject absurd KDF parameters from hostile containers\n- **Weak KDF at embed time**: Embedding validates KDF params against the same bounds\n- **Key file exposure**: PQC secret keys can be encrypted at rest with password-derived AEAD\n- **File permission leaks**: Sensitive files written with restricted permissions via atomic rename\n\n### What SNOW2 does NOT protect against\n- **Active carrier modification**: If someone can modify the carrier text (trim whitespace, normalize Unicode), extraction will fail. This is by design — integrity is mandatory.\n- **Carrier comparison**: If an adversary has both the original carrier and the modified carrier, they can diff the files and detect embedding. SNOW2 protects against single-file analysis, not differential analysis.\n- **Traffic analysis**: SNOW2 does not hide the fact that a file has been modified (file size changes, metadata, etc.)\n- **Guaranteed secure deletion**: File shredding is best-effort. SSDs, CoW filesystems, and journals may retain data.\n- **WASM security boundaries**: The browser demo uses zeroize-on-drop but cannot mlock memory\n\n### Important security caveats\n\n- **Trailing whitespace is fragile.** Most text editors (VS Code, vim, Sublime, etc.) have settings to strip trailing whitespace on save. Git hooks, linters, and formatting tools often do the same. If the carrier passes through any of these, embedded data is destroyed. This is inherent to whitespace steganography, not a SNOW2 bug.\n\n- **Zero-width Unicode is more resilient, but not bulletproof.** Zero-width characters (U+200B, U+200C) survive copy/paste in many contexts (browsers, rich-text editors, some messaging apps). However, Unicode normalization (NFC/NFD/NFKC/NFKD), some messaging platforms (Slack, Discord), and clipboard sanitizers may strip them.\n\n- **CRC-32 is not a cryptographic integrity check (legacy only).** In v1/v3 containers, the CRC-32 in the bitstream framing catches accidental corruption early. V4 containers use outer AEAD instead, which provides full cryptographic integrity over the entire bitstream.\n\n- **Shred/wipe is best-effort only.** On SSDs with wear-leveling, CoW filesystems (btrfs, ZFS), or journaling filesystems, overwritten data may persist. For high-assurance deletion, use full-disk encryption and destroy the key.\n\n- **PQC is optional and experimental.** Post-quantum crypto (Kyber1024 + Dilithium5) is available as an optional feature for users who want it. It is not the default identity of the tool. PQC containers are significantly larger (~10 KB overhead) and use different trust assumptions (keypair-based, not password-based).\n\n- **The browser/WASM demo is not the main security boundary.** It is a convenience UI for demonstration. In WASM, `mlock` is unavailable, and JavaScript's garbage collection may leave copies of sensitive data in memory.\n\n---\n\n## Building\n\n### Standard release binary\n```bash\ncargo build --release\n```\n\n### With PQC support\n```bash\ncargo build --release --features pqc\n```\n\n### Static Linux build (musl)\n```bash\nrustup target add x86_64-unknown-linux-musl\nsudo apt-get install -y musl-tools\ncargo build --release --target x86_64-unknown-linux-musl\n```\n\n### Run tests\n```bash\ncargo test -p snow2              # without PQC\ncargo test -p snow2 --features pqc  # with PQC\n```\n\n---\n\n## Browser / WASM Demo\n\nSNOW2 compiles to WebAssembly for fully client-side encryption in the browser.\n\nThe `web_demo/` folder contains a static web UI that loads the SNOW2 Rust core via WASM. It uses the `websafe-zw` mode (zero-width embedding), which is more tolerant of browser copy/paste behavior.\n\nFeatures:\n- Fully client-side — no server-side crypto, all processing in the browser\n- Configurable Argon2id KDF parameters\n- Pepper / Signal Key support with optional pepper-required policy\n- Carrier generation and download\n- Extract with UTF-8 preview and raw base64 data\n\n### Build the WASM package\n```bash\ncargo install wasm-pack\ncd snow2_wasm\nwasm-pack build --target web --out-dir web_demo/pkg\ncp -r web_demo/pkg ../web_demo/pkg\n```\n\n### Serve locally\n```bash\npython3 -m http.server 8000 -d web_demo\n```\n\nThen open http://localhost:8000.\n\n\u003e **Important:** The browser demo is convenience UI, not the security boundary. Users should understand whitespace normalization risks when copy/pasting. The WASM environment cannot use mlock and provides weaker memory protections than native builds.\n\n---\n\n## What has changed vs. original SNOW\n\nThe original SNOW (by Matthew Kwan, late 1990s) was a C program that:\n- Used ICE encryption (a block cipher by the same author)\n- Encoded data in trailing whitespace (tabs and spaces)\n- Ran on Unix and Windows\n- Was simple, elegant, and educational\n\nSNOW2 preserves the spirit but is a complete rewrite:\n- **Language**: Rust (memory-safe, no buffer overflows)\n- **Encryption**: Dual-layer AEAD — inner XChaCha20-Poly1305 (Argon2id key + pepper) + outer XChaCha20-Poly1305 (Argon2id key, password-only)\n- **Key derivation**: Argon2id + HKDF-SHA256 (memory-hard, domain-separated)\n- **Integrity**: Dual AEAD authentication (outer + inner), legacy CRC-32 for old containers\n- **Steg resistance**: Constant-size padding, random carrier fill, outer encryption makes bitstream indistinguishable from uniform random (chi-squared ≈ 255)\n- **Modes**: Classic trailing whitespace (tribute mode, 1 bit/line) + zero-width Unicode (web-friendly, 8 bits/line)\n- **Optional PQC**: Hybrid Kyber1024 + Dilithium5 post-quantum crypto\n- **Secure memory**: mlock'd buffers with dual guard pages, zeroize-on-drop, MADV_DONTDUMP\n\nWhat remains the same:\n- Text-steganography identity (\"hide in plain sight\")\n- Simplicity and educational clarity\n- Whitespace as the invisible channel\n- Single-binary CLI tool\n- The charm of hiding messages where nobody looks\n\n---\n\n## Project Structure\n\n```\nsrc/\n  main.rs             CLI entry point (clap)\n  lib.rs              Library API (embed / extract / embed_with_options)\n  config.rs           EmbedOptions, EmbedSecurityOptions, PqKeys\n  container.rs        SNOW2 container format v1/v3/v4 (seal / open / serialize / parse)\n  crypto.rs           AEAD, KDF (Argon2id + HKDF), outer encryption, random bytes\n  secure_mem.rs       SecureVec (mlock + guard pages on native, zeroize on WASM)\n  secure_fs.rs        Atomic writes, permission hardening, best-effort shredding\n  pqc.rs              Post-quantum crypto: Kyber1024 + Dilithium5 [optional]\n  stego/\n    mod.rs            Bit/byte conversion (raw + CRC-32 framing for legacy)\n    classic_trailing.rs   Trailing whitespace steganography (+ v4 random padding)\n    websafe_zw.rs         Zero-width Unicode steganography (+ v4 random padding)\nsnow2_wasm/           WASM crate for browser demo\n  src/lib.rs          wasm-bindgen bindings\nweb_demo/             Static web UI (HTML/CSS/JS + WASM pkg)\ntests/\n  roundtrip.rs        Classic embed/extract roundtrip tests\n  pepper_policy.rs    Pepper policy, KDF bounds, embed-side validation,\n                      malformed container rejection tests\n  pqc_roundtrip.rs    PQC keygen + embed/extract roundtrip test\n  negative_edge_cases.rs  Malformed input, corruption, boundary tests\n  cross_platform.rs   CRLF/LF, Unicode, platform survivability tests\nfuzz/\n  fuzz_targets/       Fuzz targets for container parse, bitstream, stego extract\nscripts/\n  make_carrier.sh     Helper to generate carrier files\n```\n\n---\n\n## Tribute\n\nOriginal SNOW was written by **Matthew Kwan** and released under the GNU GPL.\n\nSNOW2 is an independent modern rewrite created in admiration of that work. It does not reuse original code but preserves the idea, the elegance, and the educational spirit.\n\n\n---\n\n## License\n\nGPL-3.0-or-later\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsystemslibrarian%2Fsnow2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsystemslibrarian%2Fsnow2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsystemslibrarian%2Fsnow2/lists"}