Skip to content

jbaelaw/qshield

Repository files navigation

QShield
Post-Quantum Hybrid Encryption for Files, Directories, and Whole Disks

CI Release License Language Platform


QShield encrypts files, directories, and raw disk images / block devices into .qsv archives using a hybrid post-quantum key encapsulation scheme. A single password protects everything—no PKI infrastructure, no key servers, no certificate management.

  ╔═══════════════════════════════════════════════════╗
  ║    QShield — Post-Quantum Storage Encryption      ║
  ║    ML-KEM-768 + X25519 │ AES-256-GCM              ║
  ╚═══════════════════════════════════════════════════╝

Why QShield?

Concern QShield's Answer
Quantum threat ML-KEM-768 (NIST FIPS 203, Security Level 3) — resistant to Shor's algorithm on future quantum computers
Classical fallback X25519 ECDH in hybrid mode — if ML-KEM is ever broken classically, X25519 still protects the key
Password-only Argon2id stretches a single password into all key material — no key files, no certificates
Whole-disk support encrypt-disk / decrypt-disk stream raw bytes with zero memory buffering — handles multi-TB external drives
Single binary Statically linked Rust binary, ~3 MB, no runtime dependencies
Cross-platform macOS (Apple Silicon + Intel), Linux x86_64, Windows x64

Threat Model

QShield is designed to protect data at rest on portable storage media (external HDDs, USB drives, backup images) against:

  • Harvest-now, decrypt-later attacks — adversaries who capture encrypted data today and attempt decryption with future quantum computers
  • Offline brute-force — Argon2id with 64 MiB memory cost makes GPU/ASIC attacks prohibitively expensive
  • Key compromise of a single primitive — hybrid KEM ensures that both ML-KEM-768 and X25519 must be broken simultaneously

Out of scope: QShield does not provide real-time full-disk encryption (like LUKS/BitLocker), plausible deniability, or protection against an adversary with live access to a running system.

Install

Prebuilt Binaries

Download from the releases page:

Platform Architecture File SHA-256
macOS Apple Silicon (M1/M2/M3/M4) qshield-macos-aarch64.tar.gz .sha256
macOS Intel x86_64 qshield-macos-x86_64.tar.gz .sha256
Linux x86_64 (glibc) qshield-linux-x86_64.tar.gz .sha256
Windows x86_64 qshield-windows-x86_64.zip .sha256
# macOS / Linux
tar xzf qshield-macos-aarch64.tar.gz
sudo mv qshield /usr/local/bin/
qshield --version

# Windows (PowerShell)
Expand-Archive qshield-windows-x86_64.zip -DestinationPath .
.\qshield.exe --version

Build from Source

Requires Rust 1.74 or later:

git clone https://github.com/jbaelaw/qshield.git
cd qshield
cargo build --release
# Binary at target/release/qshield

Verify Download Integrity

Each release includes SHA-256 checksums:

shasum -a 256 -c qshield-macos-aarch64.tar.gz.sha256

Usage

Interactive TUI Mode

Launch the terminal UI by running qshield without arguments:

qshield

The TUI provides a menu-driven interface with:

Feature Description
Encrypt File/Folder Archive and encrypt files or directories
Decrypt File/Folder Decrypt and extract .qsv archives
Encrypt Disk (Raw) Encrypt disk images or block devices byte-for-byte
Decrypt Disk (Raw) Restore encrypted disk images to exact original
Verify Check archive integrity without extracting
Info Display cryptographic metadata

All operations show real-time progress bars and masked password input.

CLI — File and Folder Encryption

# Encrypt a file (interactive password prompt)
qshield encrypt secret.pdf

# Encrypt a directory with explicit output path
qshield encrypt ./confidential/ -o confidential.qsv

# Overwrite existing output
qshield encrypt ./docs/ -o docs.qsv --force

# Decrypt to a specific directory
qshield decrypt docs.qsv -o ./restored/

# Non-interactive mode (scripting / automation)
qshield encrypt data.zip -p "strong-passphrase-here" -o data.qsv
qshield decrypt data.qsv --password "strong-passphrase-here" -o ./output

# Verify integrity without extracting
qshield verify data.qsv --password "strong-passphrase-here"

# Inspect cryptographic metadata
qshield info data.qsv

CLI — Whole-Disk / Block Device Encryption

Encrypt raw disk images and block devices with streaming I/O — no tar wrapping, no in-memory buffering, byte-exact restore:

# Encrypt a disk image file
qshield encrypt-disk /path/to/backup.img -o backup.qsv

# macOS: encrypt an external drive (UNMOUNT FIRST)
diskutil unmountDisk /dev/disk4
sudo qshield encrypt-disk /dev/disk4 -o external_hdd.qsv

# Linux: encrypt a USB drive
sudo umount /dev/sdb
sudo qshield encrypt-disk /dev/sdb -o usb_drive.qsv

# Decrypt to an image file
qshield decrypt-disk backup.qsv -o restored.img --force

# Decrypt directly to a block device (CAUTION: overwrites entire device)
sudo qshield decrypt-disk external_hdd.qsv -o /dev/disk4 --force

# Verify and inspect
qshield verify backup.qsv --password "passphrase"
qshield info backup.qsv

Disk mode safety features:

Feature Description
Block device detection Automatic identification via OS file type metadata
Unmount warning Prompts user to unmount before reading/writing devices
Interactive confirmation Requires explicit y before device operations
Byte-exact restore Original size stored in header — no padding artifacts
Platform-native sizing macOS diskutil, Linux blockdev, seek-to-end fallback
Cross-command guard decrypt rejects raw disk files (suggests decrypt-disk)

Supported Input Types

QShield encrypts any file, directory, or block device. Automatic type detection provides human-readable descriptions:

Category Extensions / Types
Disk images .iso, .img, .dmg, .vhd, .vhdx, .vmdk, .qcow2
Archives .zip, .tar, .gz, .bz2, .xz, .zst, .7z, .rar
Documents .pdf, .doc(x), .xls(x), .ppt(x), .txt, .csv
Media .jpg, .png, .gif, .mp4, .mkv, .mp3, .flac, .wav
Data .json, .xml, .html, .sql, .db, .sqlite
Executables .exe, .dll, .so, .dylib, .bin
Crypto .key, .pem, .crt, .p12, .gpg
Directories Any folder (recursively archived via tar)
Block devices /dev/diskN (macOS), /dev/sdX (Linux) — via encrypt-disk

All inputs are treated as opaque byte streams — QShield never parses or modifies file contents.

Cryptographic Architecture

Key Derivation and Encapsulation Flow

                          ┌─────────────┐
                          │  Password   │
                          └──────┬──────┘
                                 │
                          Argon2id (64 MiB, 3 iter, 4 lanes)
                                 │
                          ┌──────▼──────┐
                          │ Master Key  │──────┐
                          │  (256-bit)  │      │
                          └──────┬──────┘      │
                                 │         Encrypts KEM
                    ┌────────────┴────────────┐ private keys
                    │                         │ (AES-256-GCM)
             ┌──────▼──────┐          ┌───────▼───────┐
             │  ML-KEM-768 │          │  X25519 ECDH  │
             │  (FIPS 203) │          │  (RFC 7748)   │
             └──────┬──────┘          └───────┬───────┘
                    │ shared secret           │ shared secret
                    └────────────┬────────────┘
                                 │
                          HKDF-SHA3-256 (SP 800-56C)
                                 │
                          ┌──────▼──────┐
                          │ Volume Key  │
                          │  (256-bit)  │
                          └──────┬──────┘
                                 │
                          AES-256-GCM (SP 800-38D)
                          1 MiB streaming chunks
                                 │
                          ┌──────▼──────┐
                          │  Encrypted  │
                          │    Data     │
                          └─────────────┘

Algorithm Selection Rationale

Layer Algorithm Standard Security Level Rationale
PQ Key Encapsulation ML-KEM-768 NIST FIPS 203 Level 3 (AES-192 equivalent) First NIST-standardized lattice-based KEM; balanced security/performance
Classical Key Agreement X25519 RFC 7748 ~128-bit classical Widely deployed, constant-time, no patents; hybrid fallback if lattice assumptions fail
Key Combination HKDF-SHA3-256 SP 800-56C 256-bit Domain-separated extraction ensures independence of KEM contributions
Password Stretching Argon2id RFC 9106 Memory-hard 64 MiB memory cost defeats GPU/ASIC parallelism; hybrid side-channel resistance
Bulk Encryption AES-256-GCM SP 800-38D 256-bit Hardware-accelerated (AES-NI), authenticated encryption with per-chunk nonces

Hybrid KEM Design

The hybrid construction follows the combiner approach recommended by NIST for transitional post-quantum deployments:

  1. Independent key generation — ML-KEM-768 and X25519 keypairs are generated independently
  2. Independent encapsulation — each KEM produces its own shared secret
  3. Domain-separated combination — HKDF-SHA3-256 combines both secrets with distinct context labels
  4. Defense-in-depth — compromise of either primitive alone does not reveal the volume key

This ensures security under the assumption that at least one of the two KEM primitives remains secure.

Streaming Encryption

Bulk data is encrypted in 1 MiB chunks with per-chunk authenticated encryption:

For each chunk i:
  nonce[0..8]  = i as u64 (little-endian counter)
  nonce[8..12] = random (4 bytes from OS CSPRNG)
  ciphertext_i = AES-256-GCM(volume_key, nonce, plaintext_chunk_i)

The counter component prevents nonce reuse across chunks; the random component provides additional uniqueness across encryptions with the same key.

Interactive TUI Screenshots

The TUI features:

Feature Description
Step indicators Visual breadcrumb showing current position in the workflow
Password strength meter Real-time strength evaluation (Weak/Fair/Good/Strong) with visual bar
Disk confirmation dialog Explicit Yes/No prompt before any block device operation
Animated progress Spinning indicator with elapsed time during encryption/decryption
Scrollable info Scroll through cryptographic metadata with ↑↓ keys
Context-sensitive help Bottom bar changes based on current screen
Vim-style navigation j/k keys work alongside ↑↓ throughout the interface

.qsv File Format Specification

Offset  Size    Field
──────  ──────  ──────────────────────────────────────────
0x00    4 B     Magic number: "QSV1" (0x51 0x53 0x56 0x31)
0x04    1 B     Format version (currently 0x01)
0x05    1 B     KEM algorithm ID (0x01 = ML-KEM-768 + X25519)
0x06    1 B     Content type (0x00 = Tar Archive, 0x01 = Raw Disk)
0x07    8 B     Original plaintext size (u64 LE) — for byte-exact restore
0x0F    32 B    Argon2id salt
0x2F    var     [u16 LE length] ML-KEM encapsulation key (1184 B for ML-KEM-768)
        var     [u16 LE length] ML-KEM decapsulation key (encrypted, ~2416 B + GCM overhead)
        32 B    X25519 public key
        var     [u16 LE length] ML-KEM ciphertext (1088 B for ML-KEM-768)
        32 B    X25519 ephemeral public key
        var     [u16 LE length] X25519 secret key (encrypted, 32 B + GCM overhead)
────────────────────────────────────────────────────────────
Data stream (repeating):
        4 B     Encrypted chunk length (u32 LE); 0x00000000 = end sentinel
        12 B    Nonce (8 B counter + 4 B random)
        var     Ciphertext + 16 B GCM authentication tag

Header size: approximately 4,817 bytes for ML-KEM-768 + X25519.

Crypto-agility: The KEM algorithm ID byte allows future versions to introduce new algorithms (e.g., ML-KEM-1024, HQC) without breaking backward compatibility.

Security Properties

Guarantees

Property Mechanism
Confidentiality AES-256-GCM with unique per-chunk nonces
Integrity GCM authentication tag on every 1 MiB chunk
Authenticity Password-derived master key authenticates the encryptor
Forward secrecy Ephemeral KEM keypair per encryption — no long-term private key stored
Key zeroization All sensitive key material (master_key, volume_key, passwords) zeroed immediately after use via the zeroize crate
Anti-DoS Decryption rejects chunks exceeding 1 MiB + 64 bytes
Path traversal protection Tar extraction validates all entry paths against ../, absolute paths, and prefix components
Symlink safety Symlinks recorded as links (not followed); symlink inputs rejected

Limitations and Caveats

  • Not a real-time FDE: QShield encrypts files/images into .qsv containers. It does not provide transparent block-layer encryption like LUKS, BitLocker, or FileVault.
  • No key escrow: If the password is lost, data is irrecoverable. There is no recovery mechanism by design.
  • Unaudited cryptographic dependencies: The underlying RustCrypto crates (ml-kem, aes-gcm, argon2, x25519-dalek) have not been independently audited. No formal side-channel analysis has been performed.
  • Single-threaded encryption: Bulk encryption uses a single thread. Performance scales linearly with data size.
  • GCM nonce space: With 8-byte counter + 4-byte random nonces, the theoretical limit is 2^64 chunks (~16 EiB) per encryption. In practice, this is not a constraint.

Performance

Measured on Apple M2 Pro (macOS 14, --release build):

Operation Data Size Time Throughput
Encrypt file 100 MiB ~1.0s ~100 MiB/s
Decrypt file 100 MiB ~1.0s ~100 MiB/s
Encrypt disk 1 GiB ~10s ~100 MiB/s
Key derivation (Argon2id) ~0.4s

Throughput is dominated by AES-256-GCM with hardware AES-NI acceleration. The Argon2id key derivation adds a fixed ~0.4s overhead regardless of data size.

Project Structure

qshield/
├── src/
│   ├── main.rs              # CLI entry point, command handlers
│   ├── crypto/
│   │   ├── kem.rs           # ML-KEM-768 + X25519 hybrid encapsulation
│   │   ├── kdf.rs           # Argon2id password stretching, HKDF key combination
│   │   └── symmetric.rs     # AES-256-GCM single-shot and streaming encryption
│   ├── volume/
│   │   └── format.rs        # QSV header serialization and parsing
│   ├── tui/
│   │   ├── app.rs           # Interactive terminal UI state machine
│   │   └── widgets.rs       # Ratatui UI components
│   ├── error.rs             # Error types
│   └── ui.rs                # CLI progress bars and formatted output
├── .github/workflows/
│   ├── ci.yml               # Test + Clippy + Format on every push/PR
│   └── release.yml          # Cross-platform binary builds on tag push
├── CHANGELOG.md             # All notable changes per version
├── SECURITY.md              # Vulnerability reporting policy
├── CONTRIBUTING.md           # Development setup and contribution guidelines
├── LICENSE                   # MIT License
└── Cargo.toml               # Dependencies and build configuration

Contributing

See CONTRIBUTING.md for development setup, coding standards, and the pull request process.

License

MIT — Copyright (c) 2026 Jiho Bae

Acknowledgments

QShield is built on the RustCrypto ecosystem:

  • ml-kem — ML-KEM (FIPS 203) implementation
  • x25519-dalek — X25519 Diffie-Hellman
  • aes-gcm — AES-256-GCM authenticated encryption
  • argon2 — Argon2id password hashing
  • sha3 / hkdf — SHA3-256 and HKDF key derivation
  • ratatui — Terminal user interface framework

About

Post-quantum hybrid encryption for files, directories, and whole disks — ML-KEM-768 + X25519 + AES-256-GCM with Argon2id key derivation. Single binary, cross-platform (macOS/Linux/Windows).

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages