symmetric · level 8

Disk Encryption (XTS)

Why FileVault, BitLocker, and LUKS use a different mode than TLS.

200 XP

Disk Encryption (XTS)

When you encrypt a TLS record, you have a sequence number and as much extra space as you need. When you encrypt a 4 KB disk sector, you have no extra space — the sector is exactly 4096 bytes coming in and exactly 4096 bytes going out. This single constraint rules out every familiar AEAD mode and explains why all the major operating systems converged on the same answer: AES-XTS.

The constraints

Disk encryption has three properties that network encryption doesn't:

  1. Random access. Reading sector 1024 must not require decrypting sectors 0 through 1023. The cipher must support O(1) seek.
  2. No expansion. The plaintext is 4096 bytes, the ciphertext must also be 4096 bytes. There's nowhere to put a nonce or a 16-byte tag.
  3. Position-dependent. Sector 0 and sector 1 may have identical plaintexts (zero-filled regions, repeated headers). They must encrypt to different ciphertexts — otherwise an observer learns the disk's structure.

CTR / GCM / ChaCha20 all fail (1) (they need an explicit per-block nonce somewhere) or (2) (GCM tags need 16 spare bytes per block). CBC fails (1) (sequential chaining). ECB fails (3) (the penguin problem at scale).

The mode that satisfies all three is XTS — XEX-based Tweaked codeBook mode with ciphertext Stealing.

XTS, in one diagram

                 sector index N (the "tweak")
                          │
                          ▼
                 ┌─────────────┐
                 │  AES_K2(N)  │   ← K2 = "tweak key"
                 └─────────────┘
                          │
                          α^j · (·)   ← multiply by α in GF(2^128) per 16-byte block
                          │
                ┌─────────┴────────┐
                ▼                  ▼
   plaintext_j ─⊕─►  AES_K1   ──⊕─► ciphertext_j
                    (data key)

Two AES keys (K1 and K2, often joined into a single 32 / 64-byte XTS key). For each 16-byte block within a sector:

  1. Encrypt the sector index N under K2 to produce the per-sector tweak T_0.
  2. Multiply T_0 by α^j in GF(2^128) for the j-th 16-byte block within the sector.
  3. XOR the tweak into the plaintext, run AES with K1, XOR the tweak back out.

The result: same plaintext at sector 0, block 0 and at sector 7, block 3 produces wildly different ciphertext. Same plaintext at sector 7, block 3 always produces the same ciphertext (which is why XTS isn't probabilistic — it's tweakable but deterministic).

What XTS is not

XTS gives you confidentiality, not integrity. A bit-flip in ciphertext at byte X flips bits in plaintext at byte X. It's a "tweakable PRP" — the cipher behaves like a random permutation per (key, tweak), but there's no MAC and no tag.

For most threat models this is fine. An attacker who can flip arbitrary bytes on your disk can probably also delete the disk; integrity at the filesystem layer (ZFS / btrfs / APFS checksums, dm-integrity, BitLocker's "Secure Boot" attestation) is the standard answer.

For threat models where the attacker must not be able to mutate ciphertext silently (e.g., evil-maid scenarios on laptops), pair XTS with dm-integrity on Linux or use a filesystem with cryptographically-checksummed extents.

Where you'll meet it

OS / system Default Notes
Linux LUKS2 AES-XTS-256 cryptsetup luksFormat defaults to this. Header is unencrypted, key slots wrap the master key.
macOS FileVault (APFS) AES-XTS-128 T2 / Apple Silicon machines use hardware AES. Recovery keys via iCloud or institutional escrow.
Windows BitLocker AES-XTS-256 Since Windows 10 1511. TPM-bound by default; can be USB-key bound.
Android (modern) AES-XTS or Adiantum Adiantum (Bernstein/Biggers, 2018) for low-end devices without AES hardware.
VeraCrypt AES-XTS, also Twofish/Serpent in XTS Cross-platform open source; supports cascaded ciphers.

The convergence is real: every major full-disk encryption product on every major OS uses XTS.

Common pitfalls

  • XTS isn't authenticated. If your threat model includes an attacker mutating ciphertext, layer integrity above (dm-integrity, ZFS) or use BitLocker's "AEAD" mode (which adds a separate integrity layer).
  • Sector size matters. XTS keys must be 2 × cipher_key_size. Sector size (default 4096 bytes for modern disks, 512 for legacy) affects the granularity of the tweak. Mismatched sector sizes between encryption and decryption corrupt the volume.
  • Don't use XTS for streams. It's designed for fixed-size random-access blocks. For network or in-memory data, use AEAD (GCM, ChaCha20-Poly1305) — XTS doesn't help there.
  • Hidden volumes are not magic. VeraCrypt's hidden volume feature relies on the outer volume's free space looking random. Filesystem activity in the outer volume can corrupt the hidden one.
  • Keys live in RAM. The disk is encrypted at rest; while mounted, the key is in RAM and reachable by anything with kernel privileges. Cold-boot attacks on un-suspended laptops are real.

Why XTS isn't the default for new application-level designs

XTS is specifically for storage-shaped problems. If you're encrypting JSON blobs in a database, log entries, or messages on a queue, you don't have the "no expansion" constraint — and you do want integrity. Use AEAD (AES-GCM, ChaCha20-Poly1305) instead.

XTS is the right tool when:

  • Block size is fixed and pre-determined (disk sectors, encrypted file systems).
  • You need O(1) random access.
  • Integrity is provided at a layer above (filesystem, hardware attestation).

For everything else, AEAD is the modern default. XTS exists because disk encryption is a different problem.

The bigger picture

The block-cipher landscape has, for two decades, basically been:

Network / messages → AEAD (GCM, CCM, ChaCha20-Poly1305)
Disk / storage   → XTS
Specialist (FF, FPE) → things like FF1 / FF3-1 for format-preserving encryption

XTS isn't fashionable, but it's everywhere — and understanding why it exists separates "I know AES-GCM" from "I understand modes well enough to know when GCM is wrong."

Tools in the wild

4 tools
  • The standard Linux disk encryption toolchain. AES-XTS by default, with optional dm-integrity for AEAD.

    cli
  • macOS native disk encryption. AES-XTS via APFS. `fdesetup status` shows current state.

    cli
  • Windows BitLocker CLI. AES-XTS-256 since Windows 10 1511. TPM-bound by default.

    cli
  • VeraCryptfree tier

    Cross-platform open-source disk/volume encryption. Multiple cipher options, hidden volumes.

    cli