LUKS Disk Encryption

Quick Reference

# Create encrypted volume
cryptsetup luksFormat /dev/sdb

# Open encrypted volume
cryptsetup open /dev/sdb crypt_data

# Close encrypted volume
cryptsetup close crypt_data

# Check status
cryptsetup status crypt_data

# Dump header info
cryptsetup luksDump /dev/sdb

# Add backup key
cryptsetup luksAddKey /dev/sdb

# Backup header
cryptsetup luksHeaderBackup /dev/sdb --header-backup-file header.img

Understanding LUKS

What is LUKS?

LUKS (Linux Unified Key Setup) provides:

  • Standardized encryption - Consistent on-disk format

  • Multiple key slots - Up to 8 different passphrases/keys

  • Header metadata - Cipher info stored on disk

  • Key derivation - PBKDF2/Argon2 protection against brute force

  • Plausible deniability - Detached headers option

LUKS Versions

Version Features Use Case

LUKS1

8 key slots, PBKDF2, wide compatibility

Legacy systems, compatibility needs

LUKS2 (default)

32 key slots, Argon2id, integrity, tokens

Modern systems, recommended

Encryption Stack

┌─────────────────────────────────────────┐
│           Filesystem (ext4/xfs)          │
└─────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────┐
│        Device Mapper (dm-crypt)          │
│         /dev/mapper/crypt_data           │
└─────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────┐
│        LUKS Container (encrypted)        │
│              /dev/sdb                    │
│   ┌───────────────────────────────────┐ │
│   │ LUKS Header (metadata, key slots) │ │
│   ├───────────────────────────────────┤ │
│   │      Encrypted Data Area          │ │
│   └───────────────────────────────────┘ │
└─────────────────────────────────────────┘

Creating Encrypted Volumes

Basic Creation

# Format with LUKS2 (default)
cryptsetup luksFormat /dev/sdb

# You'll be prompted for:
# - Confirmation (YES in uppercase)
# - Passphrase (entered twice)

# Open the encrypted volume
cryptsetup open /dev/sdb crypt_data

# The decrypted device is now at /dev/mapper/crypt_data

# Create filesystem
mkfs.ext4 /dev/mapper/crypt_data

# Mount
mount /dev/mapper/crypt_data /mnt/secure

Advanced Creation Options

# LUKS2 with specific cipher and key size
cryptsetup luksFormat --type luks2 \
    --cipher aes-xts-plain64 \
    --key-size 512 \
    --hash sha512 \
    --iter-time 5000 \
    /dev/sdb

# LUKS1 (for compatibility)
cryptsetup luksFormat --type luks1 /dev/sdb

# With Argon2id (LUKS2 default, recommended)
cryptsetup luksFormat --type luks2 \
    --pbkdf argon2id \
    --pbkdf-memory 1048576 \
    --pbkdf-parallel 4 \
    --pbkdf-force-iterations 4 \
    /dev/sdb

# With integrity (authenticated encryption)
cryptsetup luksFormat --type luks2 \
    --integrity hmac-sha256 \
    /dev/sdb

# Non-interactive (key from file)
echo -n "mypassphrase" | cryptsetup luksFormat /dev/sdb -

# Using key file
cryptsetup luksFormat /dev/sdb --key-file /root/keyfile

Cipher Options

Cipher Description

aes-xts-plain64

Default, recommended for disks >2TB

aes-cbc-essiv:sha256

Legacy, compatible with older systems

serpent-xts-plain64

Alternative cipher (slower but arguably more secure)

twofish-xts-plain64

Another alternative cipher

Key Sizes

Key Size Notes

256-bit

AES-XTS uses 256-bit for encryption (128-bit AES)

512-bit

AES-XTS uses 512-bit for 256-bit AES (recommended)

Opening and Closing Volumes

Open (Unlock)

# Basic open
cryptsetup open /dev/sdb crypt_data

# Same as (legacy syntax)
cryptsetup luksOpen /dev/sdb crypt_data

# Open with key file
cryptsetup open /dev/sdb crypt_data --key-file /root/keyfile

# Open read-only
cryptsetup open --readonly /dev/sdb crypt_data

# Open with specific key slot
cryptsetup open --key-slot 1 /dev/sdb crypt_data

# Allow discards (for SSD TRIM - security tradeoff)
cryptsetup open --allow-discards /dev/sdb crypt_data

# Open with detached header
cryptsetup open --header /path/to/header.img /dev/sdb crypt_data

Close (Lock)

# Unmount first
umount /mnt/secure

# Close the encrypted volume
cryptsetup close crypt_data

# Same as (legacy syntax)
cryptsetup luksClose crypt_data

# Deferred close (waits for users to finish)
cryptsetup close --deferred crypt_data

Check Status

# Check if device is LUKS
cryptsetup isLuks /dev/sdb && echo "Is LUKS"

# Detailed status
cryptsetup status crypt_data

# Output:
# /dev/mapper/crypt_data is active.
#   type:    LUKS2
#   cipher:  aes-xts-plain64
#   keysize: 512 bits
#   key location: keyring
#   device:  /dev/sdb
#   sector size:  512
#   offset:  32768 sectors
#   size:    1953493296 sectors
#   mode:    read/write

# Dump LUKS header
cryptsetup luksDump /dev/sdb

Key Management

Key Slots

LUKS supports multiple key slots (8 for LUKS1, 32 for LUKS2), allowing: - Multiple passphrases for same volume - Recovery keys - Key rotation without re-encryption

Add Key

# Add new passphrase (prompted for existing + new)
cryptsetup luksAddKey /dev/sdb

# Add to specific slot
cryptsetup luksAddKey --key-slot 2 /dev/sdb

# Add key file as new key
cryptsetup luksAddKey /dev/sdb /root/newkeyfile

# Add passphrase using existing key file
cryptsetup luksAddKey --key-file /root/oldkey /dev/sdb

# Non-interactive (pipe both keys)
echo -n "existingpass" | cryptsetup luksAddKey /dev/sdb /root/newkeyfile

Remove Key

# Remove by passphrase (prompted)
cryptsetup luksRemoveKey /dev/sdb

# Remove specific slot
cryptsetup luksKillSlot /dev/sdb 2

# Remove key file
cryptsetup luksRemoveKey /dev/sdb /root/oldkeyfile

Change Key

# Change passphrase
cryptsetup luksChangeKey /dev/sdb

# Change specific slot
cryptsetup luksChangeKey --key-slot 0 /dev/sdb

View Key Slots

# Dump header (shows slot status)
cryptsetup luksDump /dev/sdb

# Output includes:
# Keyslots:
#   0: luks2
#      Key:        512 bits
#      Priority:   normal
#      Cipher:     aes-xts-plain64
#   1: luks2
#      ...
#   2-7: (unused)

Key Files

# Create random key file
dd if=/dev/urandom of=/root/keyfile bs=4096 count=1

# Secure permissions
chmod 400 /root/keyfile

# Use key file
cryptsetup open --key-file /root/keyfile /dev/sdb crypt_data

# Multiple key files (use specific one)
cryptsetup open --key-file /root/keyfile1 /dev/sdb crypt_data

Header Management

Header Backup (Critical!)

Always backup LUKS headers. Header loss = data loss.
# Backup header
cryptsetup luksHeaderBackup /dev/sdb \
    --header-backup-file /root/luks-header-sdb.img

# Store backup securely:
# - Encrypted USB drive
# - Password manager
# - Secure cloud storage (encrypted)
# - Safety deposit box

# Verify backup
cryptsetup luksDump /root/luks-header-sdb.img

Header Restore

# Restore header (DESTRUCTIVE - overwrites current header)
cryptsetup luksHeaderRestore /dev/sdb \
    --header-backup-file /root/luks-header-sdb.img

# Test with --header (doesn't modify disk)
cryptsetup open --header /root/luks-header-sdb.img /dev/sdb crypt_test

Detached Headers

For enhanced security, store header separately from data:

# Create with detached header
cryptsetup luksFormat --header /root/header.img /dev/sdb

# Open with detached header
cryptsetup open --header /root/header.img /dev/sdb crypt_data

# Without the header file, the disk looks like random data

Header Information

# View header info
cryptsetup luksDump /dev/sdb

# LUKS2 shows:
# - Version
# - UUID
# - Label (if set)
# - Cipher/hash/iterations
# - Key slot info
# - Segments
# - Digests

# Set label
cryptsetup config --label "MyEncryptedDisk" /dev/sdb

# View label
cryptsetup luksDump /dev/sdb | grep Label

Auto-Mount with crypttab

Basic crypttab Entry

/etc/crypttab
# <target name>   <source device>                    <key file>   <options>
crypt_data        /dev/sdb                           none         luks
crypt_home        UUID=12345678-1234-1234-1234-123456789abc  none  luks

With Key File

/etc/crypttab
# Auto-unlock with key file (no password prompt)
crypt_data   /dev/sdb   /root/keyfile   luks

crypttab Options

Option Description

luks

LUKS mode (default, auto-detected)

plain

Plain dm-crypt mode

discard

Allow TRIM/discard (SSD, security tradeoff)

noauto

Don’t open at boot

nofail

Don’t fail boot if device missing

readonly

Open read-only

tries=N

Number of password attempts

timeout=N

Seconds to wait for password

header=/path

Use detached header

keyfile-size=N

Read N bytes from key file

keyfile-offset=N

Skip N bytes in key file

key-slot=N

Use specific key slot

Example Configurations

/etc/crypttab
# Interactive password at boot
crypt_root   UUID=abc123   none   luks,timeout=30

# Key file (automated)
crypt_data   /dev/sdb   /root/keyfile   luks

# SSD with TRIM (security vs performance)
crypt_ssd    /dev/nvme0n1p2   none   luks,discard

# Optional device (won't block boot)
crypt_usb    /dev/sdc   none   luks,noauto,nofail

# Detached header
crypt_secure   /dev/sdd   /root/keyfile   luks,header=/boot/header.img

Corresponding fstab Entry

/etc/fstab
/dev/mapper/crypt_data   /mnt/secure   ext4   defaults   0 2

Regenerate initramfs

After modifying crypttab for root encryption:

# Arch Linux
mkinitcpio -P

# Fedora/RHEL
dracut --force

# Debian/Ubuntu
update-initramfs -u

Full Disk Encryption

System Installation FDE

Most Linux installers support FDE:

  1. Choose "Encrypt disk" or "LVM on LUKS"

  2. Set encryption passphrase

  3. Installer handles the rest

Manual FDE Setup (Arch Linux Style)

# 1. Partition disk
# /dev/sda1 - EFI (512M, unencrypted)
# /dev/sda2 - LUKS container (rest)

# 2. Create LUKS container
cryptsetup luksFormat /dev/sda2

# 3. Open LUKS
cryptsetup open /dev/sda2 cryptroot

# 4. Create LVM inside LUKS (optional)
pvcreate /dev/mapper/cryptroot
vgcreate vg /dev/mapper/cryptroot
lvcreate -L 50G -n root vg
lvcreate -L 8G -n swap vg
lvcreate -l 100%FREE -n home vg

# 5. Format
mkfs.ext4 /dev/vg/root
mkfs.ext4 /dev/vg/home
mkswap /dev/vg/swap

# 6. Mount and install system
mount /dev/vg/root /mnt
mkdir /mnt/home /mnt/boot
mount /dev/vg/home /mnt/home
mount /dev/sda1 /mnt/boot

# 7. Configure crypttab/mkinitcpio/grub for encrypted root

GRUB with LUKS2

GRUB supports LUKS2 with some ciphers. Configure:

/etc/default/grub
GRUB_CMDLINE_LINUX="cryptdevice=UUID=<uuid>:cryptroot root=/dev/vg/root"
GRUB_ENABLE_CRYPTODISK=y
# Regenerate GRUB
grub-mkconfig -o /boot/grub/grub.cfg

Encrypting Existing Data

Always backup data before encryption operations.

In-Place Encryption (cryptsetup-reencrypt)

# 1. Backup data
rsync -av /dev/sdb /backup/sdb.img

# 2. Unmount
umount /dev/sdb

# 3. Encrypt in place
cryptsetup reencrypt --encrypt --reduce-device-size 16M /dev/sdb

# The --reduce-device-size makes room for LUKS header

# 4. Open and mount
cryptsetup open /dev/sdb crypt_data
mount /dev/mapper/crypt_data /mnt

Safer Method: Copy to New Encrypted Volume

# 1. Create new encrypted volume
cryptsetup luksFormat /dev/sdc
cryptsetup open /dev/sdc crypt_new
mkfs.ext4 /dev/mapper/crypt_new
mount /dev/mapper/crypt_new /mnt/new

# 2. Copy data
rsync -av /mnt/old/ /mnt/new/

# 3. Verify
diff -r /mnt/old /mnt/new

# 4. Swap drives

LVM and LUKS Combinations

Single password unlocks all LVs:

# 1. Create LUKS container
cryptsetup luksFormat /dev/sdb
cryptsetup open /dev/sdb crypt_data

# 2. Create LVM on decrypted device
pvcreate /dev/mapper/crypt_data
vgcreate vg_encrypted /dev/mapper/crypt_data
lvcreate -L 100G -n lv_data vg_encrypted
lvcreate -l 100%FREE -n lv_backup vg_encrypted

# 3. Format LVs
mkfs.ext4 /dev/vg_encrypted/lv_data
mkfs.ext4 /dev/vg_encrypted/lv_backup

LUKS on LVM

Separate password per LV:

# 1. Create LVM first
pvcreate /dev/sdb
vgcreate vg_plain /dev/sdb
lvcreate -L 100G -n lv_secure vg_plain

# 2. Encrypt individual LVs
cryptsetup luksFormat /dev/vg_plain/lv_secure
cryptsetup open /dev/vg_plain/lv_secure crypt_secure

# 3. Format
mkfs.ext4 /dev/mapper/crypt_secure

Performance Tuning

Check Crypto Performance

# Benchmark crypto algorithms
cryptsetup benchmark

# Output:
# PBKDF2-sha1        1234567 iterations per second
# PBKDF2-sha256       876543 iterations per second
# PBKDF2-sha512       654321 iterations per second
#      aes-cbc       1234.5 MiB/s   1234.5 MiB/s
#      aes-xts       2345.6 MiB/s   2345.6 MiB/s

Enable AES-NI

Check for hardware acceleration:

# Check CPU flags
grep -o aes /proc/cpuinfo | head -1

# Verify kernel module
lsmod | grep aesni

# Load if not loaded
modprobe aesni_intel

SSD Considerations

# Allow TRIM (security tradeoff: reveals which blocks are free)
cryptsetup open --allow-discards /dev/sdb crypt_data

# Or in crypttab
crypt_ssd   /dev/sdb   none   luks,discard

# Verify TRIM is working
fstrim -v /mnt/secure

Troubleshooting

Can’t Open Volume

# Verify LUKS device
cryptsetup isLuks /dev/sdb

# Check header
cryptsetup luksDump /dev/sdb

# Try with verbose
cryptsetup -v open /dev/sdb crypt_data

# Try specific key slot
cryptsetup open --key-slot 0 /dev/sdb crypt_data

# If header corrupted, restore from backup
cryptsetup luksHeaderRestore /dev/sdb \
    --header-backup-file /backup/header.img

Forgot Passphrase

If you have: - Another working key slot: Use it to add new passphrase - Key file: Use it to add new passphrase - Header backup + passphrase: Restore header - None of the above: Data is lost (by design)

# Add new passphrase using key file
cryptsetup luksAddKey --key-file /root/backup-key /dev/sdb

Corrupted Header

# Restore from backup
cryptsetup luksHeaderRestore /dev/sdb \
    --header-backup-file /backup/header.img

# If no backup, try repair (LUKS2 only)
cryptsetup repair /dev/sdb

Boot Issues with Encrypted Root

# Boot from live USB

# Open encrypted root
cryptsetup open /dev/sda2 cryptroot

# Mount
mount /dev/mapper/cryptroot /mnt
# Or if LVM: mount /dev/vg/root /mnt

# Chroot
arch-chroot /mnt  # or mount --bind /dev /mnt/dev etc.

# Verify crypttab
cat /etc/crypttab

# Regenerate initramfs
mkinitcpio -P  # Arch
update-initramfs -u  # Debian

# Verify GRUB
cat /etc/default/grub
grub-mkconfig -o /boot/grub/grub.cfg

Performance Issues

# Check crypto performance
cryptsetup benchmark

# Verify hardware acceleration
dmesg | grep -i aes

# Check if AES-NI in use
cat /proc/crypto | grep -A 10 aes

# For slow operations, check iteration count
cryptsetup luksDump /dev/sdb | grep -i iterations

Security Considerations

Best Practices

  1. Use LUKS2 with Argon2id (default)

  2. Strong passphrases - 20+ characters recommended

  3. Backup headers - Encrypted, stored separately

  4. Key files - Random, on encrypted media

  5. Secure deletion - shred key files when done

  6. Memory protection - Consider encrypted swap

Secure Key File Management

# Create secure key file
dd if=/dev/urandom of=/root/keyfile bs=4096 count=1
chmod 400 /root/keyfile
chattr +i /root/keyfile  # Immutable

# When done with key file
shred -vfz -n 5 /root/keyfile
rm /root/keyfile

Wipe LUKS Container

# Erase all key slots (makes data unrecoverable)
cryptsetup luksErase /dev/sdb

# Or wipe header area
dd if=/dev/urandom of=/dev/sdb bs=1M count=10

Cold Boot Attack Mitigation

# Enable kernel memory encryption (AMD SME)
# Add to kernel cmdline: mem_encrypt=on

# Use encrypted swap
cryptsetup luksFormat /dev/swap
# Or use random key swap (fresh each boot)
# /etc/crypttab: swap /dev/sdX /dev/urandom swap

Quick Command Reference

# Creation
cryptsetup luksFormat /dev/sdb              # Create LUKS container
cryptsetup open /dev/sdb crypt_name         # Open/unlock
cryptsetup close crypt_name                 # Close/lock

# Information
cryptsetup isLuks /dev/sdb                  # Check if LUKS
cryptsetup luksDump /dev/sdb                # Show header info
cryptsetup status crypt_name                # Show open device info
cryptsetup benchmark                        # Crypto benchmarks

# Key management
cryptsetup luksAddKey /dev/sdb              # Add passphrase
cryptsetup luksRemoveKey /dev/sdb           # Remove passphrase
cryptsetup luksChangeKey /dev/sdb           # Change passphrase
cryptsetup luksKillSlot /dev/sdb N          # Remove slot N

# Header management
cryptsetup luksHeaderBackup /dev/sdb --header-backup-file backup.img
cryptsetup luksHeaderRestore /dev/sdb --header-backup-file backup.img

# Advanced
cryptsetup reencrypt --encrypt /dev/sdb     # Encrypt in place
cryptsetup repair /dev/sdb                  # Repair LUKS2 header

See Also