- Bump VERSION constant from 1 to 2 - Add entry_type (u8) and permissions (u16) fields to TocEntry struct - Update write_toc_entry/read_toc_entry for new field order after name - Update entry_size formula from 101 to 104 + name_length - Update all unit tests for v1.1 layout (new fields, version 2, sizes) - Add placeholder entry_type/permissions to archive.rs ProcessedFile for compilation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
encrypted_archive
Custom encrypted archive format designed to be unrecognizable by standard analysis tools (file, binwalk, strings, hex editors).
Features
- AES-256-CBC encryption with per-file random IVs
- HMAC-SHA-256 authentication (IV || ciphertext)
- GZIP compression with smart detection (skips already-compressed formats)
- XOR-obfuscated headers — no recognizable magic bytes
- Encrypted file table — metadata invisible in hex dumps
- Decoy padding — random 64–4096 bytes between data blocks
- Three decoders: Rust (native CLI), Kotlin (JVM/Android), Shell (POSIX)
Quick Start
# Build
cargo build --release
# Pack files into an archive
./target/release/encrypted_archive pack file1.txt photo.jpg -o archive.bin
# Inspect metadata (without extracting)
./target/release/encrypted_archive inspect archive.bin
# Extract files
./target/release/encrypted_archive unpack archive.bin -o ./output/
CLI Reference
pack — Create an encrypted archive
encrypted_archive pack <FILES>... -o <OUTPUT> [--no-compress <PATTERNS>...]
| Argument | Description |
|---|---|
<FILES>... |
One or more files to archive |
-o, --output |
Output archive path |
--no-compress |
Skip compression for matching filenames (suffix or exact match) |
Compression is automatic for most files. Already-compressed formats (.zip, .gz, .jpg, .png, .mp3, .mp4, .apk, etc.) are stored without recompression.
# Pack with selective compression control
encrypted_archive pack app.apk config.json -o bundle.bin --no-compress "app.apk"
unpack — Extract files
encrypted_archive unpack <ARCHIVE> [-o <DIR>]
| Argument | Description |
|---|---|
<ARCHIVE> |
Archive file to extract |
-o, --output-dir |
Output directory (default: .) |
inspect — View metadata
encrypted_archive inspect <ARCHIVE>
Displays header fields, file count, per-file sizes, compression status, and integrity hashes without extracting content.
Decoders
The archive can be decoded by three independent implementations. All produce byte-identical output from the same archive.
Rust (native CLI)
The primary implementation. Used via unpack subcommand (see above).
Kotlin (JVM / Android)
Single-file decoder for JVM environments. No external dependencies — uses javax.crypto and java.util.zip from the standard library.
Standalone usage:
# Compile
kotlinc kotlin/ArchiveDecoder.kt -include-runtime -d ArchiveDecoder.jar
# Decode
java -jar ArchiveDecoder.jar archive.bin ./output/
As a library in an Android project:
Copy kotlin/ArchiveDecoder.kt into your project source tree. All crypto and compression APIs (javax.crypto.Cipher, javax.crypto.Mac, java.util.zip.GZIPInputStream) are available in the Android SDK.
To use as a library, call the decoding logic directly instead of main():
// Example: decode from a file
val archive = File("/path/to/archive.bin")
val outputDir = File("/path/to/output")
decode(archive, outputDir)
// The decode() function handles:
// 1. XOR header de-obfuscation
// 2. TOC decryption
// 3. Per-file AES decryption + HMAC verification
// 4. GZIP decompression (if compressed)
// 5. SHA-256 integrity check
No native .so required — pure Kotlin/JVM running on ART.
Shell (POSIX)
Emergency decoder for POSIX systems with OpenSSL installed.
sh shell/decode.sh archive.bin ./output/
Requirements: dd, openssl, sha256sum, gunzip, and either xxd or od.
Note: This decoder requires
opensslfor AES and HMAC operations. It will not work on minimal environments like BusyBox that lack OpenSSL. For constrained environments, use the Rust or Kotlin decoder instead.
Format Specification
Full binary format specification: docs/FORMAT.md
Archive Layout (summary)
┌──────────────────────────┐ offset 0
│ Header (40 bytes, XOR) │ magic, version, flags, toc_offset, toc_size, toc_iv, file_count
├──────────────────────────┤ offset 40
│ TOC (encrypted AES-CBC) │ file entries: name, sizes, offsets, IV, HMAC, SHA-256
├──────────────────────────┤
│ Data Block 0 │ AES-256-CBC(GZIP(plaintext))
│ Decoy Padding (random) │ 64–4096 random bytes
├──────────────────────────┤
│ Data Block 1 │
│ Decoy Padding (random) │
├──────────────────────────┤
│ ... │
└──────────────────────────┘
Flags Byte
| Bit | Mask | Feature |
|---|---|---|
| 0 | 0x01 |
At least one file is GZIP-compressed |
| 1 | 0x02 |
TOC is AES-256-CBC encrypted |
| 2 | 0x04 |
Header is XOR-obfuscated |
| 3 | 0x08 |
Decoy padding between data blocks |
Standard archives with all features: flags = 0x0F.
Security Model
What this provides:
- Confidentiality — AES-256-CBC encryption per file
- Integrity — HMAC-SHA-256 per file (encrypt-then-MAC)
- Content verification — SHA-256 hash of original plaintext
- Anti-analysis — no recognizable patterns for
file,binwalk,strings
What this does NOT provide:
- Key management — v1 uses a hardcoded key (v2 will use HKDF-derived subkeys)
- Forward secrecy
- Protection against targeted cryptanalysis (the XOR key is fixed and public)
The obfuscation layer is designed to resist casual analysis, not a determined adversary with knowledge of the format.
Building from Source
# Debug build
cargo build
# Release build (optimized)
cargo build --release
# Run all tests (unit + integration + golden vectors)
cargo test
Running Cross-Validation Tests
# Kotlin decoder tests (requires kotlinc + java)
bash kotlin/test_decoder.sh
# Shell decoder tests (requires openssl + sha256sum)
bash shell/test_decoder.sh
Project Structure
encrypted_archive/
├── src/
│ ├── main.rs # CLI entry point
│ ├── cli.rs # Clap argument definitions
│ ├── archive.rs # Pack / unpack / inspect
│ ├── format.rs # Binary format serialization
│ ├── crypto.rs # AES-256-CBC, HMAC-SHA-256, SHA-256
│ ├── compression.rs # GZIP + smart format detection
│ └── key.rs # Cryptographic key
├── kotlin/
│ └── ArchiveDecoder.kt # JVM/Android decoder (single file)
├── shell/
│ └── decode.sh # POSIX shell decoder
├── docs/
│ └── FORMAT.md # Binary format specification (normative)
└── tests/
└── golden_vectors.rs # Known-answer tests
License
TBD