# Technology Stack **Project:** encrypted_archive (Custom Encrypted Archiver) **Researched:** 2026-02-24 **Overall confidence:** MEDIUM (versions from training data — verify before use) --- ## Critical Constraint: Three-Platform Compatibility Every technology choice is constrained by the weakest link: **busybox shell**. The Rust archiver can use any library, but the format it produces must be decodable by: 1. Kotlin on Android 13 (javax.crypto / java.security) 2. busybox shell (openssl, dd, xxd) This constraint eliminates many otherwise-superior choices. --- ## Recommended Stack ### Encryption | Technology | Version | Purpose | Why | Confidence | |------------|---------|---------|-----|------------| | `aes` crate | ^0.8 | AES-256-CBC block cipher | busybox openssl supports `aes-256-cbc` — the critical three-way constraint. Android javax.crypto supports AES natively. | HIGH | | `cbc` crate | ^0.1 | CBC mode of operation | Standard mode: openssl CLI `aes-256-cbc`, javax.crypto `AES/CBC/PKCS5Padding` | HIGH | | `hmac` + `sha2` | ^0.12 / ^0.10 | HMAC-SHA256 integrity | Encrypt-then-MAC. busybox `openssl dgst -sha256 -hmac`. Kotlin `Mac("HmacSHA256")` | HIGH | **Why AES-256-CBC over AES-GCM:** busybox openssl does NOT support AEAD modes (GCM/CCM) in `openssl enc`. AES-CBC + HMAC-SHA256 (encrypt-then-MAC) provides equivalent security. CBC is the only AES mode reliably available across all three platforms. **Why NOT ChaCha20-Poly1305:** busybox openssl does not support ChaCha20. Android javax.crypto has no standard ChaCha20 support. Would require native libraries, violating constraints. **Why NOT aes-gcm crate:** Not decodable via `openssl enc` in busybox. ### Compression | Technology | Version | Purpose | Why | Confidence | |------------|---------|---------|-----|------------| | `flate2` crate | ^1.0 | gzip compression | busybox `gunzip` works natively. Android `GZIPInputStream` works natively. Simplest cross-platform path. | HIGH | **Why gzip-wrapped DEFLATE:** busybox `gunzip` handles it. Android `GZIPInputStream` handles it. flate2 `GzEncoder`/`GzDecoder` produces standard gzip. **Why NOT zstd/lz4/brotli:** busybox has no decompressors for any of these. ### CLI Framework | Technology | Version | Purpose | Why | Confidence | |------------|---------|---------|-----|------------| | `clap` | ^4 | CLI argument parsing | De facto Rust standard. Derive macros. Subcommands (`pack`/`unpack`/`inspect`). | HIGH | ### Binary Format | Technology | Version | Purpose | Why | Confidence | |------------|---------|---------|-----|------------| | Manual byte-level I/O | N/A | Custom binary format | Using bincode/serde would make format recognizable by forensic tools. Manual bytes give full control for obfuscation. | HIGH | ### Hashing / Integrity | Technology | Version | Purpose | Why | Confidence | |------------|---------|---------|-----|------------| | `sha2` crate | ^0.10 | SHA-256 checksums | busybox `sha256sum`, Android `MessageDigest("SHA-256")` | HIGH | ### Random / IV Generation | Technology | Version | Purpose | Why | Confidence | |------------|---------|---------|-----|------------| | `rand` | ^0.8 | Random IV generation | CSPRNG for AES-CBC initialization vectors. Each archive gets unique IV. | HIGH | ### Error Handling | Technology | Version | Purpose | Why | Confidence | |------------|---------|---------|-----|------------| | `anyhow` | ^1 | Application errors | CLI app, not library. Ergonomic error chains. | HIGH | | `thiserror` | ^2 | Typed format errors | Specific errors for format validation, decryption, integrity. | MEDIUM | ### Testing | Technology | Version | Purpose | Why | Confidence | |------------|---------|---------|-----|------------| | Built-in `#[test]` | N/A | Unit tests | Round-trip pack/unpack/compare | HIGH | | `assert_cmd` | ^2 | CLI integration tests | Test actual binary | MEDIUM | | `tempfile` | ^3 | Temp dirs | Clean test isolation | HIGH | --- ## Kotlin/Android Decompressor Stack (Zero External Dependencies) | Technology | Source | Purpose | |------------|--------|---------| | `javax.crypto.Cipher` | Android SDK | AES-256-CBC: `Cipher.getInstance("AES/CBC/PKCS5Padding")` | | `javax.crypto.spec.SecretKeySpec` | Android SDK | 32-byte hardcoded key | | `javax.crypto.spec.IvParameterSpec` | Android SDK | IV from archive header | | `javax.crypto.Mac` | Android SDK | HMAC-SHA256: `Mac.getInstance("HmacSHA256")` | | `java.util.zip.GZIPInputStream` | Android SDK | Gzip decompression | | `java.security.MessageDigest` | Android SDK | SHA-256 integrity | | `java.nio.ByteBuffer` | Android SDK | Little-endian parsing | --- ## Busybox Shell Decompressor Stack | Tool | Purpose | Key Flags | |------|---------|-----------| | `dd` | Extract byte ranges | `bs=1 skip=N count=M` | | `xxd` | Hex encode/decode keys | `xxd -p` | | `openssl enc` | AES-256-CBC decrypt | `-d -aes-256-cbc -K HEX -iv HEX -nosalt` | | `openssl dgst` | HMAC-SHA256 verify | `-sha256 -hmac KEY -binary` | | `gunzip` | Gzip decompress | Standard input/output | | `sha256sum` | Integrity check | `-c checksums` | **Critical:** busybox `openssl enc` uses EVP_BytesToKey by default. MUST pass `-K` (hex key) + `-iv` (hex IV) + `-nosalt` for raw key mode. IV must be in cleartext header. --- ## Cross-Platform Compatibility Matrix | Rust | Android SDK | busybox | Notes | |------|-------------|---------|-------| | `aes`+`cbc` (PKCS7) | `Cipher("AES/CBC/PKCS5Padding")` | `openssl enc -aes-256-cbc` | PKCS5=PKCS7 for 16-byte blocks | | `hmac`+`sha2` | `Mac("HmacSHA256")` | `openssl dgst -sha256 -hmac` | Raw key, not password | | `flate2` (GzEncoder) | `GZIPInputStream` | `gunzip` | Standard gzip | | `sha2` | `MessageDigest("SHA-256")` | `sha256sum` | Hex comparison | --- ## Alternatives Considered | Category | Recommended | Alternative | Why Not | |----------|-------------|-------------|---------| | Encryption | AES-256-CBC + HMAC | AES-256-GCM | busybox openssl lacks GCM | | Encryption | AES-256-CBC + HMAC | ChaCha20-Poly1305 | Not in busybox/Android SDK | | Compression | flate2 (gzip) | zstd | No busybox decompressor | | Compression | flate2 (gzip) | lz4 | No busybox decompressor | | Format | Manual bytes | bincode/serde | Recognizable patterns | | Crypto ecosystem | RustCrypto (aes+cbc) | ring | ring bundles C code | | Crypto ecosystem | RustCrypto (aes+cbc) | openssl-rs | Unnecessary system dep | --- ## Cargo.toml ```toml [package] name = "encrypted_archive" version = "0.1.0" edition = "2021" [dependencies] aes = "0.8" cbc = "0.1" hmac = "0.12" sha2 = "0.10" flate2 = "1.0" clap = { version = "4", features = ["derive"] } rand = "0.8" anyhow = "1" thiserror = "2" [dev-dependencies] assert_cmd = "2" tempfile = "3" ``` **WARNING: Versions from training data (cutoff May 2025). Verify with `cargo search CRATE --limit 1` before use.** --- ## Gaps Requiring Verification 1. Exact latest crate versions (could not verify via crates.io) 2. Confirm target busybox build includes `openssl` applet 3. Confirm `xxd` availability in target busybox (fallback: `od`) 4. Test PKCS7 padding round-trip across all three platforms 5. Test flate2 GzEncoder output with busybox `gunzip` and Android `GZIPInputStream`