Encrypting disks on Linux using LUKS

- 6 mins read

As the era passes, we are in serious need of encrypting our disks. Built-in encryption software, such as BitLocker in Microsoft Windows and FileVault in macOS, is both amazing.

Though BitLocker has been proven to be vulnerable.

In GNU/Linux, we have some great alternatives. The best and most popular one must be LUKS, aka cryptsetup.

So today I’m going to share how to encrypt your drive in Linux.

Caution

Everything on that drive will be erased and unrecoverable (as the encryption software will randomly fill part of the drive), so please back everything up.)

Before getting started…

It’s always recommended to zero your device before doing something like this. You can easily do this in any Unix/Linux operating system with dd.

dd if=/dev/zero of=/dev/TARGET_DRIVE bs=1M status=progress oflag=direct

Also, make sure the surrounding environment is suitable for this kind of operation.

Preparing your computer

We will be on Debian GNU/Linux 12 (bookworm) with apt as our package manager.

Usually, the cryptsetup package is installed by default, but if it’s not, you can install it by executing the following command.

sudo apt install cryptsetup
$ cryptsetup --version                                                                          
cryptsetup 2.6.1 flags: UDEV BLKID KEYRING KERNEL_CAPI

Encrypting with password

/dev/sdc will be the drive that we are encrypting today.

Use the following command to encrypt the whole disk.

Superuser (root) privileges are required.

$ sudo cryptsetup luksFormat /dev/sdc     
WARNING: Device /dev/sdc already contains a 'ext4' superblock signature.

WARNING!
========
This will overwrite data on /dev/sdc irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sdc: 
Verify passphrase: 

Now it’s encrypted. But it’s not over yet. We need to open it.

$ sudo cryptsetup luksOpen /dev/sdc cipherdisk
Enter passphrase for /dev/sdc: 
$ ll /dev/mapper | grep cipherdisk
lrwxrwxrwx       - root 13 Aug 22:58  cipherdisk -> ../dm-4

The opened virtual partition is located at /dev/mapper/. Now we need to create a filesystem for it.

You can create an LVM volume group on top of it, no problem. And you can also create an LVM volume group on the bare disk first and then create a LUKS partition on top of the LVM volume, though I wouldn’t recommend it since the flexibility will be extremely low. It’s not possible to resize your LUKS partition.

You can use any filesystem you want, but I will be using btrfs today.

$ sudo mkfs.btrfs /dev/mapper/cipherdisk
btrfs-progs v6.2
See http://btrfs.wiki.kernel.org for more information.

NOTE: several default settings have changed in version 5.15, please make sure
      this does not affect your deployments:
      - DUP for metadata (-m dup)
      - enabled no-holes (-O no-holes)
      - enabled free-space-tree (-R free-space-tree)

Label:              (null)
UUID:               8b68a5a5-7550-4d20-9438-a08dd933c722
Node size:          16384
Sector size:        4096
Filesystem size:    57.60GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP               1.00GiB
  System:           DUP               8.00MiB
SSD detected:       yes
Zoned device:       no
Incompat features:  extref, skinny-metadata, no-holes
Runtime features:   free-space-tree
Checksum:           crc32c
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1    57.60GiB  /dev/mapper/cipherdisk

If you are paranoid enough, you can zero the encrypted partition, so your bare disk will appear completely randomized.

Now, you can just mount the disk and do everything you want normally.

Mount automatically

If this is an internal drive, you might want to mount it automatically. It’s simple, just one step more than editing fstab directly.

First, we need to know the ID of your encrypted partition. In our case, it is /dev/sdc

$ blkid | grep /dev/sdc
/dev/sdc: UUID="22bde438-7833-4881-9439-62c7aa2cdf82" TYPE="crypto_LUKS"

Copy the UUID and head to /etc/crypttab, add a new line like the following.

cipherdisk UUID="22bde438-7833-4881-9439-62c7aa2cdf82" none luks,discard

discard means to issue a TRIM command when a block is freed, and you may add nofail to avoid failures when booting the system if the disk is not available, commonly seen when dealing with external drives.

You can put your plain-text password into a text file and replace none with the path to it. It’s not recommended.

Now we can head to /dev/fstab.

/dev/mapper/cipherdisk /mnt/encrypted_drive btrfs defaults,compress=zstd:1,nofail 0 0

Replace the mount point, filesystem, and mount arguments if you want to.

We don’t need to use UUID here, just the path directly, since we are sure it will be there. (add a nofail please)

Encrypting with FIDO

If you are into this realm for some time, you might have a FIDO-compliant hardware device, e.g., YubiKey. We can take advantage of it.

You need systemd for this.

$ sudo cryptsetup luksHeaderBackup /dev/sdc --header-backup-file luks-header-sdc.bin # Backup LUKS header in case something goes wrong

$ sudo systemd-cryptenroll --fido2-device=auto /dev/sdc
πŸ” Please enter current passphrase for disk /dev/sdc: *********               
Initializing FIDO2 credential on security token.
πŸ‘† (Hint: This might require confirmation of user presence on security token.)
πŸ” Please enter security token PIN: ******           
Generating secret key on FIDO2 security token.
πŸ‘† In order to allow secret key generation, please confirm presence on security token.
New FIDO2 token enrolled as key slot 1.

$ sudo cryptsetup luksDump /dev/sdc
LUKS header information
Version:        2
Epoch:          5
Metadata area:  16384 [bytes]
Keyslots area:  16744448 [bytes]
UUID:           <redacted>
Label:          (no label)
Subsystem:      (no subsystem)
Flags:          (no flags)

Data segments:
  0: crypt
        offset: 16777216 [bytes]
        length: (whole device)
        cipher: aes-xts-plain64
        sector: 512 [bytes]

Keyslots:
  0: luks2
        Key:        512 bits
        Priority:   normal
        Cipher:     aes-xts-plain64
        Cipher key: 512 bits
        PBKDF:      argon2id
        Time cost:  4
        Memory:     1048576
        Threads:    4
        Salt:       <redacted> 
        AF stripes: 4000
        AF hash:    sha256
        Area offset:32768 [bytes]
        Area length:258048 [bytes]
        Digest ID:  0
  1: luks2
        Key:        512 bits
        Priority:   normal
        Cipher:     aes-xts-plain64
        Cipher key: 512 bits
        PBKDF:      pbkdf2
        Hash:       sha512
        Iterations: 1000
        Salt:       <redacted> 
        AF stripes: 4000
        AF hash:    sha512
        Area offset:290816 [bytes]
        Area length:258048 [bytes]
        Digest ID:  0
Tokens:
  0: systemd-fido2
        fido2-credential:
                    <redacted>
        fido2-salt: <redacted>
        fido2-rp:   io.systemd.cryptsetup
        fido2-clientPin-required:
                    true
        fido2-up-required:
                    true
        fido2-uv-required:
                    false
        Keyslot:    1
Digests:
  0: pbkdf2
        Hash:       sha256
        Iterations: 87497
        Salt:       <redacted> 
        Digest:     <redacted>

systemd-cryptenroll also supports PKCS#11 tokens, just replace --fido2-device=auto to --pkcs11-token-uri=auto. Refer to the official manual for more instructions.

Mount automatically

Similarly, just add fido2-device=auto as an option.

cipherdisk UUID="22bde438-7833-4881-9439-62c7aa2cdf82" none luks,discard,fido2-device=auto

Mount manually

By default, cryptsetup still uses a password. We need to explicitly ask it to use our security token.

$ sudo cryptsetup luksOpen --token-only /dev/sdc cipherdisk
Enter token PIN: 
Asking FIDO2 token for authentication.
πŸ‘† Please confirm presence on security token to unlock.

You CANNOT delete the password. The option luksKillSlot WILL NOT work here since it will ask you for any remaining passphrase, which we don’t have, as we only have a FIDO key located on our security keys.

Unmounting your drive

You can’t just unplug your drive when it’s opened, at least not suggested. Instead, you should umount your partition first, and then luksClose your drive.

sudo umount /mnt/encrypted_drive
sudo cryptsetup luksClose cipherdisk

And then the drive is released, you can either power it off or unplug it directly.

Outro

There you go, now you have encrypted your drive!

References

systemd-cryptenroll(1) β€” systemd β€” Debian bookworm β€” Debian Manpages, archived in Internet Archive on April 16, 2025.

εΉ΄θ½»δΊΊηš„η¬¬δΈ€δΈͺ YubiKey | Chi_Tang’s Blog, archived in Internet Archive on June 12, 2024.