- 1 Overview
- 2 Technologies and Tools
- 3 Implementation in openSUSE
- 4 Manually creating new LUKS volumes
- 5 Migrating cryptoloop volumes to dm-crypt
- 6 Fixing Broken Initrds
- 7 Known Bugs and Pitfalls
LUKS is a special on disk format for encrypted volumes. It puts metadata in front of the actual encrypted data. The metadata stores the encryption algorithm, key length, block chaining method etc. Therefore one does not need to memorize those parameters which makes LUKS suitable for use on e.g. USB memory sticks. Additionally LUKS uses a master key that is encrypted using the passphrase hash. That way it's possible to change the passphrase and one can use multiple passphrases. cryptsetup is able to handle LUKS volumes.
LUKS is the default and the recommended format for encrypted volumes.
'raw' disk format
The raw disk format does not store any information about the necessary parameters to decrypt the volume on the volume itself. In order to access encrypted data one needs to know the correct passphrase and the key derivation function (or the binary key itself), the encryption algorithm and the method used to compute the IV for the first block of the cipher block chain.
Most users will want to use the LUKS format which is more convenient, less error prone and more secure than raw disk formats.
- Mode of Operation
- Data on Disks is stored in sectors. Sectors typically consist of a blocks of 512 bytes. Sectors can be accessed randomly. To avoid complex mapping operations hard disk encryption therefore also works by processing whole sectors. Typical block ciphers such as AES or twofish however process blocks of 16 bytes only. There are various methods to combine multiple steps of a block cipher to process bigger blocks (the so called "mode of operation"). The method almost exclusively used on Linux is Cipher Block Chaining (CBC). This method requires a so called Initialization Vector (IV). Different IVs produce different results after encryption even if the plain text data is the same. So by using different IVs for encrypting each sector it's not possible for an adversary to tell whether two sectors of a disk contain the same plain text data. The IV for a sector typically is deduced from the sector's number. Weak methods to compute the IV make the volume prone to watermarking attacks.
- Encryption Algorithm
- For hard disk encryption the algorithms used are symmetric block algorithms (such as AES or twofish). Those algorithms take a block of data as input, process them with a key and output the same amount of data in encrypted form. The key for encryption and decryption is the same. So in order to keep the data private the key has to be kept secret as well.
- Keys are a certain amount of binary data, typically 128, 192 or 256 bits (ie 16, 24 or 32 bytes). Longer keys are harder to guess by adversaries but also make encryption and decryption slower.
- Hash function
- A cryptographic hash function takes input of arbitrary data with an arbitrary length and outputs a fixed amount of data. Same input always leads to the same output. It's not possible however to compute the input given a certain output, ie the process only works one way. A hash function therefore is suitable to deduce an encryption key from a pass phrase. Typically deployed hash functions used for hard disk encryption are SHA128, RIPEMD160 and SHA256 yielding key sizes of 128, 160 and 256 bits. If the hash output is smaller than the required key size the passphrase usually gets modified and hashed multiple times in a certain way. The output of the hashing rounds then is concatenated.
- 256 bits of random binary data are hard to memorize for a human brain, therefore one typically uses a passphrase as input to a hash function in order to produce a certain binary key that is used for encryption. The longer the passphrase is the harder it is for an attacker to try out all possible inputs until the correct encryption key is found.
Technologies and Tools
- dm-crypt implements a device-mapper target for encryption. It uses the kernel's crypto architecture and therefore allows to use various encryption algorithms. It also allows to specify different methods for block chaining and IV generation. It's able to handle volumes that were created using legacy cryptoloop and loop_fish2.
- cryptsetup is used to set up dm-crypt targets.
- loop_fish2 [obsolete]
- loop_fish2 implements the twofish algorithm as a loop device. loop_fish2 has several disadvantages. It padds too short keys with zeroes and it uses zero as fixed value for the IV which makes it weak from a cryptographic point of view. Before openSUSE 10.3 when the module was loaded it was no longer possible to use cryptoloop's twofish implementation. The module has been removed in openSUSE 12.1.
- cryptoloop [obsolete]
- cryptoloop implements encrypted loop devices. It uses the kernel's crypto architecture and therefore allows to use various encryption algorithms. It uses the sector number as IV which is prone to watermarking attacks. Support for cryptoloop in losetup has been removed in openSUSE 12.2.
Implementation in openSUSE
Starting with openSUSE 10.3 encrypted partitions are handled exclusively via the device mapper (dm-crypt) instead of encrypting loop devices (cryptoloop) for the following reasons:
- LUKS is implemented on top of dm-crypt already.
- dm-crypt has no limit on the number of encrypted partitions whereas there are only eight loop devices by default.
- on-disk formats that where used by older SUSE Linux releases can be used in parallel to newer formats.
- The crypttab file contains descriptive informations about encrypted volumes. Each volume is described on a separate line; columns on each line are separated by tabs or spaces. The columns are device mapper target name, source device, key file and options. It is the preferred method to specify encrypted volumes. In order to actually mount file systems a line for the device mapper target name must also be configured in /etc/fstab.
- /etc/cryptotab (obsolete)
- The cryptotab file (notice the 'o') also contains informations about encrypted volumes similar to crypttab (without 'o'). It was supported until openSUSE 11.3 for compatibility with older SUSE Linux releases that used cryptoloop/loop_fish2. The columns in this file are loop device, source device, mount point, file system, cipher, mount options, info. In contrast to crypttab all entries are automatically mounted and a loop device needs to be used. In openSUSE 11.4 support for cryptotab was removed. The script convert_cryptotab may be used to manually convert old files to use crypttab/fstab instead.
SysV Init Scripts (obsolete)
The /etc/init.d/boot.crypto script automatically sets up all volumes specified in /etc/crypttab (formerly also /etc/cryptotab) during boot. It prompts for the passphrase if required, runs fsck and mounts the file systems. boot.crypto can also be used interactively to start stop individual volumes.
11.1 additinally introduces the script /etc/init.d/boot.crypto-early which is run before md and lvm so one can use e.g. RAID on encrypted volumes.
In openSUSE 12.3 the boot.crypto scripts are no longer available as they were obsoleted by the systemd implementation.
systemd has its own implemenation of a /etc/crypttab parser. It generates service files for each entry in crypttab. So for example an entry that has the name 'cr_sda1' as first column in /etc/crypttab would be called 'systemd-cryptsetup@cr_sda1.service' Additionally all fstab entries also appear as mount units. So for example a mount point /secret that mount cr_sda1 would be called 'secret.mount'.
To manually mount the crypted partition including unlocking it one would call 'systemctl start secret'. To disable it again call 'systemctl stop secret'. It's possible to add such commands to the sudoers file to allow users to manually start and stop crypted partitions. That's a rather impressive simplification.
To manually mount the crypted partition including unlocking it one would call 'systemctl start secret.mount'. To disable it again call 'systemctl stop systemd-cryptsetup@cr_sda1.service'. It's possible to add such commands to the sudoers file to allow users to manually start and stop crypted partitions.
Hook scripts for mkinitrd allow to unlock luks volumes already in initrd. An encrypted root file system is automatically detected, other volumes need to have the 'initrd' option in /etc/crypttab.
Manually creating new LUKS volumes
cryptsetup command can be used to prepare a partition as LUKS volume. The following command (as root) will prepare /dev/sda3 for encryption. The command will also prompt for a passphrase that is used to encrypt the master key:
cryptsetup luksFormat /dev/sda3
To be able to access the content the device needs to be opened:
cryptsetup luksOpen /dev/sda3 my_secure_partion
The device now appears as /dev/mapper/my_secure_partion. To be useful a file system needs to be created on it:
Now the partition can be mounted and filled with files:
mount /dev/mapper/my_secure_partion /secret
When done the partition needs to be unmounted and closed so noone can access it without supplying the passphrase again:
umount /secret cryptsetup luksClose /dev/mapper/my_secure_partion
To have the partition decrypted and mounted during boot, an entry in /etc/crypttab and /etc/fstab is needed:
my_secure_partion <device> none luks
where device is to be replaced with /dev/sda3 or with UUID=<luksUUID>, the luksUUID being obtained by
cryptsetup luksUUID /dev/sda3
/dev/mapper/my_secure_partion /secret ext4 nofail 0 2
Finally the init script needs to be activated:
chkconfig boot.crypto on chkconfig boot.crypto-early on
Migrating cryptoloop volumes to dm-crypt
cryptoloop is no longer supported since openSUSE 12.2. Old volumes can still be accessed via dm-crypt though. The script convert_cryptotab scripts helps in converting old /etc/cryptotab entries.
Some examples of how to convert entries manually are provided in the following sections.
Encrypted file listed in /etc/fstab
Since losetup and mount shared the same source, it was possible to have mount set up cryptoloop devices via fstab. That is no longer possible with dm-crypt.
twofish256 cryptoloop image
The following example shows a cryptoloop image as YaST typically created it.
old etc/fstab for twofish256 cryptoloop image
/secret.img /secret ext2 noauto,acl,user_xattr,loop=/dev/loop1,encryption=twofish256,phash=sha512,itercountk=100 0 0
To use dm-crypt for accessing the same volume, the crypto related parameters need to be put into /etc/crypttab, whereas the mount option need to be kept in fstab:
new /etc/crypttab for twofish256 cryptoloop image
secret /secret.img none cipher=twofish-cbc-plain,size=256,hash=sha512,itercountk=100
/etc/fstab to actually have the volume mounted
/dev/mapper/secret /secret ext2 nofail,acl,user_xattr 0 2
Commands to manually mount the file
losetup -e twofish256 /dev/loop0 /secret.img mount /dev/loop0 /secret
losetup /dev/loop0 /secret.img cryptsetup --hash sha512 --cipher twofish-cbc-plain --key-size 256 create secret_img /dev/loop0 mount /dev/mapper/secret_img /secret
aes cryptoloop image
This example shows a manually created cryptoloop image with aes algorithm
old /etc/fstab for aes cryptoloop image
/secret.img /secret ext2 nofail,user,loop,encryption=aes 0 2
Note that the above fstab neither specified a key length nor a hash algorithm. The implicit defaults were 128 bits for the key length and sha256 as hash algorithm.
new /etc/crypttab for aes cryptoloop image
secret /secret.img none cipher=aes-cbc-plain,size=128,hash=sha256
/etc/fstab to actually have the volume mounted
/dev/mapper/secret /secret ext2 nofail,user 0 2
Commands to manually mount the file
losetup -e aes /dev/loop0 /secret.img mount /dev/loop0 /secret
losetup /dev/loop0 /secret.img cryptsetup --hash sha256 --cipher aes-cbc-plain --key-size 128 create secret_img /dev/loop0 mount /dev/mapper/secret_img /secret
new: cryptsetup >= 1.6.4 (leap 42.1)
losetup /dev/loop0 /secret.img echo "<password>" | cryptsetup loopaesOpen --key-file=- /dev/loop0 secret_img mount /dev/mapper/secret_img /secret
Really old twofish volume
Volumes created using the loop_fish2 module on old distributions such as SuSE Linux 8.1 were listed as 'twofish' in cryptotab.
old /etc/cryptotab for twofish partition
/dev/loop4 /secret.img /secret ext2 twofish acl,user_xattr
new /etc/crypttab for twofish partition
secret /secret.img none cipher=twofish-cbc-null,hash=ripemd160:20,size=192
Commands to manually mount the file
losetup -e twofish /dev/loop0 /secret.img mount /dev/loop0 /secret
losetup /dev/loop0 /secret.img cryptsetup --hash ripemd160:20 --cipher twofish-cbc-null --key-size 192 create secret_img /dev/loop0 mount /dev/mapper/secret_img /secret
On SUSE Linux 9.2 YaST no longer used a key length of 192 bits but used 256 bits instead. Unfortunately, twofish encryptions with that key length can be provided by loop_fish2 as well as cryptoloop. The difference between both modules is the IV generation method, which results in sublte changes to the on-disk format. The format used by loop_fish2 was later named 'twofishSL92' in order to be able to distinguish it from cryptoloop's 'twofish256'. Special care must be taken to not use the wrong format. Use of the wrong format can lead to total file system corruption! The dm-crypt notation for the twofishSL92 format is 'twofish-cbc-*null*' whereas the notation for twofish256 is 'twofish-cbc-*plain*'
old /etc/cryptotab for twofishSL92 partition
/dev/loop0 /secret.img /secret ext2 twofishSL92 acl,user_xattr
new /etc/crypttab for twofishSL92 partition
secret /secret.img none cipher=twofish-cbc-null,hash=sha512,size=256
Commands to manually mount the file
losetup -e twofishSL92 /dev/loop0 /secret.img mount /dev/loop0 /secret
losetup /dev/loop0 /secret.img cryptsetup --hash sha512 --cipher twofish-cbc-null --key-size 256 create secret_img /dev/loop0 mount /dev/mapper/secret_img /secret
Fixing Broken Initrds
Sometimes creating the initrd goes wrong and one needs to re-create it from within the rescue system. With LVM inside LUKS this requires quite some manual steps outlined here.
The following steps assume your device is /dev/sda2 and the volume group is called 'system'. Adjust as needed.
Unlock the LUKS container as /dev/mapper/XXX. If you already know the destination name you may enter it right away (for /dev/sda2 it should be cr_sda2):
# cryptsetup luksOpen /dev/sda2 XXX
Enable the LVM volume group and mount the root device
# vgchange -a y # mount /dev/system/root /mnt
Rename XXX to the expected name of the device mapper target. It's the first column of /etc/crypttab. It's important to use the correct name before running mkinitrd. Otherwise the system will try to unlock the volume twice!
# cat /mnt/etc/crypttab cr_sda2 /dev/sda2 none none # dmsetup rename XXX cr_sda2
chroot into the system to fix whatever is needed
# for i in sys dev proc; do mount --bind /$i /mnt/$i; done # chroot /mnt su - # mount /boot # mkinitrd # umount /boot # exit
unmount and cleanup
# for i in sys dev proc; do umount /mnt/$i; done # umount /mnt # vgchange -a n # dmsetup remove cr_sda2
Known Bugs and Pitfalls
'noauto' fstab option
In the past, yast created fstab entries for encrypted volumes with the 'noauto' option. This was necessary as boot.crypto ran after boot.localfs and mounted volumes itself. Nowadays, the fstab option 'nofail' exists, which allows the boot scripts to mount the volume if possible, but continue boot if the volume fails. Since the sysv scripts are not used with systemd anymore and systemd strictly honors the 'noauto' option, old fstab entries must be converted to use 'nofail' instead.
It is also recommended to set the fs_passno column in fstab (sixth field) to '2' to enable file system checks.
international keyboard layouts
When changing a passphrase while using a non-US keyboard layout, make sure to not enter characters that are only available via special X input methods. The boot.crypto scripts only honor the settings in /etc/sysconfig/keyboard which may differ from the X keyboard layout. When using an encrypted root partition, no non-US layouts are supported at all, as the initrd currently does not support including keymaps.
- originally 'mount' and 'losetup' could not set up images that used the old 'loop_fish2' kernel module ('twofish', 'twofishSL92') instead of 'cryptoloop'. An online update reintroduced that feature. In contrast to previous distributions presence of the 'loop_fish2' module however does no longer change the meaning of 'twofish256' (see also #twofishSL92_volume).
- the implicit default hash function for algorithms with 128 bit key length (e.g. 'aes128') previously was 'sha256'. On 10.3 it's accidently 'sha512' but got corrected in newer distributions. Please always explicitly specify the hash function to avoid confusion.