docs: simplify README, reflect pure Rust extraction

Remove technical implementation details, keep it user-friendly.
Document delta update auto-detection, output folder naming,
and cross-platform support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jujuforce
2026-03-22 16:40:18 +01:00
co-authored by Claude Opus 4.6
parent 068badad7e
commit b0e97f8b00
+19 -78
View File
@@ -1,23 +1,10 @@
# 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)
- **Auto-merges delta update VHDs** with their base on Windows (Hyper-V)
- 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
Decryptor and extractor for SEGA arcade filesystem containers (fscrypt format). Works on Windows and Linux, no admin privileges required.
## Installation
Requires [Rust](https://www.rust-lang.org/tools/install) 1.56+ (edition 2021).
Requires [Rust](https://www.rust-lang.org/tools/install).
```bash
cargo build --release
@@ -27,94 +14,48 @@ The binary will be at `target/release/fsdecrypt` (or `fsdecrypt.exe` on Windows)
## Usage
```bash
fsdecrypt <FILES>...
```
fsdecrypt [OPTIONS] <FILES>...
```
### Arguments
- `<FILES>...` - 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
# Extract a game APP container
fsdecrypt ABCD_1.00.00_20240101120000_0.app
# Decrypt and extract an OPTION container
# Extract an OPTION/DLC container
fsdecrypt ABCD_A001_20240101120000_0.opt
# Process multiple containers at once
# Extract multiple files at once
fsdecrypt game_v1.app game_v2.app extras.opt
# Decrypt only, skip extraction
# Decrypt only (outputs raw .ntfs/.exfat image, no extraction)
fsdecrypt --no-extract ABCD_1.00.00_20240101120000_0.app
```
### Delta Updates
When a game ships incremental updates, you get a base `.app` (seq=0) and one or more delta `.app` files (seq>0). Pass them all together and fsdecrypt handles the rest:
Games often ship incremental updates as a separate `.app` file. Just pass the update file — fsdecrypt will automatically find the base in the same folder and merge them:
```bash
fsdecrypt ABCD_1.01.00_20240215143000_1_1.00.00.app
```
You can also pass both explicitly:
```bash
# Base + delta update: fsdecrypt extracts both VHDs, then auto-merges
fsdecrypt ABCD_1.00.00_20240101120000_0.app ABCD_1.01.00_20240215143000_1_1.00.00.app
```
The merge workflow (Windows only, requires Hyper-V):
1. Both containers are decrypted and their internal VHDs extracted
2. `Set-VHD` links the delta (differencing) VHD to its parent
3. `Merge-VHD` merges the delta into the base VHD
4. A UAC prompt will appear since these cmdlets require elevation
If you only provide the delta without its base, fsdecrypt will extract the VHD and print a warning with instructions.
### Output
By default, the tool extracts container contents directly:
| Type | Extracted contents |
|--------|--------------------|
| OS | `internal_{seq}.vhd` |
| APP | `internal_{seq}.vhd` (auto-merged if delta + base provided) |
| 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` |
The output folder is named after the input file (e.g. `ABCD_1.01.00_20240215143000_1_1.00.00/`).
## External Key Files
For games not in the built-in database, place a key file named `{GAME_ID}.bin` in the working directory:
For games not in the built-in key database, place a 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 |
- **16 bytes** for key only (IV derived automatically)
- **32 bytes** for key + IV
## License