From d4c4ba8d8d6f189ee6613eabaa4ea390838443bf Mon Sep 17 00:00:00 2001 From: Jujuforce Date: Sun, 22 Mar 2026 13:53:52 +0100 Subject: [PATCH] docs: add README Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..53b7217 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# fsdecrypt + +Decryptor and extractor for SEGA arcade filesystem containers (fscrypt format). + +Handles AES-128-CBC encrypted container images used on SEGA Nu/ALLS arcade hardware, automatically parsing the embedded BootID header to identify the game and container type, then decrypting and extracting the contents. + +## Features + +- Decrypts OS, APP, and OPTION (DLC) containers +- Extracts NTFS-based containers (OS/APP) including internal VHD images +- Extracts ExFAT-based containers (OPTION/DLC packs) +- Preserves file timestamps during extraction +- Built-in key database for 70+ game titles +- Supports external key files for unlisted games +- Progress bars with transfer speed and ETA + +## Installation + +Requires [Rust](https://www.rust-lang.org/tools/install) 1.56+ (edition 2021). + +```bash +cargo build --release +``` + +The binary will be at `target/release/fsdecrypt` (or `fsdecrypt.exe` on Windows). + +## Usage + +``` +fsdecrypt [OPTIONS] ... +``` + +### Arguments + +- `...` - One or more encrypted container files (`.app`, `.opt`, etc.) + +### Options + +- `--no-extract` - Decrypt the container to a raw image file without extracting its contents +- `-h, --help` - Print help +- `-V, --version` - Print version + +### Examples + +```bash +# Decrypt and extract an APP container +fsdecrypt SDXX_1.00.00_20240101120000_0.app + +# Decrypt and extract an OPTION container +fsdecrypt SDXX_A001_20240101120000_0.opt + +# Process multiple containers at once +fsdecrypt game_v1.app game_v2.app extras.opt + +# Decrypt only, skip extraction +fsdecrypt --no-extract SDXX_1.00.00_20240101120000_0.app +``` + +### Output + +By default, the tool extracts container contents directly: + +| Type | Extracted contents | +|--------|--------------------| +| OS | `internal_{seq}.vhd` | +| APP | `internal_{seq}.vhd` | +| OPTION | Directory with all DLC files | + +With `--no-extract`, a raw decrypted image is written instead: + +| Type | Output filename | +|--------|-----------------| +| OS | `{os_id}_{version}_{timestamp}_{seq}.ntfs` | +| APP | `{game_id}_{version}_{timestamp}_{seq}.ntfs` | +| OPTION | `{game_id}_{option}_{timestamp}_{seq}.exfat` | + +## External Key Files + +For games not in the built-in database, place a key file named `{GAME_ID}.bin` in the working directory: + +- **16 bytes**: AES-128 key only (IV will be derived automatically) +- **32 bytes**: AES-128 key (first 16 bytes) + IV (last 16 bytes) + +## How It Works + +1. The first 128 bytes of the container are decrypted using a hardcoded master key to obtain the **BootID** header +2. The BootID contains metadata: game ID, container type, block layout, and an IV mode flag +3. The game-specific AES-128 key is looked up from the built-in database (or read from an external `.bin` file) +4. If no IV is hardcoded or the container uses a custom IV, the IV is derived by trial-decrypting the first data page against the expected filesystem header (NTFS or ExFAT magic bytes) +5. Each 4096-byte page is decrypted independently using AES-128-CBC, with a per-page IV computed by XORing the file IV with the page's file offset +6. The decrypted stream is parsed as NTFS or ExFAT depending on container type, and contents are extracted + +## Container Types + +| Type | ID | Filesystem | Description | +|------|----|-----------|-------------| +| OS | `0x00` | NTFS | Operating system image | +| APP | `0x01` | NTFS | Game application and assets | +| OPTION | `0x02` | ExFAT | Downloadable content / option packs | + +## License + +[BSD Zero Clause License](LICENSE) (0BSD)