LUKS Encrypt Hard Drive with Cryptsetup on Ubuntu 20.04
Linux
This article outlines how to LUKS encrypt a secondary drive on Ubuntu 20.04 Focal Fossa using cryptsetup
on the command line.
Find the Unmounted Disk
Once you have physically connected the disk, find the unmounted disk in the system using lsblk
:
lsblk
# Typical output:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 465.8G 0 disk
├─sda1 8:1 0 512M 0 part
├─sda2 8:2 0 488M 0 part /boot
└─sda3 8:3 0 464.8G 0 part
└─sda3_crypt 252:0 0 464.8G 0 crypt
├─ubuntu--vg-root 252:1 0 448.8G 0 lvm /
└─ubuntu--vg-swap_1 252:2 0 16G 0 lvm
└─cryptswap1 252:3 0 16G 0 crypt [SWAP]
sdb 8:16 0 931.5G 0 disk
└─sdb_crypt 252:4 0 931.5G 0 crypt /media/secure-hdd-2
sdc 8:32 0 1.8T 0 disk
├─sdc1 8:33 0 994.9G 0 part /media/datadrive
└─sdc2 8:34 0 868.2G 0 part
└─sdc2_crypt 252:5 0 868.2G 0 crypt /media/secure-hdd
sdd 8:48 0 931.5G 0 disk
loop0 7:0 0 83.8M 1 loop /snap/core/3604
loop1 7:1 0 178.2M 1 loop /snap/atom/112
loop2 7:2 0 174.2M 1 loop /snap/atom/116
loop3 7:3 0 28.1M 1 loop /snap/telegram-latest/4
loop4 7:4 0 83.8M 1 loop /snap/core/3748
loop5 7:5 0 81.3M 1 loop /snap/core/3887
loop6 7:6 0 178.2M 1 loop /snap/atom/111
In this case you can see sdd
is the target drive - the size type matches, and it is unmounted (as expected).
Double check disk info:
sudo hdparm -i /dev/sdd
# Output:
/dev/sdd:
Model=Samsung SSD 860 EVO 1TB, FwRev=RVT01B6Q, SerialNo=S3Z9NB0JC01523A
Config={ Fixed }
RawCHS=16383/16/63, TrkSize=0, SectSize=0, ECCbytes=0
BuffType=unknown, BuffSize=unknown, MaxMultSect=1, MultSect=1
CurCHS=16383/16/63, CurSects=16514064, LBA=yes, LBAsects=1953525168
IORDY=on/off, tPIO={min:120,w/IORDY:120}, tDMA={min:120,rec:120}
PIO modes: pio0 pio1 pio2 pio3 pio4
DMA modes: mdma0 mdma1 mdma2
UDMA modes: udma0 udma1 udma2 udma3 udma4 udma5 *udma6
AdvancedPM=no WriteCache=enabled
Drive conforms to: unknown: ATA/ATAPI-2,3,4,5,6,7
* signifies the current active mode
If this checks out, you have the device reference.
Alternatively, list all drives in short format:
sudo lshw -short -C disk
H/W path Device Class Description
======================================================
/0/1/0.0.0 /dev/sda disk 500GB Samsung SSD 850
/0/2/0.0.0 /dev/sdb disk 1TB ST1000DM010-2EP1
/0/3/0.0.0 /dev/sdc disk 2TB WDC WD20EZRZ-00Z
/0/4/0.0.0 /dev/sdd disk 1TB Samsung SSD 860
Create a Partition
If the disk does not have an existing partition, create one.
sudo fdisk /dev/sdd
Follow instructions, hit all defaults to create one large partition…it will be /dev/sdd1.
If the disk is already partitioned, you can use an existing partition. Note that all data will be over-written.
LUKS Encryption
Next step is to LUKS encrypt the target partition - in this case, /dev/sdd1
:
cryptsetup -y -v luksFormat /dev/sdd1
-v
: verbose output-y
: Forces double entry from the user when interactively setting the passphrase - ask for it twice and complain if both inputs do not match
Create a Mapping
The encrypted partition is accessed by means of a mapping.
To create a mapping for the current session:
# Creates a mapping called backupSSD
sudo cryptsetup luksOpen /dev/sdd1 backupSSD
# Check:
ls -l /dev/mapper/backupSSD
lrwxrwxrwx 1 root root 7 Dec 17 15:48 /dev/mapper/backupSSD -> ../dm-6
# Check mapping status
sudo cryptsetup -v status backupSSD
[sudo] password for david:
/dev/mapper/backupSSD is active and is in use.
type: LUKS1
cipher: aes-xts-plain64
keysize: 256 bits
device: /dev/sdd1
offset: 4096 sectors
size: 1953519024 sectors
mode: read/write
Command successful.
This mapping is not persistent. If you want to open the disk/partition automatically on boot, you will need to amend /etc/crypttab
to set up a mapped device name.
Crypttab
The file /etc/crypttab
contains descriptive information about encrypted filesystems. Each filesystem is described on a separate line.
Fields on each line are separated by tabs or spaces. The order of records in crypttab is important because the init scripts sequentially iterate through crypttab doing their thing.
# /etc/crypttab
# Mapping name in field 1.
# UUID of partition in field 2
# Full path to keyfile in field 3
backupSSD UUID=4f942e15-ff00-4213-aab1-089448b17850 /root/.keyfiles/hdd-1.key luks,discard
The first field, target, describes the mapped device name. It must be a plain filename without any directory components. A mapped device which encrypts/decrypts data to/from the source device will be created at /dev/mapper/target by cryptsetup.
The second field, source device, describes either the block special device or file that contains the encrypted data. Instead of giving the source deviceexplicitly, the UUID is supported as well, using
UUID=<luks_uuid>
.The third field, key file, describes the file to use as a key for decrypting the data of the source device. Note that the entire key file will be used as thepassphrase; the passphrase must not be followed by a newline character.
It can also be a device name (e.g. /dev/urandom), note however that LUKS requires a persistent key and therefore does not support random data keys.
If the key file is the string “none”, a passphrase will be read interactively from the console. In this case, the options precheck, check, checkargs and triesmay be useful.
The fourth field, options, describes the cryptsetup options associated with the encryption process. At minimum, the field should contain either the string luksrespectively tcrypt or the cipher, hash and size options.
Options are in the format: key=value [,key=value …]. The supported options are described below.Note that all four fields are mandatory and that a missing field will lead to unspecified behaviour.
–Man page: man crypttab
LUKS Header
Check it using the luksDump
command. Data shown is anonymised (junk):
sudo cryptsetup luksDump /dev/sdd1
LUKS header information for /dev/sdd1
Version: 1
Cipher name: aes
Cipher mode: xts-plain64
Hash spec: sha1
Payload offset: 4096
MK bits: 256
MK digest: ad f8 5d b7 ce 4e 54 f6 17 79 a8 ce f5 07 12 ce 82 b1 94 28
MK salt: cd 44 e4 6a db a0 b4 ba d1 9d c5 da 1b 97 d1 a2
c8 a5 17 ac 7b 97 50 42 67 84 fe 74 a6 1f 5f d5
MK iterations: 274632
UUID: 2e72f987-ffa1-c0c0-d144-098f45d86100
Key Slot 0: ENABLED
Iterations: 978243
Salt: 1e b5 1f 35 7b 46 24 34 ec ab a2 7d 5a 74 ba 38
87 7e c9 57 b4 d0 2a ab b7 e1 13 32 92 65 b2 c2
Key material offset: 8
AF stripes: 4000
Key Slot 1: ENABLED
Iterations: 4456344
Salt: 39 68 d2 4e 04 51 a3 c2 c9 88 e8 71 a5 a9 0f d4
17 3f 88 0c 39 2c f5 22 35 e5 19 48 3c 1b 47 49
Key material offset: 264
AF stripes: 4000
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED
Amongst other interesting things, the output will show the size of the master key (MK bits
). A 256 bit master key will equate to a LUKS header size of 1,052,672 Bytes See the cryptsetup FAQ
Format Partition
Do not omit this step - or the partition won’t mount.
sudo mkfs.ext4 /dev/mapper/backupSSD -L "Extra SSD 1TB"
…where -L
denotes the partition label.
Mount Point
Create a mount point. Give the mount point appropriate ownership. E.g.:
sudo mkdir /media/secure-ssd
sudo chown $USER:$USER /media/secure-ssd
Mount
To mount, you need to reference the mapper not the partition:
sudo mount /dev/mapper/backupSSD /media/secure-ssd
Auto Mount
Mount at boot.
Edit /etc/fstab
to reference the mapper to the decrypted volume
# Samsung 860 1TB EVO SSD path installed 17-02-2018
# mapper mount-point type mount-options dump fs_passno
/dev/mapper/backupSSD /media/secure-ssd ext4 defaults 0 2
Mount-options refer to filesystem related parameters, formatted as a comma-separated list. This contains at least the type of mount
(ro
or rw
), plus any additional options appropriate to the filesystem type (including performance-tuning options). Basic filesystem-independent options are:
defaults
- use default options: rw, suid, dev, exec, auto, nouser, and async.noauto
- do not mount when “mount -a” is given (e.g., at boot time)user
- allow a user to mountowner
- allow device owner to mountcomment
- or x-for use by fstab-maintaining programs nofail
- do not report errors for this device if it does not exist.
The sixth field (fs_passno
) is used by fsck to determine the order in which filesystem checks are done at boot time.
The root filesystem should be specified with a fs_passno
of 1. Other filesystems should have a fs_passno
of 2. Filesystems within a drive will be checked sequentially, but filesystems on
different drives will be checked at the same time to utilize parallelism available in the hardware. Defaults to zero (don’t fsck) if not present.
Decrypt using a key
I set up additonal drives to mount & decrypt automatically by means of a keyfile held in my encrypted boot drive. This means that I just decrypt the primary disk at start up, with a passphrase as usual. The keyfile is then used to decrypt additional disks automatically. Keyfiles are secure since the drive holding the keyfile is encrypted.
Cryptsetup allows you to specify up to 8 keyslots - passwords or keyfiles. When you add these, they are hashed and added to key-slots in the LUKS header at the start of the device. When you first run luksFormat
, the initial password you supply is hashed and stored in key-slot 0 of the LUKS header. You can easily add an additional passphrase, and this can take the form of a keyfile. This means that the volume can be decrypted either with the initial passphrase or the keyfile.
To add a password to a LUKS partition, you need an unencrypted copy of the master key - so if the partition is not initialized, you will be prompted for the original passphrase. Because more than one password is possible under LUKS setups, the wording of the password prompt may seem confusing - it says: “Enter any passphrase”. This means enter any valid existing password for the partition.
Create a keyfile:
# Make an appropriate directory
sudo mkdir /root/.keyfiles
# Make a keyfile of randomly sourced bytes
sudo dd if=/dev/urandom of=/root/.keyfiles/hdd-1.key bs=1024 count=4
# Make this read-only by owner (in this case, root):
sudo chmod 0400 /root/.keyfiles/hdd-1.key
Set up a keyfile for the LUKS partition (in this case, /dev/sdd1
:
sudo cryptsetup luksAddKey /dev/sdd1 /root/.keyfiles/hdd-1.key
To automatically mount at boot, the mapping in /etc/crypttab
should reference the keyfile:
# Modify line to /etc/crypttab if the keyfile has not been added
backupSSD UUID=4f942e15-ff00-4213-aab1-089448b17850 /root/.keyfiles/hdd-1.key luks,discard
Unmount & Secure
umount /dev/mapper/backupSSD
cryptsetup luksClose backupSSD
Decrypt & remount:
cryptsetup luksOpen /dev/sdd1 backupSSD
# mount /dev/mapper/backupSSD /media/mountpoint
Check Passphrase
sudo cryptsetup luksOpen --test-passphrase /dev/sdX && echo correct
# Prompts for password, echoes "correct" if successful
# Alternative - specify slot
cryptsetup luksOpen --test-passphrase --key-slot 0 /dev/sdX && echo correct
Backup Header Files
sudo cryptsetup luksHeaderBackup --header-backup-file ~/backup-dir/LUKS-headers/my-hostname/sda3 /dev/sda3
sudo cryptsetup luksHeaderBackup --header-backup-file ~/backup-dir/LUKS-headers/my-hostname/sdb /dev/sdb
sudo cryptsetup luksHeaderBackup --header-backup-file ~/backup-dir/LUKS-headers/my-hostname/sdc2 /dev/sdc2
sudo cryptsetup luksHeaderBackup --header-backup-file ~/backup-dir/LUKS-headers/my-hostname/sdd1 /dev/sdd1
Restore Header Files
# General form:
# cryptsetup luksHeaderRestore --header-backup-file <file> <device>
sudo cryptsetup luksHeaderRestore --header-backup-file ~/backup-dir/LUKS-headers/my-hostname/sda3 /dev/sda3
sudo cryptsetup luksHeaderRestore --header-backup-file ~/backup-dir/LUKS-headers/my-hostname/sdb /dev/sdb
sudo cryptsetup luksHeaderRestore --header-backup-file ~/backup-dir/LUKS-headers/my-hostname/sdc2 /dev/sdc2
sudo cryptsetup luksHeaderRestore --header-backup-file ~/backup-dir/LUKS-headers/my-hostname/sdd1 /dev/sdd1
Breaking LUKS Encryption
This article describes a method for breaking LUKS encryption that involves dumping the contents of memory while running cryptsetup luksOpen
, and then finding the hashed password. Once an adversary has a copy of the hashed password, they can run it through a password cracker. The method relies on the fact that the hashed password is loaded into memory by cyrptsetup as part of the authentication process. I haven’t checked this vulnerability, but it certainly sounds plausible.
To prevent such an attack, use a complex password. My personal preference is for a memorised > 12 character mneumonic passsphrase drawn from a possible keyspace of 94 (upper & lowercase, number, special character), with additional padding characters to increase overall length up to 22. If you encrypt disks with LUKS and then select “password123” as your passphrase, you may as well not bother.
Appendix
lsblk
is a straightforward and concise way to get all available drives & partitions. LUKS partitions/drives have the FSTYPE crypto_LUKS
:
david@ubuntu:$ sudo lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL,UUID
NAME FSTYPE SIZE MOUNTPOINT LABEL UUID
sda 465.8G
├─sda1 vfat 512M /boot/efi xxx
├─sda2 ext2 488M /boot xxx
└─sda3 crypto_LUKS 464.8G xxx
└─sda3_crypt LVM2_member 464.8G xxx
├─ubuntu--vg-root
│ ext4 448.8G / xxx
└─ubuntu--vg-swap_1
swap 16G xxx
└─cryptswap1 swap 16G [SWAP] xxx
sdb crypto_LUKS 931.5G xxx
└─sdb_crypt ext4 931.5G /media/secure-hdd-2 Barracuda 1TB xxx
sdc 1.8T
├─sdc1 ext4 994.9G /media/datadrive Public HD xxx
└─sdc2 crypto_LUKS 868.2G xxx
└─sdc2_crypt ext4 868.2G /media/secure-hdd Secure HD xxx
sdd 931.5G
└─sdd1 crypto_LUKS 931.5G xxx
└─backupSSD ext4 931.5G /media/secure-ssd Extra SSD 1TB xxx
loop0 squashfs 83.8M /snap/core/3604
loop1 squashfs 178.2M /snap/atom/111
loop2 squashfs 83.8M /snap/core/3748
loop3 squashfs 174.2M /snap/atom/116
loop4 squashfs 178.2M /snap/atom/112
loop5 squashfs 81.3M /snap/core/3887
loop6 squashfs 28.1M /snap/telegram-latest/4
Available columns (for –output):
NAME
: device nameKNAME
: internal kernel device nameMAJ
::MIN major:minor device numberFSTYPE
: filesystem typeMOUNTPOINT
: where the device is mountedLABEL
: filesystem LABELUUID
: filesystem UUIDPARTTYPE
: partition type UUIDPARTLABEL
: partition LABELPARTUUID
: partition UUIDPARTFLAGS
: partition flagsRA
: read-ahead of the deviceRO
: read-only deviceRM
: removable deviceHOTPLUG
: removable or hotplug device (usb, pcmcia, …)MODEL
: device identifierSERIAL
: disk serial numberSIZE
: size of the deviceSTATE
: state of the deviceOWNER
: user nameGROUP
: group nameMODE
: device node permissionsALIGNMENT
: alignment offsetMIN
:-IO minimum I/O sizeOPT
:-IO optimal I/O sizePHY
:-SEC physical sector sizeLOG
:-SEC logical sector sizeROTA
: rotational deviceSCHED
: I/O scheduler nameRQ
:-SIZE request queue sizeTYPE
: device typeDISC
:-ALN discard alignment offsetDISC
:-GRAN discard granularityDISC
:-MAX discard max bytesDISC
:-ZERO discard zeroes dataWSAME
: write same max bytesWWN
: unique storage identifierRAND
: adds randomnessPKNAME
: internal parent kernel device nameHCTL
: Host:Channel:Target:Lun for SCSITRAN
: device transport typeSUBSYSTEMS
: de-duplicated chain of subsystemsREV
: device revisionVENDOR
: device vendor
References
- Guide on LUKS cryptsetup
- Labelling of partitions/volumes
- Using fdisk to manage partitions on Linux
- FAQ for cryptsetup - essential reading
- Create an encrypted LUKS disk
- Encrypt external drives with LUKS
- Breaking LUKS encryption
- Useful article from RedHat on recovering lost LUKS key/passphrase (spoiler - you probably can’t recover if the drive is encrypted and the password is strong)
- Backup LUKS headers
Resources
comments powered by Disqus