Encrypting disks on Linux using LUKS
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 addnofail
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.