diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/README.md b/README.md new file mode 100644 index 0000000..18e121f --- /dev/null +++ b/README.md @@ -0,0 +1,224 @@ +# encrypted_archive + +[Русская версия (README_ru.md)](README_ru.md) + +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 + +```bash +# 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 ... -o [--no-compress ...] +``` + +| Argument | Description | +|----------|-------------| +| `...` | 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. + +```bash +# 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 [-o ] +``` + +| Argument | Description | +|----------|-------------| +| `` | Archive file to extract | +| `-o, --output-dir` | Output directory (default: `.`) | + +### `inspect` — View metadata + +``` +encrypted_archive inspect +``` + +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:** + +```bash +# 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()`: + +```kotlin +// 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**. + +```bash +sh shell/decode.sh archive.bin ./output/ +``` + +**Requirements:** `dd`, `openssl`, `sha256sum`, `gunzip`, and either `xxd` or `od`. + +> **Note:** This decoder requires `openssl` for 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](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 + +```bash +# Debug build +cargo build + +# Release build (optimized) +cargo build --release + +# Run all tests (unit + integration + golden vectors) +cargo test +``` + +### Running Cross-Validation Tests + +```bash +# 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 diff --git a/README_ru.md b/README_ru.md new file mode 100644 index 0000000..1f46a3b --- /dev/null +++ b/README_ru.md @@ -0,0 +1,222 @@ +# encrypted_archive + +Собственный формат зашифрованного архива, **неопознаваемый** стандартными инструментами анализа (`file`, `binwalk`, `strings`, hex-редакторы). + +## Возможности + +- **AES-256-CBC** шифрование с уникальным случайным IV для каждого файла +- **HMAC-SHA-256** аутентификация (IV || шифротекст) +- **GZIP-сжатие** с интеллектуальным определением (пропускает уже сжатые форматы) +- **XOR-обфускация заголовка** — нет узнаваемых magic bytes +- **Зашифрованная таблица файлов** — метаданные невидимы в hex-дампе +- **Обманные вставки (decoy padding)** — случайные 64–4096 байт между блоками данных +- **Три декодера**: Rust (нативный CLI), Kotlin (JVM/Android), Shell (POSIX) + +## Быстрый старт + +```bash +# Сборка +cargo build --release + +# Запаковать файлы в архив +./target/release/encrypted_archive pack file1.txt photo.jpg -o archive.bin + +# Просмотреть метаданные (без распаковки) +./target/release/encrypted_archive inspect archive.bin + +# Распаковать файлы +./target/release/encrypted_archive unpack archive.bin -o ./output/ +``` + +## Команды CLI + +### `pack` — Создание зашифрованного архива + +``` +encrypted_archive pack ... -o [--no-compress ...] +``` + +| Аргумент | Описание | +|----------|----------| +| `...` | Один или несколько файлов для архивации | +| `-o, --output` | Путь к выходному архиву | +| `--no-compress` | Не сжимать файлы, соответствующие шаблону (суффикс или точное имя) | + +Сжатие применяется автоматически. Уже сжатые форматы (`.zip`, `.gz`, `.jpg`, `.png`, `.mp3`, `.mp4`, `.apk` и др.) сохраняются без повторной компрессии. + +```bash +# Упаковка с управлением сжатием +encrypted_archive pack app.apk config.json -o bundle.bin --no-compress "app.apk" +``` + +### `unpack` — Распаковка файлов + +``` +encrypted_archive unpack [-o ] +``` + +| Аргумент | Описание | +|----------|----------| +| `` | Файл архива для распаковки | +| `-o, --output-dir` | Директория для извлечения (по умолчанию: `.`) | + +### `inspect` — Просмотр метаданных + +``` +encrypted_archive inspect +``` + +Отображает поля заголовка, количество файлов, размеры, статус сжатия и хэши целостности — без извлечения содержимого. + +## Декодеры + +Архив может быть декодирован тремя независимыми реализациями. Все дают **побайтно идентичный** результат из одного и того же архива. + +### Rust (нативный CLI) + +Основная реализация. Используется через подкоманду `unpack` (см. выше). + +### Kotlin (JVM / Android) + +Однофайловый декодер для JVM-окружений. Без внешних зависимостей — использует `javax.crypto` и `java.util.zip` из стандартной библиотеки. + +**Автономное использование:** + +```bash +# Компиляция +kotlinc kotlin/ArchiveDecoder.kt -include-runtime -d ArchiveDecoder.jar + +# Декодирование +java -jar ArchiveDecoder.jar archive.bin ./output/ +``` + +**Как библиотека в Android-проекте:** + +Скопируйте `kotlin/ArchiveDecoder.kt` в исходники вашего проекта. Все используемые криптографические и компрессионные API (`javax.crypto.Cipher`, `javax.crypto.Mac`, `java.util.zip.GZIPInputStream`) доступны в Android SDK. + +Для использования как библиотеки вызывайте логику декодирования напрямую вместо `main()`: + +```kotlin +// Пример: декодирование из файла +val archive = File("/path/to/archive.bin") +val outputDir = File("/path/to/output") +decode(archive, outputDir) + +// Функция decode() выполняет: +// 1. XOR-деобфускацию заголовка +// 2. Расшифровку таблицы файлов (TOC) +// 3. AES-расшифровку + HMAC-верификацию каждого файла +// 4. GZIP-декомпрессию (если файл сжат) +// 5. Проверку целостности по SHA-256 +``` + +Нативный `.so` не требуется — чистый Kotlin/JVM, работает на ART. + +### Shell (POSIX) + +Аварийный декодер для POSIX-систем **с установленным OpenSSL**. + +```bash +sh shell/decode.sh archive.bin ./output/ +``` + +**Зависимости:** `dd`, `openssl`, `sha256sum`, `gunzip` и `xxd` или `od`. + +> **Важно:** Этот декодер требует `openssl` для операций AES и HMAC. Он **не будет работать** в минимальных окружениях типа BusyBox, где OpenSSL отсутствует. Для ограниченных сред используйте Rust- или Kotlin-декодер. + +## Спецификация формата + +Полная спецификация бинарного формата: **[docs/FORMAT.md](docs/FORMAT.md)** + +### Структура архива (обзор) + +``` +┌──────────────────────────────┐ смещение 0 +│ Заголовок (40 байт, XOR) │ magic, версия, флаги, toc_offset, toc_size, toc_iv, кол-во файлов +├──────────────────────────────┤ смещение 40 +│ TOC (зашифрован AES-CBC) │ записи файлов: имя, размеры, смещения, IV, HMAC, SHA-256 +├──────────────────────────────┤ +│ Блок данных 0 │ AES-256-CBC(GZIP(открытый текст)) +│ Обманная вставка (случайная)│ 64–4096 случайных байт +├──────────────────────────────┤ +│ Блок данных 1 │ +│ Обманная вставка (случайная)│ +├──────────────────────────────┤ +│ ... │ +└──────────────────────────────┘ +``` + +### Байт флагов + +| Бит | Маска | Функция | +|-----|-------|---------| +| 0 | `0x01` | Хотя бы один файл GZIP-сжат | +| 1 | `0x02` | TOC зашифрован AES-256-CBC | +| 2 | `0x04` | Заголовок XOR-обфусцирован | +| 3 | `0x08` | Обманные вставки между блоками данных | + +Стандартные архивы со всеми функциями: флаги = `0x0F`. + +## Модель безопасности + +**Что обеспечивается:** +- Конфиденциальность — AES-256-CBC шифрование каждого файла +- Целостность — HMAC-SHA-256 для каждого файла (encrypt-then-MAC) +- Верификация содержимого — SHA-256 хэш оригинального открытого текста +- Защита от анализа — никаких узнаваемых паттернов для `file`, `binwalk`, `strings` + +**Что НЕ обеспечивается:** +- Управление ключами — v1 использует зашитый ключ (v2 будет использовать подключи через HKDF) +- Прямая секретность (forward secrecy) +- Защита от целевого криптоанализа (XOR-ключ фиксирован и публичен) + +Слой обфускации рассчитан на противодействие **поверхностному анализу**, а не целенаправленному исследователю, знакомому с форматом. + +## Сборка из исходников + +```bash +# Отладочная сборка +cargo build + +# Релизная сборка (оптимизированная) +cargo build --release + +# Запуск всех тестов (юнит + интеграция + golden vectors) +cargo test +``` + +### Кросс-валидационные тесты + +```bash +# Тесты Kotlin-декодера (требуется kotlinc + java) +bash kotlin/test_decoder.sh + +# Тесты Shell-декодера (требуется openssl + sha256sum) +bash shell/test_decoder.sh +``` + +## Структура проекта + +``` +encrypted_archive/ +├── src/ +│ ├── main.rs # Точка входа CLI +│ ├── cli.rs # Определение аргументов (Clap) +│ ├── archive.rs # Упаковка / распаковка / инспекция +│ ├── format.rs # Сериализация бинарного формата +│ ├── crypto.rs # AES-256-CBC, HMAC-SHA-256, SHA-256 +│ ├── compression.rs # GZIP + определение сжатых форматов +│ └── key.rs # Криптографический ключ +├── kotlin/ +│ └── ArchiveDecoder.kt # JVM/Android-декодер (один файл) +├── shell/ +│ └── decode.sh # POSIX shell-декодер +├── docs/ +│ └── FORMAT.md # Спецификация бинарного формата (нормативная) +└── tests/ + └── golden_vectors.rs # Тесты с известными ответами +``` + +## Лицензия + +TBD diff --git a/kotlin/ArchiveDecoder.jar b/kotlin/ArchiveDecoder.jar new file mode 100644 index 0000000..e4b79f6 Binary files /dev/null and b/kotlin/ArchiveDecoder.jar differ