Secure Storage: Creating an Encrypted File System in Linux

Linux encrypted file system

In Linux,  an encrypted file system occurs through dm-crypt using LUKS as the key setup using kernel crypto API. This feature is part of Linux Kernel 4.14.18-106 and above, additionally we need Exynos5422 Slim SSS (Security Sub-System) driver which supports AES, SHA-1, SHA-256, HMAC-SHA-1, and HMAC-SHA-256 encryptions. The device-mapper target provides transparent encryption of block devices using the kernel crypto API.

  • AES cipher with support of aes-cbc/aes-ctr
  • Cipher-block chaining (CBC)
  • Counter (CTR) known as integer counter mode (ICM) and segmented integer counter (SIC) mode
  • ESSIV (“Encrypted salt-sector initialization vector”) allows the system to create IVs based on a hash including the sector number and encryption key
  • SHA-256 is the hashing algorithm used for key derivation
  • XTS is counter-oriented chaining mode
  • PLAIN64 is an IV generation mechanism that simply passes the 64-bit sector index directly to the chaining algorithm as the IV

Parameters: < cipher > < key > < iv_offset > < device path > < offset > [< #opt_params > < opt_params >]
< cipher >
Encryption cipher, encryption mode and Initial Vector (IV) generator.
The cipher specifications format is:
cipher[ :keycount ]-chainmode-ivmode[ :ivopts ]

Cipher format also supports direct specification with kernel crypt API
format (selected by capi: prefix). The IV specification is the same
as for the first format type.
This format is mainly used for specification of authenticated modes.
The crypto API cipher specifications format is:
Capi:cipher_api_spec-ivmode[ :ivopts ]
Examples of authenticated modes:

Cryptsetup benchmark testing with DRAM

# root@odroid:~# cryptsetup benchmark

# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1 297552 iterations per second
PBKDF2-sha256 195338 iterations per second
PBKDF2-sha512 125068 iterations per second
PBKDF2-ripemd160 247305 iterations per second
PBKDF2-whirlpool 27935 iterations per second
# Algorithm | Key | Encryption | Decryption
aes-cbc 128b 73.8 MiB/s 97.7 MiB/s
serpent-cbc 128b 40.9 MiB/s 42.9 MiB/s
twofish-cbc 128b 58.0 MiB/s 62.0 MiB/s
aes-cbc 256b 59.8 MiB/s 74.0 MiB/s
serpent-cbc 256b 41.5 MiB/s 42.7 MiB/s
twofish-cbc 256b 59.1 MiB/s 62.0 MiB/s
aes-xts 256b 110.6 MiB/s 95.2 MiB/s
serpent-xts 256b 41.6 MiB/s 42.2 MiB/s
twofish-xts 256b 59.7 MiB/s 61.9 MiB/s
aes-xts 512b 86.1 MiB/s 72.5 MiB/s
serpent-xts 512b 42.1 MiB/s 42.4 MiB/s
twofish-xts 512b 60.7 MiB/s 61.6 MiB/s

Cryptsetup benchmark testing with HDD

Figure 1 shows test results from an ODROID-HC2 using a WD 4TB 5400RPM NAS HDD, which may vary depending on the type of hard drive used:

$ iozone -e -I -a -s 100M -r 4k -r 16k -r 512k -r 1024k -r 16384k -i 0 -i 1 -i 2
Figure 1 - Cryptsetup benchmark test results for an ODROID-HC2
Figure 1 - Cryptsetup benchmark test results for an ODROID-HC2

Encrypt the hard drive using cryptsetup

Install cryptsetup, and so as not to need rebooting, start the dm-crypt modules.

$ sudo apt-get install cryptsetup
$ sudo modprobe dm-crypt sha256 aes
Test verify the cryptsetup and dm-crypt are working:
$ fallocate -l 128MiB /tmp/test.bin
$ dd if=/dev/urandom of=/tmp/testkey.key bs=128 count=1
$ sync
$ cryptsetup luksFormat --debug -q -d /tmp/testkey.key --cipher aes-cbc-essiv:sha256 -h sha256 -s 128 /tmp/test.bin

$ fallocate -l 128MiB /tmp/test.bin
$ dd if=/dev/urandom of=/tmp/testkey.key bs=128 count=1
$ sync
$ cryptsetup luksFormat --debug -q -d /tmp/testkey.key --cipher aes-ctr-plain -h sha256 -s 128 /tmp/test.bin
Once the you verify the cryptsetup is working fine, you can start encrypting the disk. Note that this is full disk encryption, so the disk needs to be formatted.
$ sudo wipefs -a /dev/sda1
/dev/sda1: 6 bytes were erased at offset 0x00000000 (crypto_LUKS): 4c 55 4b 53 ba be

Create a key to unlock the volume

Luks encryption supports multiple keys. These keys can be passwords entered interactively, or key files passed as an argument while unlocking the encrypted partition.

$ sudo dd if=/dev/urandom of=/root/keyfile bs=1024 count=4
$ sudo chmod 400 /root/keyfile
To create the encrypted partition on /dev/sda1, luks is used. The encryption of the partition will be managed using the cryptsetup command.
$ sudo cryptsetup --verify-passphrase luksFormat /dev/sda1 -c aes-cbc-essiv:sha256 -h sha256 -s 128
This will ask for passphrase which should be long (more than 8 characters), which should be noted. The following steps demonstrate how to open up the encrypted drive and map the dp-crypt to filesystem Next, unlock the drive using the passphrase we just gave,then create a filesystem on the device.
$ sudo cryptsetup luksOpen /dev/sda1 securebackup
Format the partition:
$ sudo mkfs -t ext4 -m 1 /dev/mapper/securebackup
Add a luks key to support auto mounting at boot time:
$ sudo cryptsetup -v luksClose securebackup
$ sudo cryptsetup luksAddKey /dev/sda1 /root/keyfile
Update the /etc/crypttab file, to refer to the keyfile:
$ cat /etc/crypttab
# < target name > < source device > < key file > < options >
securebackup /dev/sda1 /root/keyfile luks
We need to tell the dm-crypt subsystem that this stick must be mounted before the encrypted HDD partition. To do this, open the /etc/default/cryptdisks file and look for the line CRYPTDISKS_MOUNT=“”:
$ cat /etc/default/cryptdisks
# Run cryptdisks initscripts at startup? Default is Yes.

# Mountpoints to mount, before cryptsetup is invoked at initscripts. Takes
# mountpoins which are configured in /etc/fstab as arguments. Separate
# mountpoints by space.
# This is useful for keyfiles on removable media. Default is unset.

# Default check script. Takes effect, if the 'check' option is set in crypttab
# without a value.

# Default precheck script. Takes effect, if the 'precheck' option is set in
# crypttab without a value.
# Default is 'un_blkid' for plain dm-crypt devices if unset here.
Verify that the drive is mapped to the crypto device:
$ sudo cryptsetup luksOpen /dev/sda1 securebackup
$ lsblk
mmcblk1 179:0 0 29.8G 0 disk
|-mmcblk1p1 179:1 0 128M 0 part /media/boot
`-mmcblk1p2 179:2 0 29.7G 0 part /
sda 8:0 0 149G 0 disk
`-sda1 8:1 0 149G 0 part
`-securebackup 254:0 0 149G 0 crypt
In order to auto mount the disk on next boot up, you need to update the /etc/fstab entry:
$ mkdir -p /media/secure
$ sudo cat /etc/fstab
UUID=e139ce78-9841-40fe-8823-96a304a09859 / ext4 errors=remount-ro,noatime 0 1
LABEL=boot /media/boot vfat defaults 0 1
/dev/mapper/securebackup /media/secure ext4 defaults,rw 0 2
You will be able to manually mount drive the disk if the previous steps were successful:
$ mount /dev/mapper/securebackup /media/secure

CIFS/Samba performance on an encrypted HDD

Figures 2 - 7 show performance using the following hardware configuration:

  • HC2 + ubuntu-16.04.3-4.14-minimal-odroid-xu4-20171213.img.xz with updated 4.14.18-106 kernel
  • 8GB MicroSD card
  • Seagate 8TB HDD (ST8000AS0002)
  • Encryption: aes-xts-plain64 (256 bit key, SHA256 hash)

Samba was using the following configuration:

comment = NAS
path = /media/internal
valid users = odroid
writable = yes
create mask = 0775
directory mask = 0775
# Tweaks
write cache size = 524288
getwd cache = yes
use sendfile = yes
min receivefile size = 16384
Figure 2 - Before encryption test 1
Figure 2 - Before encryption test 1

Figure 3 - Before encryption test 2
Figure 3 - Before encryption test 2

Figure 4 - HELIOS LanTest Before Encryption
Figure 4 - HELIOS LanTest Before Encryption

Figure 5 - After encryption test 1
Figure 5 - After encryption test 1

Figure 6 - After encryption test 2
Figure 6 - After encryption test 2

Figure 7 - HELIOS LanTest After Encryption
Figure 7 - HELIOS LanTest After Encryption

For the original article, please see the Wiki post at

Be the first to comment

Leave a Reply