/ Documentation / CLI reference / luksbox create

luksbox create

Create a new encrypted container.

luksbox create [OPTIONS] <PATH>

Creates a new vault at <PATH> with one initial keyslot. The kind of slot 0 is set by --kind (passphrase by default).

Examples

Passphrase-only vault (default)

luksbox create my.lbx

Creates my.lbx with one passphrase keyslot using AES-256-GCM-SIV and the interactive Argon2id preset.

Detached header

luksbox create my.lbx --header /media/usb/my.hdr

Writes the 8 KiB header to a separate file. Without that sidecar, my.lbx is unreadable - no magic bytes, no keyslot table, just random data.

FIDO2-protected vault

luksbox create my.lbx --kind fido2
# Two touches: makeCredential + getAssertion

Adds a FIDO2 keyslot as slot 0. You'll be prompted for a backup passphrase too (added as slot 1) so losing the device doesn't lose the vault. Skip the backup with --no-backup-passphrase if you understand the trade-off.

Hybrid post-quantum

# First, generate the Kyber seed file (keep on separate storage)
luksbox kyber-init /media/usb/my.kyber

# Then create the vault
luksbox create my.lbx --kind hybrid-pq --pq-hybrid /media/usb/my.kyber

Or for the strongest variant (FIPS 203 cat 5):

luksbox create my.lbx --kind hybrid-pq1024-fido2 \
    --pq-hybrid /media/usb/my.kyber

Key flags

Flag Purpose
--kind <KIND> First keyslot kind: passphrase (default), fido2, fido2-direct, hybrid-pq, hybrid-pq-fido2, hybrid-pq1024, hybrid-pq1024-fido2
--cipher <aes|chacha|aes-siv> AEAD primitive. aes-siv (default) is AES-256-GCM-SIV per RFC 8452
--kdf <interactive|sensitive> Argon2id preset. sensitive multiplies brute-force cost by 6x
--header <PATH> Write header to a separate sidecar file
--fido2-device <PATH> Pin to a specific FIDO2 device (see list-fido2-devices)
--pq-hybrid <PATH> Path to the .kyber seed file (required for hybrid-PQ kinds)
--chunk-size <N> File chunk size in bytes (default 4096)
--metadata-size <BYTES> Reserved metadata region size (default + cap: 16 MiB). Lower this only for tiny demo vaults; higher values are rejected at the CLI boundary.
--format <v2|v3> On-disk metadata format (default v3). See the format section below.
--pad-files Pad each file's chunk count to next power of 2 (hides exact size from disk forensics)
--hide-sizes Move the size field into AEAD-encrypted chunks (implies --pad-files)
--no-backup-passphrase For --kind fido2: don't add a passphrase backup slot

On-disk format: v2 vs v0.2.1 (LBM5 + LUKSBOX2)

Every new vault picks one of two on-disk envelopes. The choice is permanent for that vault.

v0.2.1 format (default) v2 (legacy)
Metadata magic LBM\x05 LBM\x02
Header magic LUKSBOX2 LUKSBOX1
Per-file chunk list location External: linked chain of encrypted chunk-list blocks in the data area. Files above 256 chunks (~1 MiB plaintext) spill; tiny files stay inline. Inline: Vec<ChunkRef> packed into the fixed metadata region.
Practical per-vault content ceiling Tested up to ~30 GiB; engineered for much more. 64 MiB metadata cap. ~8-10 GiB before the metadata region overflows.
Crash-safety <vault>.lbx.{header,meta}-bak sidecar mirrors; mid-write force-quit recovers automatically. NOT crash-safe. A force-quit mid-write can leave the vault permanently unopenable.
Persistent chmod / hardlinks / symlinks Yes No
Reader compatibility LUKSbox v0.2.1+ only Every LUKSbox release ever shipped

Pick the v0.2.1 default unless you need to share the new vault with a colleague on a pre-v0.3 LUKSbox install AND can suppress the auto-upgrade trigger via LUKSBOX_FORMAT_V2=1 in their environment. Otherwise the first flush on their side auto-upgrades the vault to the v0.2.1 envelope and they can no longer open it with their old binary.

# Default: v0.2.1 (LBM5 + LUKSBOX2 + sidecar mirrors)
luksbox create my.lbx

# Explicit v2 legacy for cross-version compatibility
luksbox create my.lbx --format v2

# Power-user knob: shrink the metadata region for a demo vault
luksbox create demo.lbx --format v2 --metadata-size 256K

Migrating an existing v2 vault to v3

luksbox migrate-to-v3 old-v2.lbx --dst new-v3.lbx

Reads the v2 vault, creates a fresh v3 vault, copies every file through the VFS read API. Source vault is left untouched; verify the new one opens cleanly (luksbox info new-v3.lbx) before deleting the source. The destination is created with a single passphrase keyslot -- re-enroll other keyslots afterwards via luksbox enroll.

Deniable vaults can be created in v3 format directly via the wizard (it asks for the format alongside the cipher and KDF params); there's no automated migrate-to-v3 path for deniable vaults yet because the deniable open ceremony is interactive.

Environment-variable opt-out

# Force v2 for every fresh vault in this shell session, even
# when --format isn't passed.
LUKSBOX_FORMAT_V2=0  # opts into v3 (the default -- leave unset)
LUKSBOX_FORMAT_V2=1  # opt into v3 (legacy gate from the v0.2-dev cycle)
# Values `false` / `no` / `off` on LUKSBOX_FORMAT_V2 force v2.

What gets created on disk

File When
<PATH> (the .lbx) Always
<PATH>.hdr (if --header) When --header is passed
<PATH>.hybrid For hybrid-PQ kinds only - small sidecar with ML-KEM data
<KYBER_PATH> For hybrid-PQ kinds only - the seed file you pre-generated

After create, the vault is empty. Use luksbox put to add files or luksbox mount to mount as a drive and write to it normally.