docs: add README

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jujuforce
2026-03-22 16:39:52 +01:00
co-authored by Claude Opus 4.6
parent 49e24c0ee4
commit d4c4ba8d8d
+103
View File
@@ -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] <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
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)