1. Overview
We can protect the data on a block device using disk encryption. This is important for removable media since it protects the data even if the media is physically removed from a system.
LUKS (Linux Unified Key Setup) is a popular disk encryption method in Linux. LUKS encrypts a block device — typically a disk partition — with a master key, and multiple users can use the encrypted block device with different passphrases by decrypting the master key.
In this tutorial, we’ll discuss how to change a LUKS passphrase. First, we’ll give a brief introduction to LUKS. Then, we’ll prepare the necessary setup. Finally, we’ll see how to change a passphrase.
2. Brief Introduction to LUKS
LUKS encrypts a block device with a randomly generated master key and contains an unencrypted header preceding the encrypted data. This unencrypted header supports multiple passphrases by providing several key slots. Therefore, multiple users can use the same LUKS-encrypted partition using different passphrases.
There are two versions of LUKS. The older version, LUKS1, allows the usage of up to eight key slots. LUKS2, on the other hand, supports up to 32 key slots and is more resilient to header corruption.
LUKS encrypts the master key with user keys generated from the passphrases of users. Therefore, when we want to access an encrypted partition, it first decrypts the master key using our passphrase and decrypts the partition using the master key. This multi-layer approach enhances security.
3. Preparing the Setup
Let’s start by checking the block devices on our host using the lsblk command:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 512G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 511G 0 part
├─cs-root 253:0 0 70G 0 lvm /
├─cs-swap 253:1 0 2.1G 0 lvm [SWAP]
└─cs-home 253:2 0 439G 0 lvm /home
sdb 8:16 0 20G 0 disk
According to the last line in the output of lsblk, we have a hard disk, namely sdb, which hasn’t been mounted yet.
Let’s also check the file system on /dev/sdb:
$ lsblk -f /dev/sdb
NAME FSTYPE LABEL UUID MOUNTPOINT
sdb
The -l option of lsblk gives information about the file systems. Notably, the disk doesn’t have a file system.
3.1. Creating a LUKS Partition
Since the disk has no file system, let’s format the disk with LUKS:
$ sudo cryptsetup luksFormat /dev/sdb
WARNING!
========
This will overwrite data on /dev/sdb irrevocably.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sdb:
Verify passphrase:
cryptsetup is a command-line tool we use to create, access, and manage dm-crypt and LUKS-encrypted volumes. The cryptsetup luksFormat command initializes a LUKS partition and sets the initial passphrase for the specified device. We pass /dev/sdb as the device in our case.
We get a warning about overwriting the existing data in the device and cryptsetup wants us to confirm it by typing YES. Then, it prompts for the passphrase. Additionally, it wants us to verify the passphrase.
cryptsetup has several options for specifying arguments like the LUKS version, the hash algorithm, and the key sizes used under the hood. However, using it with the default options is sufficient for our purpose.
We need root privileges for using cryptsetup, so we use it together with the sudo command.
Having created the LUKS partition, let’s check the file system on /dev/sdb using lsblk again:
$ lsblk -f /dev/sdb
NAME FSTYPE LABEL UUID MOUNTPOINT
sdb crypto_LUKS c39f7404-6fa3-4c39-ba81-0a3fe41cb642
Now, /dev/sdb has a LUKS-encrypted file system as is apparent from the output.
3.2. Opening the LUKS Partition
We can open the LUKS partition using the cryptsetup luksOpen command:
$ sudo cryptsetup luksOpen /dev/sdb luks_disk
Enter passphrase for /dev/sdb:
We pass the LUKS formatted device name, which is /dev/sdb in our case, to the cryptsetup luksOpen command. Notably, we must provide the passphrase we created while using cryptsetup luksFormat.
In addition to the device name, we specify the name of the map point, which is luks_disk. The map point can be assigned any name and specifies the name in /dev/mapper. In our case, the LUKS partition is mapped to /dev/mapper/luks_disk:
$ ls /dev/mapper/luks_disk
/dev/mapper/luks_disk
We can also check the mapping using lsblk:
$ lsblk -f /dev/sdb
NAME FSTYPE LABEL UUID MOUNTPOINT
sdb crypto_LUKS c39f7404-6fa3-4c39-ba81-0a3fe41cb642
└─luks_disk
As we can see from the output, luks_disk doesn’t have a file system on it yet.
3.3. Creating a File System in the LUKS Partition
Now, we’ll create a file system in the LUKS partition using the mkfs.xfs command:
$ sudo mkfs.xfs /dev/mapper/luks_disk >& /dev/null
The mkfs.xfs command is used for creating an XFS file system. We create the XFS file system on /dev/mapper/luks_disk in the above command, and we redirect the output of the command to /dev/null to skip viewing the details.
Although we use XFS in our example, we can use any other file system — for example, EXT4.
3.4. Mounting the File System
The final step is to mount the file system:
$ sudo mkdir /mnt/luks_mount
$ sudo mount /dev/mapper/luks_disk /mnt/luks_mount
Here, we mount the /dev/mapper/luks_disk file system to the /mnt/luks_mount directory.
Let’s check the file system on /dev/sdb once more:
$ lsblk -f /dev/sdb
NAME FSTYPE LABEL UUID MOUNTPOINT
sdb crypto_LUKS c39f7404-6fa3-4c39-ba81-0a3fe41cb642
└─luks_disk xfs 4238dadf-7abf-41e1-89b8-b54363e21fc1 /mnt/luks_mount
Now, the /dev/sdb LUKS-encrypted device has an XFS file system on it, and its mount point is /mnt/luks_mount, as expected.
4. Changing the LUKS Passphrase
Next, we’ll change the passphrase that was provided when creating the LUKS partition using cryptsetup luksFormat. This passphrase actually corresponds to that of the first key slot.
Before changing the passphrase of the first key slot, let’s check the header of the LUKS partition:
$ sudo cryptsetup luksDump /dev/sdb
LUKS header information
Version: 2
Epoch: 3
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: c39f7404-6fa3-4c39-ba81-0a3fe41cb642
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: argon2i
Time cost: 4
Memory: 930152
Threads: 2
Salt: 22 77 54 98 4e a6 5c fa 51 21 49 7f 7d 10 21 dd
ab 27 83 c3 73 f4 99 44 d2 af ee ba 9b 9b 26 c9
AF stripes: 4000
AF hash: sha256
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 177845
Salt: 8a f0 cd 5b 9a 1f 45 ec a3 11 99 dd 5c 5e c7 0c
78 c8 75 5d c8 24 cb 2f 80 18 52 16 d4 9a bb db
Digest: b9 49 dc a0 53 49 ea fe 1f f5 bf ac c8 10 b1 f5
e8 b8 06 85 b2 8f 43 8c 9d 5b 69 17 4b 87 09 1f
We use the cryptsetup luksDump command for displaying the LUKS header, passing the block device to it as an argument.
As we see from the output, we have only one key slot.
4.1. Single Key Slot Case
We can change the existing passphrase using the cryptsetup luksChangeKey command:
$ sudo cryptsetup luksChangeKey /dev/sdb
Enter passphrase to be changed:
Enter new passphrase:
Verify passphrase:
We pass the /dev/sdb device as an argument to the cryptsetup luksChangeKey command. The command asks for the current passphrase, and once we enter it correctly, it asks for the new passphrase.
4.2. Multiple Key Slots Case
Earlier, we didn’t have to specify a key slot while changing the passphrase as there’s only one key slot in the LUKS partition. However, LUKS supports multiple key slots. How do we specify the key slot in that case?
Let’s add a new key slot using the cryptsetup luksAddKey command:
$ sudo cryptsetup luksAddKey /dev/sdb
Enter any existing passphrase:
Enter new passphrase for key slot:
Verify passphrase:
The cryptsetup luksAddKey command first asks for an existing passphrase. Since there’s only one key slot, we enter the corresponding passphrase. Once we enter the passphrase for the first key slot correctly, it prompts us to provide a new passphrase for the new key slot and then wants us to verify the new passphrase.
We can use the -S option of cryptsetup luksChangeKey to select a specific key slot. The numbering of key slots starts from 0, so the number of the second key slot is 1.
Let’s change the passphrase of the second key slot we’ve just added:
$ sudo cryptsetup luksChangeKey /dev/sdb -S 1
Enter passphrase to be changed:
Enter new passphrase:
Verify passphrase:
Now, we must first enter the passphrase of the second key slot. Once we enter the passphrase of the second key slot correctly, we’re asked to enter and verify the new passphrase.
Equivalently, we can also use the –key-slot option instead of -S.
We can remove a passphrase using the cryptsetup luksRemoveKey command:
$ sudo cryptsetup luksRemoveKey /dev/sdb
Enter passphrase to be deleted:
We don’t have to specify the slot number while deleting a passphrase. Providing the passphrase of the second slot removes the second slot from the device.
5. Conclusion
In this article, we discussed how to change a LUKS passphrase.
First, we gave a brief introduction to LUKS. Then, we created a LUKS partition to demonstrate adding and changing key slots.
Finally, we learned how to change the passphrase of an existing key slot using the cryptsetup luksChangeKey command. We saw that we can use the -S option to specify the key slot number when there are multiple key slots.